From kwrobot at kitware.com Mon Aug 1 00:01:08 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Mon, 1 Aug 2016 00:01:08 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-475-g8b9cd61 Message-ID: <20160801040108.CAC55F53D4@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 8b9cd61337501b6adb36fcd70e13ad59d1a63b34 (commit) from 963c4e4b909dd573f10aab21362c342431e6496d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8b9cd61337501b6adb36fcd70e13ad59d1a63b34 commit 8b9cd61337501b6adb36fcd70e13ad59d1a63b34 Author: Kitware Robot AuthorDate: Mon Aug 1 00:01:03 2016 -0400 Commit: Kitware Robot CommitDate: Mon Aug 1 00:01:03 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 79ce316..8e548e5 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160731) +set(CMake_VERSION_PATCH 20160801) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 1 14:59:44 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 1 Aug 2016 14:59:44 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-477-g8427b8e Message-ID: <20160801185944.2C4C7F54DF@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 8427b8e11c9a98fb7f7875a1153ab4998e61d4c1 (commit) via ea6475334aff57633ad7bb80c013c8953328a909 (commit) from 8b9cd61337501b6adb36fcd70e13ad59d1a63b34 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8427b8e11c9a98fb7f7875a1153ab4998e61d4c1 commit 8427b8e11c9a98fb7f7875a1153ab4998e61d4c1 Merge: 8b9cd61 ea64753 Author: Brad King AuthorDate: Mon Aug 1 14:59:41 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 1 14:59:41 2016 -0400 Merge topic 'aliased-target-properties' ea647533 Do not report ALIASED_TARGET as always set (#15783) ----------------------------------------------------------------------- Summary of changes: Source/cmGetPropertyCommand.cxx | 2 +- Tests/AliasTarget/CMakeLists.txt | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 1 14:59:47 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 1 Aug 2016 14:59:47 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-482-g2711c35 Message-ID: <20160801185947.49B07F54EB@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 2711c35a8d42e43c7600ef23bf586f2e068292e8 (commit) via f951d0adb4f7ca185804fba530a3dbc9b81f1cc5 (commit) via c63380b1955422d7116f7ea90c238ab8619e9bc4 (commit) via 134d5c1f7c82698b79d88ba92a7bd98b81dceaec (commit) via 2b909c08f526536d4dd84dfe68edf22682ae88ca (commit) from 8427b8e11c9a98fb7f7875a1153ab4998e61d4c1 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2711c35a8d42e43c7600ef23bf586f2e068292e8 commit 2711c35a8d42e43c7600ef23bf586f2e068292e8 Merge: 8427b8e f951d0a Author: Brad King AuthorDate: Mon Aug 1 14:59:44 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 1 14:59:44 2016 -0400 Merge topic 'app-framework-bundle-extension' f951d0ad Add tests for BUNDLE_EXTENSION c63380b1 Update documentation about bundle extensions 134d5c1f Honor BUNDLE_EXTENSION also for Frameworks (#14742) 2b909c08 Honor BUNDLE_EXTENSION also for App Bundles (#16148) ----------------------------------------------------------------------- Summary of changes: Help/prop_tgt/BUNDLE_EXTENSION.rst | 7 ++-- .../release/dev/app-framework-bundle-extension.rst | 5 +++ Source/cmGeneratorTarget.cxx | 22 +++++++++-- Source/cmGlobalXCodeGenerator.cxx | 10 +++++ Source/cmInstallTargetGenerator.cxx | 13 ++++++- Tests/RunCMake/XcodeProject/RunCMakeTest.cmake | 20 ++++++++-- .../XcodeProject/XcodeBundles-install-check.cmake | 8 ++++ Tests/RunCMake/XcodeProject/XcodeBundles.cmake | 40 ++++++++++++++++++++ 8 files changed, 113 insertions(+), 12 deletions(-) create mode 100644 Help/release/dev/app-framework-bundle-extension.rst create mode 100644 Tests/RunCMake/XcodeProject/XcodeBundles-install-check.cmake hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 1 14:59:49 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 1 Aug 2016 14:59:49 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-484-gbfac78d Message-ID: <20160801185949.D3F03F54E8@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via bfac78d07479eb652405ee51548c4011766666ce (commit) via 624b72159be327505c01f4d68ef6e67ac5f4335e (commit) from 2711c35a8d42e43c7600ef23bf586f2e068292e8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bfac78d07479eb652405ee51548c4011766666ce commit bfac78d07479eb652405ee51548c4011766666ce Merge: 2711c35 624b721 Author: Brad King AuthorDate: Mon Aug 1 14:59:47 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 1 14:59:47 2016 -0400 Merge topic 'more-virtual-override' 624b7215 Source/CPack: Add CM_OVERRIDE on MacOS cmCPackGenerator overrides ----------------------------------------------------------------------- Summary of changes: Source/CPack/cmCPackBundleGenerator.h | 8 ++++---- Source/CPack/cmCPackDragNDropGenerator.h | 10 +++++----- Source/CPack/cmCPackOSXX11Generator.h | 8 ++++---- Source/CPack/cmCPackPKGGenerator.h | 6 +++--- Source/CPack/cmCPackPackageMakerGenerator.h | 8 ++++---- Source/CPack/cmCPackProductBuildGenerator.h | 6 +++--- 6 files changed, 23 insertions(+), 23 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 1 14:59:52 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 1 Aug 2016 14:59:52 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-487-g88e1c54 Message-ID: <20160801185952.85DC3F54EC@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 88e1c54a7cd3213d87143558a8fddf39e7fdccc0 (commit) via 7a649111cdea2b10f2ec57084416be619867fbfb (commit) via 5d0d980d9949daf596e10715d686adc95c1c232b (commit) from bfac78d07479eb652405ee51548c4011766666ce (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=88e1c54a7cd3213d87143558a8fddf39e7fdccc0 commit 88e1c54a7cd3213d87143558a8fddf39e7fdccc0 Merge: bfac78d 7a64911 Author: Brad King AuthorDate: Mon Aug 1 14:59:50 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 1 14:59:50 2016 -0400 Merge topic 'use-string-append' 7a649111 Use string(APPEND) in Tests 5d0d980d Use string(APPEND) in Modules ----------------------------------------------------------------------- Summary of changes: .../BasicConfigVersion-AnyNewerVersion.cmake.in | 2 +- Modules/BasicConfigVersion-ExactVersion.cmake.in | 2 +- .../BasicConfigVersion-SameMajorVersion.cmake.in | 2 +- Modules/CMakeBackwardCompatibilityCXX.cmake | 2 +- Modules/CMakeCommonLanguageInclude.cmake | 6 +- Modules/CMakeCompilerIdDetection.cmake | 8 +-- Modules/CMakeDetermineCompilerId.cmake | 6 +- Modules/CMakeDetermineFortranCompiler.cmake | 6 +- Modules/CMakePackageConfigHelpers.cmake | 8 +-- Modules/CMakeParseImplicitLinkInfo.cmake | 44 +++++++------- Modules/CMakePrintHelpers.cmake | 12 ++-- Modules/CPack.cmake | 2 +- Modules/CPackComponent.cmake | 10 +-- Modules/CPackIFW.cmake | 4 +- Modules/CPackRPM.cmake | 64 ++++++++++---------- Modules/CTestUseLaunchers.cmake | 2 +- Modules/CheckIncludeFile.cmake | 2 +- Modules/CheckIncludeFileCXX.cmake | 2 +- Modules/CheckIncludeFiles.cmake | 8 +-- Modules/CheckPrototypeDefinition.cmake | 4 +- Modules/CheckStructHasMember.cmake | 2 +- Modules/CheckSymbolExists.cmake | 8 +-- Modules/CheckTypeSize.cmake | 10 +-- .../Compiler/AppleClang-DetermineCompiler.cmake | 2 +- Modules/Dart.cmake | 2 +- Modules/DeployQt4.cmake | 4 +- Modules/ExternalData.cmake | 16 ++--- Modules/ExternalProject.cmake | 16 ++--- Modules/FeatureSummary.cmake | 12 ++-- Modules/FindBoost.cmake | 48 +++++++-------- Modules/FindCUDA.cmake | 4 +- Modules/FindCUDA/make2cmake.cmake | 2 +- Modules/FindCUDA/run_nvcc.cmake | 2 +- Modules/FindCups.cmake | 2 +- Modules/FindEXPAT.cmake | 2 +- Modules/FindFreetype.cmake | 2 +- Modules/FindMPI.cmake | 8 +-- Modules/FindPHP4.cmake | 8 +-- Modules/FindPackageHandleStandardArgs.cmake | 18 +++--- Modules/FindPkgConfig.cmake | 2 +- Modules/FindQt4.cmake | 2 +- Modules/FindSDL_sound.cmake | 4 +- Modules/FindZLIB.cmake | 2 +- Modules/FindwxWidgets.cmake | 2 +- Modules/FindwxWindows.cmake | 2 +- Modules/FortranCInterface.cmake | 8 +-- Modules/GenerateExportHeader.cmake | 2 +- Modules/GetPrerequisites.cmake | 2 +- Modules/MatlabTestsRedirect.cmake | 2 +- Modules/Platform/BlueGeneQ-base.cmake | 2 +- Modules/Platform/Linux-Intel-Fortran.cmake | 2 +- Modules/Platform/Windows-MSVC.cmake | 2 +- Modules/Qt4Macros.cmake | 4 +- Modules/UseJava.cmake | 6 +- Modules/UseSWIG.cmake | 12 ++-- Modules/Use_wxWindows.cmake | 2 +- Modules/UsewxWidgets.cmake | 2 +- Modules/WriteCompilerDetectionHeader.cmake | 56 ++++++++--------- Tests/AliasTarget/CMakeLists.txt | 2 +- .../CMakeOnly/CheckCXXSymbolExists/CMakeLists.txt | 2 +- .../CMakeOnly/CheckStructHasMember/CMakeLists.txt | 2 +- Tests/CMakeOnly/CheckSymbolExists/CMakeLists.txt | 2 +- Tests/CMakeTests/ModuleNoticesTest.cmake.in | 2 +- Tests/CMakeTests/WhileTest.cmake.in | 6 +- ...yResult-components-lintian-dpkgdeb-checks.cmake | 2 +- .../CPackComponentsDEB/RunCPackVerifyResult.cmake | 2 +- Tests/CTestUpdateBZR.cmake.in | 2 +- Tests/CTestUpdateCVS.cmake.in | 2 +- Tests/CTestUpdateCommon.cmake | 12 ++-- Tests/CTestUpdateGIT.cmake.in | 2 +- Tests/CTestUpdateHG.cmake.in | 2 +- Tests/CTestUpdateP4.cmake.in | 8 +-- Tests/CTestUpdateSVN.cmake.in | 2 +- Tests/Complex/CMakeLists.txt | 4 +- Tests/Complex/Executable/CMakeLists.txt | 4 +- Tests/Complex/Library/CMakeLists.txt | 2 +- Tests/Complex/VarTests.cmake | 2 +- Tests/ComplexOneConfig/CMakeLists.txt | 4 +- Tests/ComplexOneConfig/Executable/CMakeLists.txt | 4 +- Tests/ComplexOneConfig/Library/CMakeLists.txt | 2 +- Tests/ComplexOneConfig/VarTests.cmake | 2 +- Tests/CustomCommand/CMakeLists.txt | 6 +- Tests/FindPackageTest/CMakeLists.txt | 2 +- Tests/Fortran/CMakeLists.txt | 2 +- Tests/IncludeDirectories/CMakeLists.txt | 4 +- Tests/MakeClean/CMakeLists.txt | 2 +- Tests/MathTest/CMakeLists.txt | 2 +- Tests/Module/GenerateExportHeader/CMakeLists.txt | 4 +- Tests/Plugin/CMakeLists.txt | 2 +- Tests/Preprocess/CMakeLists.txt | 30 ++++----- Tests/RunCMake/BuildDepends/check.cmake | 8 +-- .../CMP0054/CMP0054-policy-while-scope.cmake | 4 +- Tests/RunCMake/CPack/DEB/Helpers.cmake | 10 +-- Tests/RunCMake/CPack/VerifyResult.cmake | 4 +- Tests/RunCMake/RunCMake.cmake | 6 +- Tests/RunCMake/continue/ContinueWhile.cmake | 2 +- Tests/RunCMake/if/IsDirectoryLong.cmake | 2 +- .../include_external_msproject/check_utils.cmake | 6 +- .../install/DIRECTORY-MESSAGE_NEVER-check.cmake | 8 +-- .../RunCMake/install/DIRECTORY-message-check.cmake | 12 ++-- .../install/DIRECTORY-message-lazy-check.cmake | 12 ++-- Tests/SimpleInstall/CMakeLists.txt | 4 +- Tests/SimpleInstallS2/CMakeLists.txt | 4 +- Tests/TryCompile/CMakeLists.txt | 4 +- Tests/VSMASM/CMakeLists.txt | 2 +- 105 files changed, 348 insertions(+), 348 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 1 14:59:55 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 1 Aug 2016 14:59:55 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-490-g5ec03c9 Message-ID: <20160801185955.520A4F54EC@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 5ec03c93fc92149708b4ec9d19384a015d845f8e (commit) via ad453f0502fe5d95ca1f050cdf52c2d32a892988 (commit) via 6f108f84d08a4cc12ef5bafc93d5aad903ba687a (commit) from 88e1c54a7cd3213d87143558a8fddf39e7fdccc0 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5ec03c93fc92149708b4ec9d19384a015d845f8e commit 5ec03c93fc92149708b4ec9d19384a015d845f8e Merge: 88e1c54 ad453f0 Author: Brad King AuthorDate: Mon Aug 1 14:59:53 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 1 14:59:53 2016 -0400 Merge topic 'wix-disabled-components' ad453f05 CPackWIX: Support CPACK_COMPONENT__DISABLED 6f108f84 CPackComponent: Document the *_HIDDEN and *_DISABLED variables ----------------------------------------------------------------------- Summary of changes: Help/release/dev/wix-disabled-components.rst | 6 ++++++ Modules/CPackComponent.cmake | 10 +++++++++- Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx | 4 ++++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 Help/release/dev/wix-disabled-components.rst hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 1 15:00:25 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 1 Aug 2016 15:00:25 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1004-g1cc3c5f Message-ID: <20160801190025.BE375F5513@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 1cc3c5f70e71d12671fdad6d6c7b3bebfef33741 (commit) via 5ec03c93fc92149708b4ec9d19384a015d845f8e (commit) via 88e1c54a7cd3213d87143558a8fddf39e7fdccc0 (commit) via bfac78d07479eb652405ee51548c4011766666ce (commit) via 2711c35a8d42e43c7600ef23bf586f2e068292e8 (commit) via 8427b8e11c9a98fb7f7875a1153ab4998e61d4c1 (commit) via 8b9cd61337501b6adb36fcd70e13ad59d1a63b34 (commit) via 963c4e4b909dd573f10aab21362c342431e6496d (commit) via 99f5a32c7ab6011ab826f11e4d48f018dfb758a6 (commit) via db713223a85eb7140c7a6800e4de6173f3d4b326 (commit) via 09a86b392e6eb7ffa1c697b225c436e07d21d7da (commit) from a135841da3110538f92f9aa51923e51157f31f1b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1cc3c5f70e71d12671fdad6d6c7b3bebfef33741 commit 1cc3c5f70e71d12671fdad6d6c7b3bebfef33741 Merge: a135841 5ec03c9 Author: Brad King AuthorDate: Mon Aug 1 15:00:11 2016 -0400 Commit: Brad King CommitDate: Mon Aug 1 15:00:11 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 1 15:04:13 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 1 Aug 2016 15:04:13 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1014-g7140cb5 Message-ID: <20160801190413.7AAECF55E6@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 7140cb5ba763f473ac0717b4dd080337916259e1 (commit) via cd7ed47c4ad5b9c2c7539a6f77bbe11a8510a718 (commit) via bca8be583eda435202f7a0eb6e288646ce70570f (commit) via 7decbe8ffb66a1a02b9ffab027f33558fa36873a (commit) via 2b57b139201f7fa1959702db0a8c18482452f903 (commit) via 8ac4e2cfa283d6a27ba11c9ce6e2cea44457b5cb (commit) via 3b3bd880a3de1d6348d746c15b6bc3b32757343a (commit) via 481f8cf1cc73f99d06ed75752715f2f9fbb8f0ba (commit) via ffa44a39c9d7e092f8c86a4648b976ccc64da4d6 (commit) via 29eeb9a8fd9a6417b99e7fbd8b406f72fc83f35f (commit) from 1cc3c5f70e71d12671fdad6d6c7b3bebfef33741 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7140cb5ba763f473ac0717b4dd080337916259e1 commit 7140cb5ba763f473ac0717b4dd080337916259e1 Merge: 1cc3c5f cd7ed47 Author: Brad King AuthorDate: Mon Aug 1 15:04:12 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 1 15:04:12 2016 -0400 Merge topic 'vim-syntax-updates' into next cd7ed47c Aux: highlight commands using Function bca8be58 Aux: sort the highlighting list 7decbe8f Aux: highlight CMAKE_{CMAKE,CPACK}_COMMAND variables 2b57b139 Aux: highlight modules using Include 8ac4e2cf Aux: highlight conditiona and repeat commands differently 3b3bd880 Aux: highlight deprecated commands as warnings 481f8cf1 Aux: remove unused highlight links ffa44a39 Aux: highlight Lua-style comments 29eeb9a8 Aux: check spelling in comments https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cd7ed47c4ad5b9c2c7539a6f77bbe11a8510a718 commit cd7ed47c4ad5b9c2c7539a6f77bbe11a8510a718 Author: Ben Boeckel AuthorDate: Fri Jul 22 12:32:59 2016 -0400 Commit: Ben Boeckel CommitDate: Fri Jul 22 12:33:23 2016 -0400 Aux: highlight commands using Function These are closer to functions than anything else. Also change the other groups which were highlighted with Function to other groups. diff --git a/Auxiliary/cmake-syntax.vim b/Auxiliary/cmake-syntax.vim index 35eae63..9ffc1e8 100644 --- a/Auxiliary/cmake-syntax.vim +++ b/Auxiliary/cmake-syntax.vim @@ -443,7 +443,7 @@ syn keyword cmakeTodo \ TODO FIXME XXX \ contained -hi def link cmakeCommand Statement +hi def link cmakeCommand Function hi def link cmakeCommandConditional Conditional hi def link cmakeCommandDeprecated WarningMsg hi def link cmakeCommandRepeat Repeat @@ -451,10 +451,10 @@ hi def link cmakeComment Comment hi def link cmakeEnvironment Special hi def link cmakeEscaped Special hi def link cmakeGeneratorExpression WarningMsg -hi def link cmakeGeneratorExpressions Function +hi def link cmakeGeneratorExpressions Keyword hi def link cmakeLuaComment Comment hi def link cmakeModule Include -hi def link cmakeProperty Function +hi def link cmakeProperty Constant hi def link cmakeRegistry Underlined hi def link cmakeString String hi def link cmakeTodo TODO https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bca8be583eda435202f7a0eb6e288646ce70570f commit bca8be583eda435202f7a0eb6e288646ce70570f Author: Ben Boeckel AuthorDate: Fri Jul 22 12:32:40 2016 -0400 Commit: Ben Boeckel CommitDate: Fri Jul 22 12:32:40 2016 -0400 Aux: sort the highlighting list diff --git a/Auxiliary/cmake-syntax.vim b/Auxiliary/cmake-syntax.vim index a41e9d5..35eae63 100644 --- a/Auxiliary/cmake-syntax.vim +++ b/Auxiliary/cmake-syntax.vim @@ -450,15 +450,15 @@ hi def link cmakeCommandRepeat Repeat hi def link cmakeComment Comment hi def link cmakeEnvironment Special hi def link cmakeEscaped Special +hi def link cmakeGeneratorExpression WarningMsg +hi def link cmakeGeneratorExpressions Function hi def link cmakeLuaComment Comment hi def link cmakeModule Include +hi def link cmakeProperty Function hi def link cmakeRegistry Underlined hi def link cmakeString String hi def link cmakeTodo TODO -hi def link cmakeGeneratorExpression WarningMsg hi def link cmakeVariable Identifier -hi def link cmakeGeneratorExpressions Function -hi def link cmakeProperty Function hi def link cmakeVariableValue Type hi def link cmakeKWExternalProject ModeMsg https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7decbe8ffb66a1a02b9ffab027f33558fa36873a commit 7decbe8ffb66a1a02b9ffab027f33558fa36873a Author: Ben Boeckel AuthorDate: Fri Jul 22 12:32:05 2016 -0400 Commit: Ben Boeckel CommitDate: Fri Jul 22 12:32:05 2016 -0400 Aux: highlight CMAKE_{CMAKE,CPACK}_COMMAND variables diff --git a/Auxiliary/cmake-syntax.vim b/Auxiliary/cmake-syntax.vim index 0526443..a41e9d5 100644 --- a/Auxiliary/cmake-syntax.vim +++ b/Auxiliary/cmake-syntax.vim @@ -36,7 +36,7 @@ syn keyword cmakeProperty \ contained syn keyword cmakeVariable - \ _BINARY_DIR _SOURCE_DIR _VERSION _VERSION_MAJOR _VERSION_MINOR _VERSION_PATCH _VERSION_TWEAK APPLE BORLAND BUILD_SHARED_LIBS CMAKE__POSTFIX CMAKE__ARCHIVE_APPEND CMAKE__ARCHIVE_CREATE CMAKE__ARCHIVE_FINISH CMAKE__COMPILER CMAKE__COMPILER_ABI CMAKE__COMPILER_EXTERNAL_TOOLCHAIN CMAKE__COMPILER_ID CMAKE__COMPILER_LAUNCHER CMAKE__COMPILER_LOADED CMAKE__COMPILER_TARGET CMAKE__COMPILER_VERSION CMAKE__COMPILE_OBJECT CMAKE__CREATE_SHARED_LIBRARY CMAKE__CREATE_SHARED_MODULE CMAKE__CREATE_STATIC_LIBRARY CMAKE__FLAGS CMAKE__FLAGS_DEBUG CMAKE__FLAGS_MINSIZEREL CMAKE__FLAGS_RELEASE CMAKE__FLAGS_RELWITHDEBINFO CMAKE__GHS_KERNEL_FLAGS_DEBUG CMAKE__GHS_KERNEL_FLAGS_MINSIZEREL CMAKE__GHS_KERNEL_FLAGS_RELEASE CMAKE__GHS_KERNEL_FLAGS_RELWITHDEBINFO CMAKE__IGNORE_EXTENSIONS CMAKE__IMPLICIT_INCLUDE_DIRECTORIES CMAKE__IMPLICIT_LINK_DIRECTORIES CMAKE__IMPLICIT_LINK_FRAMEWORK_DIRECTORIES CMAKE__IMPLICIT_LINK_LIBRARIES CMAKE__INCLUDE_WHAT_YOU_USE CMAKE__LIBRARY_ARCHITECTURE CMAKE__LINKER_PREFERENCE CMAKE__LINKER_PREFERENCE_PROPAGATES CMAKE__LINK_EXECUTABLE CMAKE__OUTPUT_EXTENSION CMAKE__PLATFORM_ID CMAKE__SIMULATE_ID CMAKE__SIMULATE_VERSION CMAKE__SIZEOF_DATA_PTR CMAKE__SOURCE_FILE_EXTENSIONS CMAKE__VISIBILITY_PRESET CMAKE_ABSOLUTE_DESTINATION_FILES CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS CMAKE_ANDROID_API CMAKE_ANDROID_API_MIN CMAKE_ANDROID_ARCH CMAKE_ANDROID_ASSETS_DIRECTORIES CMAKE_ANDROID_GUI CMAKE_ANDROID_JAR_DEPENDENCIES CMAKE_ANDROID_JAR_DIRECTORIES CMAKE_ANDROID_JAVA_SOURCE_DIR CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES CMAKE_ANDROID_PROCESS_MAX CMAKE_ANDROID_PROGUARD CMAKE_ANDROID_PROGUARD_CONFIG_PATH CMAKE_ANDROID_SECURE_PROPS_PATH CMAKE_ANDROID_SKIP_ANT_STEP CMAKE_ANDROID_STL_TYPE CMAKE_APPBUNDLE_PATH CMAKE_AR CMAKE_ARCHIVE_OUTPUT_DIRECTORY CMAKE_ARCHIVE_OUTPUT_DIRECTORY_ CMAKE_ARGC CMAKE_ARGV0 CMAKE_AUTOMOC CMAKE_AUTOMOC_MOC_OPTIONS CMAKE_AUTOMOC_RELAXED_MODE CMAKE_AUTORCC CMAKE_AUTORCC_OPTIONS CMAKE_AUTOUIC CMAKE_AUTOUIC_OPTIONS CMAKE_BACKWARDS_COMPATIBILITY CMAKE_BINARY_DIR CMAKE_BUILD_TOOL CMAKE_BUILD_TYPE CMAKE_BUILD_WITH_INSTALL_RPATH CMAKE_CACHEFILE_DIR CMAKE_CACHE_MAJOR_VERSION CMAKE_CACHE_MINOR_VERSION CMAKE_CACHE_PATCH_VERSION CMAKE_CFG_INTDIR CMAKE_CL_64 CMAKE_COLOR_MAKEFILE CMAKE_COMMAND CMAKE_COMPILER_2005 CMAKE_COMPILER_IS_GNU CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_ CMAKE_CONFIGURATION_TYPES CMAKE_CROSSCOMPILING CMAKE_CROSSCOMPILING_EMULATOR CMAKE_CTEST_COMMAND CMAKE_CURRENT_BINARY_DIR CMAKE_CURRENT_LIST_DIR CMAKE_CURRENT_LIST_FILE CMAKE_CURRENT_LIST_LINE CMAKE_CURRENT_SOURCE_DIR CMAKE_CXX_COMPILE_FEATURES CMAKE_CXX_EXTENSIONS CMAKE_CXX_STANDARD CMAKE_CXX_STANDARD_REQUIRED CMAKE_C_COMPILE_FEATURES CMAKE_C_EXTENSIONS CMAKE_C_STANDARD CMAKE_C_STANDARD_REQUIRED CMAKE_DEBUG_POSTFIX CMAKE_DEBUG_TARGET_PROPERTIES CMAKE_DISABLE_FIND_PACKAGE_ CMAKE_DL_LIBS CMAKE_EDIT_COMMAND CMAKE_ENABLE_EXPORTS CMAKE_ERROR_DEPRECATED CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION CMAKE_EXECUTABLE_SUFFIX CMAKE_EXE_LINKER_FLAGS CMAKE_EXE_LINKER_FLAGS_ CMAKE_EXPORT_COMPILE_COMMANDS CMAKE_EXPORT_NO_PACKAGE_REGISTRY CMAKE_EXTRA_GENERATOR CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES CMAKE_FIND_APPBUNDLE CMAKE_FIND_FRAMEWORK CMAKE_FIND_LIBRARY_PREFIXES CMAKE_FIND_LIBRARY_SUFFIXES CMAKE_FIND_NO_INSTALL_PREFIX CMAKE_FIND_PACKAGE_NAME CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY CMAKE_FIND_PACKAGE_WARN_NO_MODULE CMAKE_FIND_ROOT_PATH CMAKE_FIND_ROOT_PATH_MODE_INCLUDE CMAKE_FIND_ROOT_PATH_MODE_LIBRARY CMAKE_FIND_ROOT_PATH_MODE_PACKAGE CMAKE_FIND_ROOT_PATH_MODE_PROGRAM CMAKE_FRAMEWORK_PATH CMAKE_Fortran_FORMAT CMAKE_Fortran_MODDIR_DEFAULT CMAKE_Fortran_MODDIR_FLAG CMAKE_Fortran_MODOUT_FLAG CMAKE_Fortran_MODULE_DIRECTORY CMAKE_GENERATOR CMAKE_GENERATOR_PLATFORM CMAKE_GENERATOR_TOOLSET CMAKE_GNUtoMS CMAKE_HOME_DIRECTORY CMAKE_HOST_APPLE CMAKE_HOST_SYSTEM CMAKE_HOST_SYSTEM_NAME CMAKE_HOST_SYSTEM_PROCESSOR CMAKE_HOST_SYSTEM_VERSION CMAKE_HOST_UNIX CMAKE_HOST_WIN32 CMAKE_IGNORE_PATH CMAKE_IMPORT_LIBRARY_PREFIX CMAKE_IMPORT_LIBRARY_SUFFIX CMAKE_INCLUDE_CURRENT_DIR CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE CMAKE_INCLUDE_DIRECTORIES_BEFORE CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE CMAKE_INCLUDE_PATH CMAKE_INSTALL_DEFAULT_COMPONENT_NAME CMAKE_INSTALL_MESSAGE CMAKE_INSTALL_NAME_DIR CMAKE_INSTALL_PREFIX CMAKE_INSTALL_RPATH CMAKE_INSTALL_RPATH_USE_LINK_PATH CMAKE_INTERNAL_PLATFORM_ABI CMAKE_IOS_INSTALL_COMBINED CMAKE_JOB_POOL_COMPILE CMAKE_JOB_POOL_LINK CMAKE_LIBRARY_ARCHITECTURE CMAKE_LIBRARY_ARCHITECTURE_REGEX CMAKE_LIBRARY_OUTPUT_DIRECTORY CMAKE_LIBRARY_OUTPUT_DIRECTORY_ CMAKE_LIBRARY_PATH CMAKE_LIBRARY_PATH_FLAG CMAKE_LINK_DEF_FILE_FLAG CMAKE_LINK_DEPENDS_NO_SHARED CMAKE_LINK_INTERFACE_LIBRARIES CMAKE_LINK_LIBRARY_FILE_FLAG CMAKE_LINK_LIBRARY_FLAG CMAKE_LINK_LIBRARY_SUFFIX CMAKE_LINK_SEARCH_END_STATIC CMAKE_LINK_SEARCH_START_STATIC CMAKE_MACOSX_BUNDLE CMAKE_MACOSX_RPATH CMAKE_MAJOR_VERSION CMAKE_MAKE_PROGRAM CMAKE_MAP_IMPORTED_CONFIG_ CMAKE_MATCH_COUNT CMAKE_MFC_FLAG CMAKE_MINIMUM_REQUIRED_VERSION CMAKE_MINOR_VERSION CMAKE_MODULE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS_ CMAKE_MODULE_PATH CMAKE_NOT_USING_CONFIG_FLAGS CMAKE_NO_BUILTIN_CHRPATH CMAKE_NO_SYSTEM_FROM_IMPORTED CMAKE_OBJECT_PATH_MAX CMAKE_OSX_ARCHITECTURES CMAKE_OSX_DEPLOYMENT_TARGET CMAKE_OSX_SYSROOT CMAKE_PARENT_LIST_FILE CMAKE_PATCH_VERSION CMAKE_PDB_OUTPUT_DIRECTORY CMAKE_PDB_OUTPUT_DIRECTORY_ CMAKE_POLICY_DEFAULT_CMP CMAKE_POLICY_WARNING_CMP CMAKE_POSITION_INDEPENDENT_CODE CMAKE_PREFIX_PATH CMAKE_PROGRAM_PATH CMAKE_PROJECT__INCLUDE CMAKE_PROJECT_NAME CMAKE_RANLIB CMAKE_ROOT CMAKE_RUNTIME_OUTPUT_DIRECTORY CMAKE_RUNTIME_OUTPUT_DIRECTORY_ CMAKE_SCRIPT_MODE_FILE CMAKE_SHARED_LIBRARY_PREFIX CMAKE_SHARED_LIBRARY_SUFFIX CMAKE_SHARED_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS_ CMAKE_SHARED_MODULE_PREFIX CMAKE_SHARED_MODULE_SUFFIX CMAKE_SIZEOF_VOID_P CMAKE_SKIP_BUILD_RPATH CMAKE_SKIP_INSTALL_ALL_DEPENDENCY CMAKE_SKIP_INSTALL_RPATH CMAKE_SKIP_INSTALL_RULES CMAKE_SKIP_RPATH CMAKE_SOURCE_DIR CMAKE_STAGING_PREFIX CMAKE_STANDARD_LIBRARIES CMAKE_STATIC_LIBRARY_PREFIX CMAKE_STATIC_LIBRARY_SUFFIX CMAKE_STATIC_LINKER_FLAGS CMAKE_STATIC_LINKER_FLAGS_ CMAKE_SYSROOT CMAKE_SYSTEM CMAKE_SYSTEM_APPBUNDLE_PATH CMAKE_SYSTEM_FRAMEWORK_PATH CMAKE_SYSTEM_IGNORE_PATH CMAKE_SYSTEM_INCLUDE_PATH CMAKE_SYSTEM_LIBRARY_PATH CMAKE_SYSTEM_NAME CMAKE_SYSTEM_PREFIX_PATH CMAKE_SYSTEM_PROCESSOR CMAKE_SYSTEM_PROGRAM_PATH CMAKE_SYSTEM_VERSION CMAKE_TOOLCHAIN_FILE CMAKE_TRY_COMPILE_CONFIGURATION CMAKE_TWEAK_VERSION CMAKE_USER_MAKE_RULES_OVERRIDE CMAKE_USER_MAKE_RULES_OVERRIDE_ CMAKE_USE_RELATIVE_PATHS CMAKE_VERBOSE_MAKEFILE CMAKE_VERSION CMAKE_VISIBILITY_INLINES_HIDDEN CMAKE_VS_DEVENV_COMMAND CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD CMAKE_VS_INTEL_Fortran_PROJECT_VERSION CMAKE_VS_MSBUILD_COMMAND CMAKE_VS_MSDEV_COMMAND CMAKE_VS_NsightTegra_VERSION CMAKE_VS_PLATFORM_NAME CMAKE_VS_PLATFORM_TOOLSET CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION CMAKE_WARN_DEPRECATED CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION CMAKE_WIN32_EXECUTABLE CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS CMAKE_XCODE_ATTRIBUTE_ CMAKE_XCODE_PLATFORM_TOOLSET CPACK_ABSOLUTE_DESTINATION_FILES CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION CPACK_INCLUDE_TOPLEVEL_DIRECTORY CPACK_INSTALL_SCRIPT CPACK_PACKAGING_INSTALL_PREFIX CPACK_SET_DESTDIR CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION CTEST_BINARY_DIRECTORY CTEST_BUILD_COMMAND CTEST_BUILD_NAME CTEST_BZR_COMMAND CTEST_BZR_UPDATE_OPTIONS CTEST_CHANGE_ID CTEST_CHECKOUT_COMMAND CTEST_CONFIGURATION_TYPE CTEST_CONFIGURE_COMMAND CTEST_COVERAGE_COMMAND CTEST_COVERAGE_EXTRA_FLAGS CTEST_CURL_OPTIONS CTEST_CUSTOM_COVERAGE_EXCLUDE CTEST_CUSTOM_ERROR_EXCEPTION CTEST_CUSTOM_ERROR_MATCH CTEST_CUSTOM_ERROR_POST_CONTEXT CTEST_CUSTOM_ERROR_PRE_CONTEXT CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE CTEST_CUSTOM_MEMCHECK_IGNORE CTEST_CUSTOM_POST_MEMCHECK CTEST_CUSTOM_POST_TEST CTEST_CUSTOM_PRE_MEMCHECK CTEST_CUSTOM_PRE_TEST CTEST_CUSTOM_TEST_IGNORE CTEST_CUSTOM_WARNING_EXCEPTION CTEST_CUSTOM_WARNING_MATCH CTEST_CVS_CHECKOUT CTEST_CVS_COMMAND CTEST_CVS_UPDATE_OPTIONS CTEST_DROP_LOCATION CTEST_DROP_METHOD CTEST_DROP_SITE CTEST_DROP_SITE_CDASH CTEST_DROP_SITE_PASSWORD CTEST_DROP_SITE_USER CTEST_EXTRA_COVERAGE_GLOB CTEST_GIT_COMMAND CTEST_GIT_UPDATE_CUSTOM CTEST_GIT_UPDATE_OPTIONS CTEST_HG_COMMAND CTEST_HG_UPDATE_OPTIONS CTEST_MEMORYCHECK_COMMAND CTEST_MEMORYCHECK_COMMAND_OPTIONS CTEST_MEMORYCHECK_SANITIZER_OPTIONS CTEST_MEMORYCHECK_SUPPRESSIONS_FILE CTEST_MEMORYCHECK_TYPE CTEST_NIGHTLY_START_TIME CTEST_P4_CLIENT CTEST_P4_COMMAND CTEST_P4_OPTIONS CTEST_P4_UPDATE_OPTIONS CTEST_SCP_COMMAND CTEST_SITE CTEST_SOURCE_DIRECTORY CTEST_SVN_COMMAND CTEST_SVN_OPTIONS CTEST_SVN_UPDATE_OPTIONS CTEST_TEST_LOAD CTEST_TEST_TIMEOUT CTEST_TRIGGER_SITE CTEST_UPDATE_COMMAND CTEST_UPDATE_OPTIONS CTEST_UPDATE_VERSION_ONLY CTEST_USE_LAUNCHERS CYGWIN ENV EXECUTABLE_OUTPUT_PATH GHS-MULTI LIBRARY_OUTPUT_PATH MINGW MSVC MSVC10 MSVC11 MSVC12 MSVC14 MSVC60 MSVC70 MSVC71 MSVC80 MSVC90 MSVC_IDE MSVC_VERSION PROJECT_BINARY_DIR PROJECT_NAME PROJECT_SOURCE_DIR PROJECT_VERSION PROJECT_VERSION_MAJOR PROJECT_VERSION_MINOR PROJECT_VERSION_PATCH PROJECT_VERSION_TWEAK UNIX WIN32 WINCE WINDOWS_PHONE WINDOWS_STORE XCODE_VERSION + \ _BINARY_DIR _SOURCE_DIR _VERSION _VERSION_MAJOR _VERSION_MINOR _VERSION_PATCH _VERSION_TWEAK APPLE BORLAND BUILD_SHARED_LIBS CMAKE__POSTFIX CMAKE__ARCHIVE_APPEND CMAKE__ARCHIVE_CREATE CMAKE__ARCHIVE_FINISH CMAKE__COMPILER CMAKE__COMPILER_ABI CMAKE__COMPILER_EXTERNAL_TOOLCHAIN CMAKE__COMPILER_ID CMAKE__COMPILER_LAUNCHER CMAKE__COMPILER_LOADED CMAKE__COMPILER_TARGET CMAKE__COMPILER_VERSION CMAKE__COMPILE_OBJECT CMAKE__CREATE_SHARED_LIBRARY CMAKE__CREATE_SHARED_MODULE CMAKE__CREATE_STATIC_LIBRARY CMAKE__FLAGS CMAKE__FLAGS_DEBUG CMAKE__FLAGS_MINSIZEREL CMAKE__FLAGS_RELEASE CMAKE__FLAGS_RELWITHDEBINFO CMAKE__GHS_KERNEL_FLAGS_DEBUG CMAKE__GHS_KERNEL_FLAGS_MINSIZEREL CMAKE__GHS_KERNEL_FLAGS_RELEASE CMAKE__GHS_KERNEL_FLAGS_RELWITHDEBINFO CMAKE__IGNORE_EXTENSIONS CMAKE__IMPLICIT_INCLUDE_DIRECTORIES CMAKE__IMPLICIT_LINK_DIRECTORIES CMAKE__IMPLICIT_LINK_FRAMEWORK_DIRECTORIES CMAKE__IMPLICIT_LINK_LIBRARIES CMAKE__INCLUDE_WHAT_YOU_USE CMAKE__LIBRARY_ARCHITECTURE CMAKE__LINKER_PREFERENCE CMAKE__LINKER_PREFERENCE_PROPAGATES CMAKE__LINK_EXECUTABLE CMAKE__OUTPUT_EXTENSION CMAKE__PLATFORM_ID CMAKE__SIMULATE_ID CMAKE__SIMULATE_VERSION CMAKE__SIZEOF_DATA_PTR CMAKE__SOURCE_FILE_EXTENSIONS CMAKE__VISIBILITY_PRESET CMAKE_ABSOLUTE_DESTINATION_FILES CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS CMAKE_ANDROID_API CMAKE_ANDROID_API_MIN CMAKE_ANDROID_ARCH CMAKE_ANDROID_ASSETS_DIRECTORIES CMAKE_ANDROID_GUI CMAKE_ANDROID_JAR_DEPENDENCIES CMAKE_ANDROID_JAR_DIRECTORIES CMAKE_ANDROID_JAVA_SOURCE_DIR CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES CMAKE_ANDROID_PROCESS_MAX CMAKE_ANDROID_PROGUARD CMAKE_ANDROID_PROGUARD_CONFIG_PATH CMAKE_ANDROID_SECURE_PROPS_PATH CMAKE_ANDROID_SKIP_ANT_STEP CMAKE_ANDROID_STL_TYPE CMAKE_APPBUNDLE_PATH CMAKE_AR CMAKE_ARCHIVE_OUTPUT_DIRECTORY CMAKE_ARCHIVE_OUTPUT_DIRECTORY_ CMAKE_ARGC CMAKE_ARGV0 CMAKE_AUTOMOC CMAKE_AUTOMOC_MOC_OPTIONS CMAKE_AUTOMOC_RELAXED_MODE CMAKE_AUTORCC CMAKE_AUTORCC_OPTIONS CMAKE_AUTOUIC CMAKE_AUTOUIC_OPTIONS CMAKE_BACKWARDS_COMPATIBILITY CMAKE_BINARY_DIR CMAKE_BUILD_TOOL CMAKE_BUILD_TYPE CMAKE_BUILD_WITH_INSTALL_RPATH CMAKE_CACHEFILE_DIR CMAKE_CACHE_MAJOR_VERSION CMAKE_CACHE_MINOR_VERSION CMAKE_CACHE_PATCH_VERSION CMAKE_CFG_INTDIR CMAKE_CL_64 CMAKE_COLOR_MAKEFILE CMAKE_COMMAND CMAKE_COMPILER_2005 CMAKE_COMPILER_IS_GNU CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_ CMAKE_CONFIGURATION_TYPES CMAKE_CROSSCOMPILING CMAKE_CROSSCOMPILING_EMULATOR CMAKE_CMAKE_COMMAND CMAKE_CPACK_COMMAND CMAKE_CTEST_COMMAND CMAKE_CURRENT_BINARY_DIR CMAKE_CURRENT_LIST_DIR CMAKE_CURRENT_LIST_FILE CMAKE_CURRENT_LIST_LINE CMAKE_CURRENT_SOURCE_DIR CMAKE_CXX_COMPILE_FEATURES CMAKE_CXX_EXTENSIONS CMAKE_CXX_STANDARD CMAKE_CXX_STANDARD_REQUIRED CMAKE_C_COMPILE_FEATURES CMAKE_C_EXTENSIONS CMAKE_C_STANDARD CMAKE_C_STANDARD_REQUIRED CMAKE_DEBUG_POSTFIX CMAKE_DEBUG_TARGET_PROPERTIES CMAKE_DISABLE_FIND_PACKAGE_ CMAKE_DL_LIBS CMAKE_EDIT_COMMAND CMAKE_ENABLE_EXPORTS CMAKE_ERROR_DEPRECATED CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION CMAKE_EXECUTABLE_SUFFIX CMAKE_EXE_LINKER_FLAGS CMAKE_EXE_LINKER_FLAGS_ CMAKE_EXPORT_COMPILE_COMMANDS CMAKE_EXPORT_NO_PACKAGE_REGISTRY CMAKE_EXTRA_GENERATOR CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES CMAKE_FIND_APPBUNDLE CMAKE_FIND_FRAMEWORK CMAKE_FIND_LIBRARY_PREFIXES CMAKE_FIND_LIBRARY_SUFFIXES CMAKE_FIND_NO_INSTALL_PREFIX CMAKE_FIND_PACKAGE_NAME CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY CMAKE_FIND_PACKAGE_WARN_NO_MODULE CMAKE_FIND_ROOT_PATH CMAKE_FIND_ROOT_PATH_MODE_INCLUDE CMAKE_FIND_ROOT_PATH_MODE_LIBRARY CMAKE_FIND_ROOT_PATH_MODE_PACKAGE CMAKE_FIND_ROOT_PATH_MODE_PROGRAM CMAKE_FRAMEWORK_PATH CMAKE_Fortran_FORMAT CMAKE_Fortran_MODDIR_DEFAULT CMAKE_Fortran_MODDIR_FLAG CMAKE_Fortran_MODOUT_FLAG CMAKE_Fortran_MODULE_DIRECTORY CMAKE_GENERATOR CMAKE_GENERATOR_PLATFORM CMAKE_GENERATOR_TOOLSET CMAKE_GNUtoMS CMAKE_HOME_DIRECTORY CMAKE_HOST_APPLE CMAKE_HOST_SYSTEM CMAKE_HOST_SYSTEM_NAME CMAKE_HOST_SYSTEM_PROCESSOR CMAKE_HOST_SYSTEM_VERSION CMAKE_HOST_UNIX CMAKE_HOST_WIN32 CMAKE_IGNORE_PATH CMAKE_IMPORT_LIBRARY_PREFIX CMAKE_IMPORT_LIBRARY_SUFFIX CMAKE_INCLUDE_CURRENT_DIR CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE CMAKE_INCLUDE_DIRECTORIES_BEFORE CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE CMAKE_INCLUDE_PATH CMAKE_INSTALL_DEFAULT_COMPONENT_NAME CMAKE_INSTALL_MESSAGE CMAKE_INSTALL_NAME_DIR CMAKE_INSTALL_PREFIX CMAKE_INSTALL_RPATH CMAKE_INSTALL_RPATH_USE_LINK_PATH CMAKE_INTERNAL_PLATFORM_ABI CMAKE_IOS_INSTALL_COMBINED CMAKE_JOB_POOL_COMPILE CMAKE_JOB_POOL_LINK CMAKE_LIBRARY_ARCHITECTURE CMAKE_LIBRARY_ARCHITECTURE_REGEX CMAKE_LIBRARY_OUTPUT_DIRECTORY CMAKE_LIBRARY_OUTPUT_DIRECTORY_ CMAKE_LIBRARY_PATH CMAKE_LIBRARY_PATH_FLAG CMAKE_LINK_DEF_FILE_FLAG CMAKE_LINK_DEPENDS_NO_SHARED CMAKE_LINK_INTERFACE_LIBRARIES CMAKE_LINK_LIBRARY_FILE_FLAG CMAKE_LINK_LIBRARY_FLAG CMAKE_LINK_LIBRARY_SUFFIX CMAKE_LINK_SEARCH_END_STATIC CMAKE_LINK_SEARCH_START_STATIC CMAKE_MACOSX_BUNDLE CMAKE_MACOSX_RPATH CMAKE_MAJOR_VERSION CMAKE_MAKE_PROGRAM CMAKE_MAP_IMPORTED_CONFIG_ CMAKE_MATCH_COUNT CMAKE_MFC_FLAG CMAKE_MINIMUM_REQUIRED_VERSION CMAKE_MINOR_VERSION CMAKE_MODULE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS_ CMAKE_MODULE_PATH CMAKE_NOT_USING_CONFIG_FLAGS CMAKE_NO_BUILTIN_CHRPATH CMAKE_NO_SYSTEM_FROM_IMPORTED CMAKE_OBJECT_PATH_MAX CMAKE_OSX_ARCHITECTURES CMAKE_OSX_DEPLOYMENT_TARGET CMAKE_OSX_SYSROOT CMAKE_PARENT_LIST_FILE CMAKE_PATCH_VERSION CMAKE_PDB_OUTPUT_DIRECTORY CMAKE_PDB_OUTPUT_DIRECTORY_ CMAKE_POLICY_DEFAULT_CMP CMAKE_POLICY_WARNING_CMP CMAKE_POSITION_INDEPENDENT_CODE CMAKE_PREFIX_PATH CMAKE_PROGRAM_PATH CMAKE_PROJECT__INCLUDE CMAKE_PROJECT_NAME CMAKE_RANLIB CMAKE_ROOT CMAKE_RUNTIME_OUTPUT_DIRECTORY CMAKE_RUNTIME_OUTPUT_DIRECTORY_ CMAKE_SCRIPT_MODE_FILE CMAKE_SHARED_LIBRARY_PREFIX CMAKE_SHARED_LIBRARY_SUFFIX CMAKE_SHARED_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS_ CMAKE_SHARED_MODULE_PREFIX CMAKE_SHARED_MODULE_SUFFIX CMAKE_SIZEOF_VOID_P CMAKE_SKIP_BUILD_RPATH CMAKE_SKIP_INSTALL_ALL_DEPENDENCY CMAKE_SKIP_INSTALL_RPATH CMAKE_SKIP_INSTALL_RULES CMAKE_SKIP_RPATH CMAKE_SOURCE_DIR CMAKE_STAGING_PREFIX CMAKE_STANDARD_LIBRARIES CMAKE_STATIC_LIBRARY_PREFIX CMAKE_STATIC_LIBRARY_SUFFIX CMAKE_STATIC_LINKER_FLAGS CMAKE_STATIC_LINKER_FLAGS_ CMAKE_SYSROOT CMAKE_SYSTEM CMAKE_SYSTEM_APPBUNDLE_PATH CMAKE_SYSTEM_FRAMEWORK_PATH CMAKE_SYSTEM_IGNORE_PATH CMAKE_SYSTEM_INCLUDE_PATH CMAKE_SYSTEM_LIBRARY_PATH CMAKE_SYSTEM_NAME CMAKE_SYSTEM_PREFIX_PATH CMAKE_SYSTEM_PROCESSOR CMAKE_SYSTEM_PROGRAM_PATH CMAKE_SYSTEM_VERSION CMAKE_TOOLCHAIN_FILE CMAKE_TRY_COMPILE_CONFIGURATION CMAKE_TWEAK_VERSION CMAKE_USER_MAKE_RULES_OVERRIDE CMAKE_USER_MAKE_RULES_OVERRIDE_ CMAKE_USE_RELATIVE_PATHS CMAKE_VERBOSE_MAKEFILE CMAKE_VERSION CMAKE_VISIBILITY_INLINES_HIDDEN CMAKE_VS_DEVENV_COMMAND CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD CMAKE_VS_INTEL_Fortran_PROJECT_VERSION CMAKE_VS_MSBUILD_COMMAND CMAKE_VS_MSDEV_COMMAND CMAKE_VS_NsightTegra_VERSION CMAKE_VS_PLATFORM_NAME CMAKE_VS_PLATFORM_TOOLSET CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION CMAKE_WARN_DEPRECATED CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION CMAKE_WIN32_EXECUTABLE CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS CMAKE_XCODE_ATTRIBUTE_ CMAKE_XCODE_PLATFORM_TOOLSET CPACK_ABSOLUTE_DESTINATION_FILES CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION CPACK_INCLUDE_TOPLEVEL_DIRECTORY CPACK_INSTALL_SCRIPT CPACK_PACKAGING_INSTALL_PREFIX CPACK_SET_DESTDIR CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION CTEST_BINARY_DIRECTORY CTEST_BUILD_COMMAND CTEST_BUILD_NAME CTEST_BZR_COMMAND CTEST_BZR_UPDATE_OPTIONS CTEST_CHANGE_ID CTEST_CHECKOUT_COMMAND CTEST_CONFIGURATION_TYPE CTEST_CONFIGURE_COMMAND CTEST_COVERAGE_COMMAND CTEST_COVERAGE_EXTRA_FLAGS CTEST_CURL_OPTIONS CTEST_CUSTOM_COVERAGE_EXCLUDE CTEST_CUSTOM_ERROR_EXCEPTION CTEST_CUSTOM_ERROR_MATCH CTEST_CUSTOM_ERROR_POST_CONTEXT CTEST_CUSTOM_ERROR_PRE_CONTEXT CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE CTEST_CUSTOM_MEMCHECK_IGNORE CTEST_CUSTOM_POST_MEMCHECK CTEST_CUSTOM_POST_TEST CTEST_CUSTOM_PRE_MEMCHECK CTEST_CUSTOM_PRE_TEST CTEST_CUSTOM_TEST_IGNORE CTEST_CUSTOM_WARNING_EXCEPTION CTEST_CUSTOM_WARNING_MATCH CTEST_CVS_CHECKOUT CTEST_CVS_COMMAND CTEST_CVS_UPDATE_OPTIONS CTEST_DROP_LOCATION CTEST_DROP_METHOD CTEST_DROP_SITE CTEST_DROP_SITE_CDASH CTEST_DROP_SITE_PASSWORD CTEST_DROP_SITE_USER CTEST_EXTRA_COVERAGE_GLOB CTEST_GIT_COMMAND CTEST_GIT_UPDATE_CUSTOM CTEST_GIT_UPDATE_OPTIONS CTEST_HG_COMMAND CTEST_HG_UPDATE_OPTIONS CTEST_MEMORYCHECK_COMMAND CTEST_MEMORYCHECK_COMMAND_OPTIONS CTEST_MEMORYCHECK_SANITIZER_OPTIONS CTEST_MEMORYCHECK_SUPPRESSIONS_FILE CTEST_MEMORYCHECK_TYPE CTEST_NIGHTLY_START_TIME CTEST_P4_CLIENT CTEST_P4_COMMAND CTEST_P4_OPTIONS CTEST_P4_UPDATE_OPTIONS CTEST_SCP_COMMAND CTEST_SITE CTEST_SOURCE_DIRECTORY CTEST_SVN_COMMAND CTEST_SVN_OPTIONS CTEST_SVN_UPDATE_OPTIONS CTEST_TEST_LOAD CTEST_TEST_TIMEOUT CTEST_TRIGGER_SITE CTEST_UPDATE_COMMAND CTEST_UPDATE_OPTIONS CTEST_UPDATE_VERSION_ONLY CTEST_USE_LAUNCHERS CYGWIN ENV EXECUTABLE_OUTPUT_PATH GHS-MULTI LIBRARY_OUTPUT_PATH MINGW MSVC MSVC10 MSVC11 MSVC12 MSVC14 MSVC60 MSVC70 MSVC71 MSVC80 MSVC90 MSVC_IDE MSVC_VERSION PROJECT_BINARY_DIR PROJECT_NAME PROJECT_SOURCE_DIR PROJECT_VERSION PROJECT_VERSION_MAJOR PROJECT_VERSION_MINOR PROJECT_VERSION_PATCH PROJECT_VERSION_TWEAK UNIX WIN32 WINCE WINDOWS_PHONE WINDOWS_STORE XCODE_VERSION \ contained syn keyword cmakeModule https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2b57b139201f7fa1959702db0a8c18482452f903 commit 2b57b139201f7fa1959702db0a8c18482452f903 Author: Ben Boeckel AuthorDate: Fri Jul 22 12:31:26 2016 -0400 Commit: Ben Boeckel CommitDate: Fri Jul 22 12:31:26 2016 -0400 Aux: highlight modules using Include They are closer to Include than generic preprocessor lines. diff --git a/Auxiliary/cmake-syntax.vim b/Auxiliary/cmake-syntax.vim index 25c66df..0526443 100644 --- a/Auxiliary/cmake-syntax.vim +++ b/Auxiliary/cmake-syntax.vim @@ -451,7 +451,7 @@ hi def link cmakeComment Comment hi def link cmakeEnvironment Special hi def link cmakeEscaped Special hi def link cmakeLuaComment Comment -hi def link cmakeModule PreProc +hi def link cmakeModule Include hi def link cmakeRegistry Underlined hi def link cmakeString String hi def link cmakeTodo TODO https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8ac4e2cfa283d6a27ba11c9ce6e2cea44457b5cb commit 8ac4e2cfa283d6a27ba11c9ce6e2cea44457b5cb Author: Ben Boeckel AuthorDate: Fri Jul 22 12:30:57 2016 -0400 Commit: Ben Boeckel CommitDate: Fri Jul 22 12:30:57 2016 -0400 Aux: highlight conditiona and repeat commands differently diff --git a/Auxiliary/cmake-syntax.vim b/Auxiliary/cmake-syntax.vim index e41a2e5..25c66df 100644 --- a/Auxiliary/cmake-syntax.vim +++ b/Auxiliary/cmake-syntax.vim @@ -426,7 +426,13 @@ syn keyword cmakeGeneratorExpressions syn case ignore syn keyword cmakeCommand - \ add_compile_options add_custom_command add_custom_target add_definitions add_dependencies add_executable add_library add_subdirectory add_test aux_source_directory break build_command cmake_host_system_information cmake_minimum_required cmake_parse_arguments cmake_policy configure_file continue create_test_sourcelist ctest_build ctest_configure ctest_coverage ctest_empty_binary_directory ctest_memcheck ctest_read_custom_files ctest_run_script ctest_sleep ctest_start ctest_submit ctest_test ctest_update ctest_upload define_property else elseif enable_language enable_testing endforeach endfunction endif endmacro endwhile execute_process export file find_file find_library find_package find_path find_program fltk_wrap_ui foreach function get_cmake_property get_directory_property get_filename_component get_property get_source_file_property get_target_property get_test_property if include include_directories include_external_msproject include_regular_expression install link_directories list load_cache load_command macro mark_as_advanced math message option project qt_wrap_cpp qt_wrap_ui remove_definitions return separate_arguments set set_directory_properties set_property set_source_files_properties set_target_properties set_tests_properties site_name source_group string target_compile_definitions target_compile_features target_compile_options target_include_directories target_link_libraries target_sources try_compile try_run unset variable_watch while + \ add_compile_options add_custom_command add_custom_target add_definitions add_dependencies add_executable add_library add_subdirectory add_test aux_source_directory break build_command cmake_host_system_information cmake_minimum_required cmake_parse_arguments cmake_policy configure_file continue create_test_sourcelist ctest_build ctest_configure ctest_coverage ctest_empty_binary_directory ctest_memcheck ctest_read_custom_files ctest_run_script ctest_sleep ctest_start ctest_submit ctest_test ctest_update ctest_upload define_property enable_language enable_testing endfunction endmacro execute_process export file find_file find_library find_package find_path find_program fltk_wrap_ui function get_cmake_property get_directory_property get_filename_component get_property get_source_file_property get_target_property get_test_property include include_directories include_external_msproject include_regular_expression install link_directories list load_cache load_command macro mark_as_advanced math message option project qt_wrap_cpp qt_wrap_ui remove_definitions return separate_arguments set set_directory_properties set_property set_source_files_properties set_target_properties set_tests_properties site_name source_group string target_compile_definitions target_compile_features target_compile_options target_include_directories target_link_libraries target_sources try_compile try_run unset variable_watch + \ nextgroup=cmakeArguments +syn keyword cmakeCommandConditional + \ else elseif endif if + \ nextgroup=cmakeArguments +syn keyword cmakeCommandRepeat + \ endforeach endwhile foreach while \ nextgroup=cmakeArguments syn keyword cmakeCommandDeprecated \ build_name exec_program export_library_dependencies install_files install_programs install_targets link_libraries make_directory output_required_files remove subdir_depends subdirs use_mangled_mesa utility_source variable_requires write_file @@ -438,7 +444,9 @@ syn keyword cmakeTodo \ contained hi def link cmakeCommand Statement +hi def link cmakeCommandConditional Conditional hi def link cmakeCommandDeprecated WarningMsg +hi def link cmakeCommandRepeat Repeat hi def link cmakeComment Comment hi def link cmakeEnvironment Special hi def link cmakeEscaped Special https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3b3bd880a3de1d6348d746c15b6bc3b32757343a commit 3b3bd880a3de1d6348d746c15b6bc3b32757343a Author: Ben Boeckel AuthorDate: Fri Jul 22 12:25:25 2016 -0400 Commit: Ben Boeckel CommitDate: Fri Jul 22 12:30:44 2016 -0400 Aux: highlight deprecated commands as warnings diff --git a/Auxiliary/cmake-syntax.vim b/Auxiliary/cmake-syntax.vim index 8917ecc..e41a2e5 100644 --- a/Auxiliary/cmake-syntax.vim +++ b/Auxiliary/cmake-syntax.vim @@ -426,7 +426,10 @@ syn keyword cmakeGeneratorExpressions syn case ignore syn keyword cmakeCommand - \ add_compile_options add_custom_command add_custom_target add_definitions add_dependencies add_executable add_library add_subdirectory add_test aux_source_directory break build_command build_name cmake_host_system_information cmake_minimum_required cmake_parse_arguments cmake_policy configure_file continue create_test_sourcelist ctest_build ctest_configure ctest_coverage ctest_empty_binary_directory ctest_memcheck ctest_read_custom_files ctest_run_script ctest_sleep ctest_start ctest_submit ctest_test ctest_update ctest_upload define_property else elseif enable_language enable_testing endforeach endfunction endif endmacro endwhile exec_program execute_process export export_library_dependencies file find_file find_library find_package find_path find_program fltk_wrap_ui foreach function get_cmake_property get_directory_property get_filename_component get_property get_source_file_property get_target_property get_test_property if include include_directories include_external_msproject include_regular_expression install install_files install_programs install_targets link_directories link_libraries list load_cache load_command macro make_directory mark_as_advanced math message option output_required_files project qt_wrap_cpp qt_wrap_ui remove remove_definitions return separate_arguments set set_directory_properties set_property set_source_files_properties set_target_properties set_tests_properties site_name source_group string subdir_depends subdirs target_compile_definitions target_compile_features target_compile_options target_include_directories target_link_libraries target_sources try_compile try_run unset use_mangled_mesa utility_source variable_requires variable_watch while write_file + \ add_compile_options add_custom_command add_custom_target add_definitions add_dependencies add_executable add_library add_subdirectory add_test aux_source_directory break build_command cmake_host_system_information cmake_minimum_required cmake_parse_arguments cmake_policy configure_file continue create_test_sourcelist ctest_build ctest_configure ctest_coverage ctest_empty_binary_directory ctest_memcheck ctest_read_custom_files ctest_run_script ctest_sleep ctest_start ctest_submit ctest_test ctest_update ctest_upload define_property else elseif enable_language enable_testing endforeach endfunction endif endmacro endwhile execute_process export file find_file find_library find_package find_path find_program fltk_wrap_ui foreach function get_cmake_property get_directory_property get_filename_component get_property get_source_file_property get_target_property get_test_property if include include_directories include_external_msproject include_regular_expression install link_directories list load_cache load_command macro mark_as_advanced math message option project qt_wrap_cpp qt_wrap_ui remove_definitions return separate_arguments set set_directory_properties set_property set_source_files_properties set_target_properties set_tests_properties site_name source_group string target_compile_definitions target_compile_features target_compile_options target_include_directories target_link_libraries target_sources try_compile try_run unset variable_watch while + \ nextgroup=cmakeArguments +syn keyword cmakeCommandDeprecated + \ build_name exec_program export_library_dependencies install_files install_programs install_targets link_libraries make_directory output_required_files remove subdir_depends subdirs use_mangled_mesa utility_source variable_requires write_file \ nextgroup=cmakeArguments syn case match @@ -435,6 +438,7 @@ syn keyword cmakeTodo \ contained hi def link cmakeCommand Statement +hi def link cmakeCommandDeprecated WarningMsg hi def link cmakeComment Comment hi def link cmakeEnvironment Special hi def link cmakeEscaped Special https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=481f8cf1cc73f99d06ed75752715f2f9fbb8f0ba commit 481f8cf1cc73f99d06ed75752715f2f9fbb8f0ba Author: Ben Boeckel AuthorDate: Fri Jul 22 12:24:23 2016 -0400 Commit: Ben Boeckel CommitDate: Fri Jul 22 12:24:23 2016 -0400 Aux: remove unused highlight links diff --git a/Auxiliary/cmake-syntax.vim b/Auxiliary/cmake-syntax.vim index 44619c7..8917ecc 100644 --- a/Auxiliary/cmake-syntax.vim +++ b/Auxiliary/cmake-syntax.vim @@ -437,9 +437,7 @@ syn keyword cmakeTodo hi def link cmakeCommand Statement hi def link cmakeComment Comment hi def link cmakeEnvironment Special -hi def link cmakeError Error hi def link cmakeEscaped Special -hi def link cmakeMacro PreProc hi def link cmakeLuaComment Comment hi def link cmakeModule PreProc hi def link cmakeRegistry Underlined https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ffa44a39c9d7e092f8c86a4648b976ccc64da4d6 commit ffa44a39c9d7e092f8c86a4648b976ccc64da4d6 Author: Ben Boeckel AuthorDate: Fri Jul 22 12:23:53 2016 -0400 Commit: Ben Boeckel CommitDate: Fri Jul 22 12:23:53 2016 -0400 Aux: highlight Lua-style comments diff --git a/Auxiliary/cmake-syntax.vim b/Auxiliary/cmake-syntax.vim index 6a888b6..44619c7 100644 --- a/Auxiliary/cmake-syntax.vim +++ b/Auxiliary/cmake-syntax.vim @@ -16,6 +16,7 @@ endif syn match cmakeEscaped /\(\\\\\|\\"\|\\n\|\\t\)/ contained syn region cmakeComment start="#" end="$" contains=cmakeTodo, at Spell +syn region cmakeLuaComment start="\[\z(=*\)\[" end="\]\z1\]" contains=cmakeTodo, at Spell syn region cmakeGeneratorExpression start=/$/ \ contained oneline contains=CONTAINED,cmakeTodo,cmakeVariable,cmakeProperty,cmakeGeneratorExpressions syn region cmakeRegistry start=/\[/ end=/]/ @@ -439,6 +440,7 @@ hi def link cmakeEnvironment Special hi def link cmakeError Error hi def link cmakeEscaped Special hi def link cmakeMacro PreProc +hi def link cmakeLuaComment Comment hi def link cmakeModule PreProc hi def link cmakeRegistry Underlined hi def link cmakeString String https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=29eeb9a8fd9a6417b99e7fbd8b406f72fc83f35f commit 29eeb9a8fd9a6417b99e7fbd8b406f72fc83f35f Author: Ben Boeckel AuthorDate: Fri Jul 22 12:23:16 2016 -0400 Commit: Ben Boeckel CommitDate: Fri Jul 22 12:23:16 2016 -0400 Aux: check spelling in comments diff --git a/Auxiliary/cmake-syntax.vim b/Auxiliary/cmake-syntax.vim index 973252d..6a888b6 100644 --- a/Auxiliary/cmake-syntax.vim +++ b/Auxiliary/cmake-syntax.vim @@ -15,7 +15,7 @@ if exists("b:current_syntax") endif syn match cmakeEscaped /\(\\\\\|\\"\|\\n\|\\t\)/ contained -syn region cmakeComment start="#" end="$" contains=cmakeTodo +syn region cmakeComment start="#" end="$" contains=cmakeTodo, at Spell syn region cmakeGeneratorExpression start=/$/ \ contained oneline contains=CONTAINED,cmakeTodo,cmakeVariable,cmakeProperty,cmakeGeneratorExpressions syn region cmakeRegistry start=/\[/ end=/]/ ----------------------------------------------------------------------- Summary of changes: Auxiliary/cmake-syntax.vim | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 1 15:04:39 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 1 Aug 2016 15:04:39 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-500-gb1cd292 Message-ID: <20160801190439.0E689F55E7@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via b1cd292335d4d760d2bbd5062e21fdb6d24fcbd8 (commit) via cd7ed47c4ad5b9c2c7539a6f77bbe11a8510a718 (commit) via bca8be583eda435202f7a0eb6e288646ce70570f (commit) via 7decbe8ffb66a1a02b9ffab027f33558fa36873a (commit) via 2b57b139201f7fa1959702db0a8c18482452f903 (commit) via 8ac4e2cfa283d6a27ba11c9ce6e2cea44457b5cb (commit) via 3b3bd880a3de1d6348d746c15b6bc3b32757343a (commit) via 481f8cf1cc73f99d06ed75752715f2f9fbb8f0ba (commit) via ffa44a39c9d7e092f8c86a4648b976ccc64da4d6 (commit) via 29eeb9a8fd9a6417b99e7fbd8b406f72fc83f35f (commit) from 5ec03c93fc92149708b4ec9d19384a015d845f8e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b1cd292335d4d760d2bbd5062e21fdb6d24fcbd8 commit b1cd292335d4d760d2bbd5062e21fdb6d24fcbd8 Merge: 5ec03c9 cd7ed47 Author: Brad King AuthorDate: Mon Aug 1 15:04:37 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 1 15:04:37 2016 -0400 Merge topic 'vim-syntax-updates' cd7ed47c Aux: highlight commands using Function bca8be58 Aux: sort the highlighting list 7decbe8f Aux: highlight CMAKE_{CMAKE,CPACK}_COMMAND variables 2b57b139 Aux: highlight modules using Include 8ac4e2cf Aux: highlight conditiona and repeat commands differently 3b3bd880 Aux: highlight deprecated commands as warnings 481f8cf1 Aux: remove unused highlight links ffa44a39 Aux: highlight Lua-style comments 29eeb9a8 Aux: check spelling in comments ----------------------------------------------------------------------- Summary of changes: Auxiliary/cmake-syntax.vim | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 1 15:04:57 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 1 Aug 2016 15:04:57 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1016-g55ac87c Message-ID: <20160801190457.87841F57B0@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 55ac87c6778b86f37338db13a2acbf052fc7c8e4 (commit) via b1cd292335d4d760d2bbd5062e21fdb6d24fcbd8 (commit) from 7140cb5ba763f473ac0717b4dd080337916259e1 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=55ac87c6778b86f37338db13a2acbf052fc7c8e4 commit 55ac87c6778b86f37338db13a2acbf052fc7c8e4 Merge: 7140cb5 b1cd292 Author: Brad King AuthorDate: Mon Aug 1 15:04:47 2016 -0400 Commit: Brad King CommitDate: Mon Aug 1 15:04:47 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 1 15:13:31 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 1 Aug 2016 15:13:31 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1019-gb76fd38 Message-ID: <20160801191331.BC26DF3CFC@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via b76fd38ba8d4718faa0e0766823bbaefaa3af5c5 (commit) via b8ef638e8d7bccb3109e87770f9ac6a4b3482726 (commit) via ca684ccb467d35cbebf7374746509788a5eb917d (commit) from 55ac87c6778b86f37338db13a2acbf052fc7c8e4 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b76fd38ba8d4718faa0e0766823bbaefaa3af5c5 commit b76fd38ba8d4718faa0e0766823bbaefaa3af5c5 Merge: 55ac87c b8ef638 Author: Brad King AuthorDate: Mon Aug 1 15:13:31 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 1 15:13:31 2016 -0400 Merge topic 'emacs-mode-compilation-warning' into next b8ef638e cmake-model.el: Replace use of obsolete function (since Emacs 24.3). ca684ccb cmake-mode.el: Fix byte-compilation warnings. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b8ef638e8d7bccb3109e87770f9ac6a4b3482726 commit b8ef638e8d7bccb3109e87770f9ac6a4b3482726 Author: Jostein Kj?nigsen AuthorDate: Mon Jul 25 10:13:38 2016 +0200 Commit: Jostein Kj?nigsen CommitDate: Tue Jul 26 14:41:02 2016 +0200 cmake-model.el: Replace use of obsolete function (since Emacs 24.3). diff --git a/Auxiliary/cmake-mode.el b/Auxiliary/cmake-mode.el index b35d369..f29b59b 100644 --- a/Auxiliary/cmake-mode.el +++ b/Auxiliary/cmake-mode.el @@ -271,7 +271,7 @@ optional argument topic will be appended to the argument list." (save-selected-window (select-window (display-buffer buffer 'not-this-window)) (cmake-mode) - (toggle-read-only t)) + (read-only-mode 1)) ) ) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ca684ccb467d35cbebf7374746509788a5eb917d commit ca684ccb467d35cbebf7374746509788a5eb917d Author: Jostein Kj?nigsen AuthorDate: Mon Jul 25 09:56:49 2016 +0200 Commit: Jostein Kj?nigsen CommitDate: Tue Jul 26 14:41:02 2016 +0200 cmake-mode.el: Fix byte-compilation warnings. diff --git a/Auxiliary/cmake-mode.el b/Auxiliary/cmake-mode.el index 20def8b..b35d369 100644 --- a/Auxiliary/cmake-mode.el +++ b/Auxiliary/cmake-mode.el @@ -114,6 +114,14 @@ set the path with these commands: ;------------------------------------------------------------------------------ ;; +;; Indentation increment. +;; +(defcustom cmake-tab-width 2 + "Number of columns to indent cmake blocks" + :type 'integer + :group 'cmake) + +;; ;; Line indentation function. ;; (defun cmake-indent () @@ -225,13 +233,6 @@ the indentation. Otherwise it retains the same position on the line" ;; (defvar cmake-mode-hook nil) -;; -;; Indentation increment. -;; -(defcustom cmake-tab-width 2 - "Number of columns to indent cmake blocks" - :type 'integer) - ;------------------------------------------------------------------------------ ;; For compatibility with Emacs < 24 ----------------------------------------------------------------------- Summary of changes: Auxiliary/cmake-mode.el | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 1 15:14:08 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 1 Aug 2016 15:14:08 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1021-g91237c3 Message-ID: <20160801191408.6C6EFF419E@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 91237c3208e4bccd1f587d639c3540146e6d0505 (commit) via 82388543d2b7984fb98583817a3683f789c84cdd (commit) from b76fd38ba8d4718faa0e0766823bbaefaa3af5c5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=91237c3208e4bccd1f587d639c3540146e6d0505 commit 91237c3208e4bccd1f587d639c3540146e6d0505 Merge: b76fd38 8238854 Author: Brad King AuthorDate: Mon Aug 1 15:14:07 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 1 15:14:07 2016 -0400 Merge topic 'emacs-mode-compilation-warning' into next 82388543 cmake-mode.el: Replace use of obsolete function (since Emacs 24.3). https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=82388543d2b7984fb98583817a3683f789c84cdd commit 82388543d2b7984fb98583817a3683f789c84cdd Author: Jostein Kj?nigsen AuthorDate: Mon Jul 25 10:13:38 2016 +0200 Commit: Brad King CommitDate: Mon Aug 1 15:13:43 2016 -0400 cmake-mode.el: Replace use of obsolete function (since Emacs 24.3). diff --git a/Auxiliary/cmake-mode.el b/Auxiliary/cmake-mode.el index b35d369..f29b59b 100644 --- a/Auxiliary/cmake-mode.el +++ b/Auxiliary/cmake-mode.el @@ -271,7 +271,7 @@ optional argument topic will be appended to the argument list." (save-selected-window (select-window (display-buffer buffer 'not-this-window)) (cmake-mode) - (toggle-read-only t)) + (read-only-mode 1)) ) ) ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 1 15:15:41 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 1 Aug 2016 15:15:41 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-503-g5f99e61 Message-ID: <20160801191541.0A7E1F496E@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 5f99e61cadada755ad8c19ec1f114079c660b400 (commit) via 82388543d2b7984fb98583817a3683f789c84cdd (commit) via ca684ccb467d35cbebf7374746509788a5eb917d (commit) from b1cd292335d4d760d2bbd5062e21fdb6d24fcbd8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5f99e61cadada755ad8c19ec1f114079c660b400 commit 5f99e61cadada755ad8c19ec1f114079c660b400 Merge: b1cd292 8238854 Author: Brad King AuthorDate: Mon Aug 1 15:15:39 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 1 15:15:39 2016 -0400 Merge topic 'emacs-mode-compilation-warning' 82388543 cmake-mode.el: Replace use of obsolete function (since Emacs 24.3). ca684ccb cmake-mode.el: Fix byte-compilation warnings. ----------------------------------------------------------------------- Summary of changes: Auxiliary/cmake-mode.el | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 1 15:16:11 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 1 Aug 2016 15:16:11 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1023-g5b6200e Message-ID: <20160801191611.1C01DF4B7E@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 5b6200ee7c0c1b5930fb8b40f544b9611c43a35e (commit) via 5f99e61cadada755ad8c19ec1f114079c660b400 (commit) from 91237c3208e4bccd1f587d639c3540146e6d0505 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5b6200ee7c0c1b5930fb8b40f544b9611c43a35e commit 5b6200ee7c0c1b5930fb8b40f544b9611c43a35e Merge: 91237c3 5f99e61 Author: Brad King AuthorDate: Mon Aug 1 15:16:03 2016 -0400 Commit: Brad King CommitDate: Mon Aug 1 15:16:03 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 1 15:30:05 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 1 Aug 2016 15:30:05 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1025-g62452bb Message-ID: <20160801193009.AB586F56AE@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 62452bbd410a93493f9d6d5f668a5f4a3062d941 (commit) via bdd9b1c73c8c43e45561a000cb9f5c61349528b7 (commit) from 5b6200ee7c0c1b5930fb8b40f544b9611c43a35e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=62452bbd410a93493f9d6d5f668a5f4a3062d941 commit 62452bbd410a93493f9d6d5f668a5f4a3062d941 Merge: 5b6200e bdd9b1c Author: Brad King AuthorDate: Mon Aug 1 15:30:04 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 1 15:30:04 2016 -0400 Merge topic 'doc-CMAKE_INSTALL_PREFIX-default' into next bdd9b1c7 Help: Fix CMAKE_INSTALL_PREFIX documented default on Windows https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bdd9b1c73c8c43e45561a000cb9f5c61349528b7 commit bdd9b1c73c8c43e45561a000cb9f5c61349528b7 Author: Brad King AuthorDate: Mon Aug 1 15:28:14 2016 -0400 Commit: Brad King CommitDate: Mon Aug 1 15:29:11 2016 -0400 Help: Fix CMAKE_INSTALL_PREFIX documented default on Windows Fixes #16211. diff --git a/Help/variable/CMAKE_INSTALL_PREFIX.rst b/Help/variable/CMAKE_INSTALL_PREFIX.rst index 3f3347f..86f1944 100644 --- a/Help/variable/CMAKE_INSTALL_PREFIX.rst +++ b/Help/variable/CMAKE_INSTALL_PREFIX.rst @@ -5,7 +5,7 @@ Install directory used by :command:`install`. If ``make install`` is invoked or ``INSTALL`` is built, this directory is prepended onto all install directories. This variable defaults to -``/usr/local`` on UNIX and ``c:/Program Files`` on Windows. +``/usr/local`` on UNIX and ``c:/Program Files/${PROJECT_NAME}`` on Windows. On UNIX one can use the ``DESTDIR`` mechanism in order to relocate the whole installation. ``DESTDIR`` means DESTination DIRectory. It is ----------------------------------------------------------------------- Summary of changes: Help/variable/CMAKE_INSTALL_PREFIX.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From kwrobot at kitware.com Tue Aug 2 00:01:07 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Tue, 2 Aug 2016 00:01:07 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-504-g55d9bfa Message-ID: <20160802040107.27CCDF56F1@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 55d9bfa9dd42912432eea3297507187084a7d154 (commit) from 5f99e61cadada755ad8c19ec1f114079c660b400 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=55d9bfa9dd42912432eea3297507187084a7d154 commit 55d9bfa9dd42912432eea3297507187084a7d154 Author: Kitware Robot AuthorDate: Tue Aug 2 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Tue Aug 2 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 8e548e5..f203b3c 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160801) +set(CMake_VERSION_PATCH 20160802) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From nilsgladitz at gmail.com Tue Aug 2 08:10:42 2016 From: nilsgladitz at gmail.com (Nils Gladitz) Date: Tue, 2 Aug 2016 08:10:42 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1028-gc751592 Message-ID: <20160802121042.D65B2B0235@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via c751592abd68d027235597b20bf3ae4143a4a73c (commit) via e29bfbf272dbf4ea5f6a89084ec1f503fcf0e4f7 (commit) via 55d9bfa9dd42912432eea3297507187084a7d154 (commit) from 62452bbd410a93493f9d6d5f668a5f4a3062d941 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c751592abd68d027235597b20bf3ae4143a4a73c commit c751592abd68d027235597b20bf3ae4143a4a73c Merge: 62452bb e29bfbf Author: Nils Gladitz AuthorDate: Tue Aug 2 08:10:41 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 08:10:41 2016 -0400 Merge topic 'wix-root-description' into next e29bfbf2 CPackWIX: Support custom title and description for the root feature 55d9bfa9 CMake Nightly Date Stamp https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e29bfbf272dbf4ea5f6a89084ec1f503fcf0e4f7 commit e29bfbf272dbf4ea5f6a89084ec1f503fcf0e4f7 Author: Michael St?rmer AuthorDate: Wed Jul 20 15:27:01 2016 +0200 Commit: Nils Gladitz CommitDate: Tue Aug 2 14:05:08 2016 +0200 CPackWIX: Support custom title and description for the root feature These can now be specified through the WIX generator specific CPack variables CPACK_WIX_ROOT_FEATURE_TITLE and CPACK_WIX_ROOT_FEATURE_DESCRIPTION. diff --git a/Help/release/dev/wix-root-description.rst b/Help/release/dev/wix-root-description.rst new file mode 100644 index 0000000..24afed2 --- /dev/null +++ b/Help/release/dev/wix-root-description.rst @@ -0,0 +1,7 @@ +wix-root-description +-------------------- + +* The CPack WIX generator now supports + :variable:`CPACK_WIX_ROOT_FEATURE_TITLE` and + :variable:`CPACK_WIX_ROOT_FEATURE_DESCRIPTION` to allow the specification + of a custom title and description for the root feature element. diff --git a/Modules/CPackWIX.cmake b/Modules/CPackWIX.cmake index 3c90561..10926c0 100644 --- a/Modules/CPackWIX.cmake +++ b/Modules/CPackWIX.cmake @@ -237,6 +237,17 @@ # * ARPURLUPDATEINFO - Update information URL # * ARPHELPTELEPHONE - Help and support telephone number # * ARPSIZE - Size (in kilobytes) of the application +# +# .. variable:: CPACK_WIX_ROOT_FEATURE_TITLE +# +# Sets the name of the root install feature in the WIX installer. Same as +# CPACK_COMPONENT__DISPLAY_NAME for components. +# +# .. variable:: CPACK_WIX_ROOT_FEATURE_DESCRIPTION +# +# Sets the description of the root install feature in the WIX installer. Same as +# CPACK_COMPONENT__DESCRIPTION for components. +# #============================================================================= # Copyright 2014-2015 Kitware, Inc. diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index 97216c3..3ecc14d 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -464,7 +464,14 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() return false; } - featureDefinitions.AddAttribute("Title", cpackPackageName); + std::string featureTitle = cpackPackageName; + if (const char* title = GetOption("CPACK_WIX_ROOT_FEATURE_TITLE")) { + featureTitle = title; + } + featureDefinitions.AddAttribute("Title", featureTitle); + if (const char* desc = GetOption("CPACK_WIX_ROOT_FEATURE_DESCRIPTION")) { + featureDefinitions.AddAttribute("Description", desc); + } featureDefinitions.AddAttribute("Level", "1"); this->Patch->ApplyFragment("#PRODUCTFEATURE", featureDefinitions); ----------------------------------------------------------------------- Summary of changes: Help/release/dev/wix-root-description.rst | 7 +++++++ Modules/CPackWIX.cmake | 11 +++++++++++ Source/CMakeVersion.cmake | 2 +- Source/CPack/WiX/cmCPackWIXGenerator.cxx | 9 ++++++++- 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 Help/release/dev/wix-root-description.rst hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 2 09:11:54 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 2 Aug 2016 09:11:54 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-506-gfd59f9a Message-ID: <20160802131154.543B4E8A40@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via fd59f9ad519c1c311c54569133797d9061e90558 (commit) via bdd9b1c73c8c43e45561a000cb9f5c61349528b7 (commit) from 55d9bfa9dd42912432eea3297507187084a7d154 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=fd59f9ad519c1c311c54569133797d9061e90558 commit fd59f9ad519c1c311c54569133797d9061e90558 Merge: 55d9bfa bdd9b1c Author: Brad King AuthorDate: Tue Aug 2 09:11:52 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 09:11:52 2016 -0400 Merge topic 'doc-CMAKE_INSTALL_PREFIX-default' bdd9b1c7 Help: Fix CMAKE_INSTALL_PREFIX documented default on Windows ----------------------------------------------------------------------- Summary of changes: Help/variable/CMAKE_INSTALL_PREFIX.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 2 09:12:11 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 2 Aug 2016 09:12:11 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1030-g18d4165 Message-ID: <20160802131211.A99ADE78E1@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 18d4165a60d8f36d32b0eab09306d84a4cce4b0b (commit) via fd59f9ad519c1c311c54569133797d9061e90558 (commit) from c751592abd68d027235597b20bf3ae4143a4a73c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=18d4165a60d8f36d32b0eab09306d84a4cce4b0b commit 18d4165a60d8f36d32b0eab09306d84a4cce4b0b Merge: c751592 fd59f9a Author: Brad King AuthorDate: Tue Aug 2 09:12:04 2016 -0400 Commit: Brad King CommitDate: Tue Aug 2 09:12:04 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 2 09:20:39 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 2 Aug 2016 09:20:39 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1032-g49fc180 Message-ID: <20160802132040.07DD9F4E2C@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 49fc180cabb53ac734b335cdf0d05c22192690c8 (commit) via f4e979b126e41384b14f0d5ff8b41d81b6f41a00 (commit) from 18d4165a60d8f36d32b0eab09306d84a4cce4b0b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=49fc180cabb53ac734b335cdf0d05c22192690c8 commit 49fc180cabb53ac734b335cdf0d05c22192690c8 Merge: 18d4165 f4e979b Author: Brad King AuthorDate: Tue Aug 2 09:20:39 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 09:20:39 2016 -0400 Merge topic 'FindCUDA-no-windows-librt' into next f4e979b1 FindCUDA: Do not look for librt on Windows https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f4e979b126e41384b14f0d5ff8b41d81b6f41a00 commit f4e979b126e41384b14f0d5ff8b41d81b6f41a00 Author: Stephen Sorley AuthorDate: Fri Jul 22 17:53:24 2016 -0400 Commit: Brad King CommitDate: Tue Aug 2 09:15:22 2016 -0400 FindCUDA: Do not look for librt on Windows Otherwise an incorrect warning appears when compiling with CUDA SDK 6.5 or older and CUDA_USE_STATIC_CUDA_RUNTIME is true. diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake index 6d9b833..354ee6e 100644 --- a/Modules/FindCUDA.cmake +++ b/Modules/FindCUDA.cmake @@ -817,7 +817,7 @@ if(CUDA_USE_STATIC_CUDA_RUNTIME) unset(CMAKE_THREAD_PREFER_PTHREAD) endif() endif() - if (NOT APPLE AND CUDA_VERSION VERSION_LESS "7.0") + if (UNIX AND NOT APPLE AND CUDA_VERSION VERSION_LESS "7.0") # Before CUDA 7.0, there was librt that has things such as, clock_gettime, shm_open, and shm_unlink. find_library(CUDA_rt_LIBRARY rt) if (NOT CUDA_rt_LIBRARY) ----------------------------------------------------------------------- Summary of changes: Modules/FindCUDA.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 2 09:22:53 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 2 Aug 2016 09:22:53 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1035-g174049d Message-ID: <20160802132253.6806BF4F81@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 174049de9c674d86052f6f091f6dfe1c9259266d (commit) via 35995fa6b5872b58f086d16b16ca90d7d259d9b0 (commit) via 6bc3073e23af70bde3e8a7659aa51a784deeec9c (commit) from 49fc180cabb53ac734b335cdf0d05c22192690c8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=174049de9c674d86052f6f091f6dfe1c9259266d commit 174049de9c674d86052f6f091f6dfe1c9259266d Merge: 49fc180 35995fa Author: Brad King AuthorDate: Tue Aug 2 09:22:52 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 09:22:52 2016 -0400 Merge topic 'update-kwsys' into next 35995fa6 Merge branch 'upstream-KWSys' into update-kwsys 6bc3073e KWSys 2016-08-01 (560bcdbb) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=35995fa6b5872b58f086d16b16ca90d7d259d9b0 commit 35995fa6b5872b58f086d16b16ca90d7d259d9b0 Merge: fd59f9a 6bc3073 Author: Brad King AuthorDate: Tue Aug 2 09:21:52 2016 -0400 Commit: Brad King CommitDate: Tue Aug 2 09:21:52 2016 -0400 Merge branch 'upstream-KWSys' into update-kwsys * upstream-KWSys: KWSys 2016-08-01 (560bcdbb) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6bc3073e23af70bde3e8a7659aa51a784deeec9c commit 6bc3073e23af70bde3e8a7659aa51a784deeec9c Author: KWSys Upstream AuthorDate: Mon Aug 1 15:20:05 2016 -0400 Commit: Brad King CommitDate: Tue Aug 2 09:21:31 2016 -0400 KWSys 2016-08-01 (560bcdbb) Code extracted from: http://public.kitware.com/KWSys.git at commit 560bcdbb972cbf4c7ea77010363c652b697b9933 (master). Upstream Shortlog ----------------- Brad King (1): 560bcdbb SystemTools: Factor out common `const char* GetEnv()` private implementation James Johnston (1): 1c147abb Directory: Use Windows API wherever possible and port to Embarcadero diff --git a/Directory.cxx b/Directory.cxx index c549792..15480e1 100644 --- a/Directory.cxx +++ b/Directory.cxx @@ -84,9 +84,9 @@ void Directory::Clear() } // namespace KWSYS_NAMESPACE -// First microsoft compilers +// First Windows platforms -#if defined(_MSC_VER) || defined(__WATCOMC__) +#if defined(_WIN32) && !defined(__CYGWIN__) #include #include #include @@ -97,15 +97,25 @@ void Directory::Clear() #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 _MSC_VER < 1300 +#if (defined(_MSC_VER) && _MSC_VER < 1300) || defined(__BORLANDC__) + // Older Visual C++ and Embarcadero compilers. long srchHandle; -#else +#else // Newer Visual C++ intptr_t srchHandle; #endif char* buf; @@ -132,7 +142,7 @@ bool Directory::Load(const std::string& name) 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); + srchHandle = _wfindfirst_func((wchar_t*)Encoding::ToWide(buf).c_str(), &data); delete [] buf; if ( srchHandle == -1 ) @@ -145,16 +155,17 @@ bool Directory::Load(const std::string& name) { this->Internal->Files.push_back(Encoding::ToNarrow(data.name)); } - while ( _wfindnext(srchHandle, &data) != -1 ); + while ( _wfindnext_func(srchHandle, &data) != -1 ); this->Internal->Path = name; return _findclose(srchHandle) != -1; } unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) { -#if _MSC_VER < 1300 +#if (defined(_MSC_VER) && _MSC_VER < 1300) || defined(__BORLANDC__) + // Older Visual C++ and Embarcadero compilers. long srchHandle; -#else +#else // Newer Visual C++ intptr_t srchHandle; #endif char* buf; @@ -172,7 +183,7 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) 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); + srchHandle = _wfindfirst_func((wchar_t*)Encoding::ToWide(buf).c_str(), &data); delete [] buf; if ( srchHandle == -1 ) @@ -186,7 +197,7 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) { count++; } - while ( _wfindnext(srchHandle, &data) != -1 ); + while ( _wfindnext_func(srchHandle, &data) != -1 ); _findclose(srchHandle); return count; } diff --git a/SystemTools.cxx b/SystemTools.cxx index 0526372..9b56db0 100644 --- a/SystemTools.cxx +++ b/SystemTools.cxx @@ -523,7 +523,7 @@ void SystemTools::GetPath(std::vector& path, const char* env) } } -const char* SystemTools::GetEnv(const char* key) +const char* SystemTools::GetEnvImpl(const char* key) { const char *v = 0; #if defined(_WIN32) @@ -540,9 +540,14 @@ const char* SystemTools::GetEnv(const char* key) return v; } +const char* SystemTools::GetEnv(const char* key) +{ + return SystemTools::GetEnvImpl(key); +} + const char* SystemTools::GetEnv(const std::string& key) { - return SystemTools::GetEnv(key.c_str()); + return SystemTools::GetEnvImpl(key.c_str()); } bool SystemTools::GetEnv(const char* key, std::string& result) diff --git a/SystemTools.hxx.in b/SystemTools.hxx.in index 8f01e75..aa1bf1b 100644 --- a/SystemTools.hxx.in +++ b/SystemTools.hxx.in @@ -984,6 +984,7 @@ private: std::vector(), bool no_system_path = false); + static const char* GetEnvImpl(const char* key); /** * Path translation table from dir to refdir ----------------------------------------------------------------------- Summary of changes: Source/kwsys/Directory.cxx | 31 +++++++++++++++++++++---------- Source/kwsys/SystemTools.cxx | 9 +++++++-- Source/kwsys/SystemTools.hxx.in | 1 + 3 files changed, 29 insertions(+), 12 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 2 09:27:17 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 2 Aug 2016 09:27:17 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1037-g7b3e38b Message-ID: <20160802132717.37290F50BE@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 7b3e38b04e7abd7144b33938f839c61aa92e6660 (commit) via 85e0314201005c923420eb650a9629e38356b77a (commit) from 174049de9c674d86052f6f091f6dfe1c9259266d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7b3e38b04e7abd7144b33938f839c61aa92e6660 commit 7b3e38b04e7abd7144b33938f839c61aa92e6660 Merge: 174049d 85e0314 Author: Brad King AuthorDate: Tue Aug 2 09:27:16 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 09:27:16 2016 -0400 Merge topic 'gcc-fvisibility-version' into next 85e03142 GNU: Use -fvisibility on GCC 4.0 and 4.1 too https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=85e0314201005c923420eb650a9629e38356b77a commit 85e0314201005c923420eb650a9629e38356b77a Author: Brad King AuthorDate: Tue Aug 2 09:24:54 2016 -0400 Commit: Brad King CommitDate: Tue Aug 2 09:24:54 2016 -0400 GNU: Use -fvisibility on GCC 4.0 and 4.1 too This flag is needed for the `_VISIBILITY_PRESET` target property. It has been supported since GCC 4.0, not 4.2 as we previously recorded. Fixes #16222. diff --git a/Modules/Compiler/GNU.cmake b/Modules/Compiler/GNU.cmake index 34d4eaf..4d2fe5b 100644 --- a/Modules/Compiler/GNU.cmake +++ b/Modules/Compiler/GNU.cmake @@ -25,7 +25,7 @@ macro(__compiler_gnu lang) if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.4) set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE") endif() - if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 4.2) + if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 4.0) set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=") endif() set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC") ----------------------------------------------------------------------- Summary of changes: Modules/Compiler/GNU.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 2 10:11:32 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 2 Aug 2016 10:11:32 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1040-g567b83a Message-ID: <20160802141132.E37E0F2BC2@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 567b83acbae9f986bbbe0d85770810be4b88836a (commit) via 56539d89da4f8f0834a17faee14ef88f3b232048 (commit) via 16a3a73508e8109e453e35288c37fe545a8ab59e (commit) from 7b3e38b04e7abd7144b33938f839c61aa92e6660 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=567b83acbae9f986bbbe0d85770810be4b88836a commit 567b83acbae9f986bbbe0d85770810be4b88836a Merge: 7b3e38b 56539d8 Author: Brad King AuthorDate: Tue Aug 2 10:11:32 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 10:11:32 2016 -0400 Merge topic 'port-to-sco' into next 56539d89 SCO_SV: Enable so filename versioning 16a3a735 cmELF: Port to SCO OpenServer 5.0.7/3.2 https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=56539d89da4f8f0834a17faee14ef88f3b232048 commit 56539d89da4f8f0834a17faee14ef88f3b232048 Author: Patrick Welche AuthorDate: Thu Jul 28 17:26:10 2016 +0100 Commit: Brad King CommitDate: Tue Aug 2 10:09:52 2016 -0400 SCO_SV: Enable so filename versioning Take changes used by pkgsrc [1]: * so filename versioning requires CMAKE_SHARED_LIBRARY_SONAME_C_FLAG. [1] http://cdn.netbsd.org/pub/pkgsrc/current/pkgsrc/devel/cmake/patches/ diff --git a/Modules/Platform/SCO_SV.cmake b/Modules/Platform/SCO_SV.cmake index ddd9600..1cb4b38 100644 --- a/Modules/Platform/SCO_SV.cmake +++ b/Modules/Platform/SCO_SV.cmake @@ -1,2 +1,3 @@ set(CMAKE_DL_LIBS "") +set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-h,") include(Platform/UnixPaths) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=16a3a73508e8109e453e35288c37fe545a8ab59e commit 16a3a73508e8109e453e35288c37fe545a8ab59e Author: Patrick Welche AuthorDate: Thu Jul 28 17:26:10 2016 +0100 Commit: Brad King CommitDate: Tue Aug 2 10:04:31 2016 -0400 cmELF: Port to SCO OpenServer 5.0.7/3.2 Take changes used by pkgsrc [1]: * SCO OpenServer 5.0.7/3.2 does not support 64-bit ELF. [1] http://cdn.netbsd.org/pub/pkgsrc/current/pkgsrc/devel/cmake/patches/ diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx index 15755cb..266b786 100644 --- a/Source/cmELF.cxx +++ b/Source/cmELF.cxx @@ -46,6 +46,9 @@ typedef struct Elf32_Rela Elf32_Rela; #if defined(__sun) #include // For dynamic section information #endif +#ifdef _SCO_DS +#include // For DT_SONAME etc. +#endif // Low-level byte swapping implementation. template @@ -214,6 +217,7 @@ struct cmELFTypes32 }; // Configure the implementation template for 64-bit ELF files. +#ifndef _SCO_DS struct cmELFTypes64 { typedef Elf64_Ehdr ELF_Ehdr; @@ -223,6 +227,7 @@ struct cmELFTypes64 typedef KWIML_INT_uint64_t tagtype; static const char* GetName() { return "64-bit"; } }; +#endif // Parser implementation template. template @@ -800,10 +805,14 @@ cmELF::cmELF(const char* fname) if (ident[EI_CLASS] == ELFCLASS32) { // 32-bit ELF this->Internal = new cmELFInternalImpl(this, fin, order); - } else if (ident[EI_CLASS] == ELFCLASS64) { + } +#ifndef _SCO_DS + else if (ident[EI_CLASS] == ELFCLASS64) { // 64-bit ELF this->Internal = new cmELFInternalImpl(this, fin, order); - } else { + } +#endif + else { this->ErrorMessage = "ELF file class is not 32-bit or 64-bit."; return; } ----------------------------------------------------------------------- Summary of changes: Modules/Platform/SCO_SV.cmake | 1 + Source/cmELF.cxx | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 2 10:17:50 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 2 Aug 2016 10:17:50 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1042-ge6bfb7d Message-ID: <20160802141750.133E3F4357@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via e6bfb7d0d6a053aeb105a2480687519095b35b70 (commit) via 52aecc0c382384d5bea3c18d7894e80bc573d8d7 (commit) from 567b83acbae9f986bbbe0d85770810be4b88836a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e6bfb7d0d6a053aeb105a2480687519095b35b70 commit e6bfb7d0d6a053aeb105a2480687519095b35b70 Merge: 567b83a 52aecc0 Author: Brad King AuthorDate: Tue Aug 2 10:17:49 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 10:17:49 2016 -0400 Merge topic 'ExternalProject-no-DS_Store' into next 52aecc0c ExternalProject: Ignore macOS .DS_Store files in tarball extraction https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=52aecc0c382384d5bea3c18d7894e80bc573d8d7 commit 52aecc0c382384d5bea3c18d7894e80bc573d8d7 Author: Brad King AuthorDate: Mon Aug 1 11:49:17 2016 -0400 Commit: Brad King CommitDate: Tue Aug 2 10:14:26 2016 -0400 ExternalProject: Ignore macOS .DS_Store files in tarball extraction Do not consider a top-level `.DS_Store` file when deciding whether a tarball contains exactly one directory whose contents should be used as the resulting top-level of the extraction. Fixes #16218. Suggested-by: Patrice Kouame diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index 7e179aa..4929848 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -993,6 +993,7 @@ endif() # message(STATUS \"extracting... [analysis]\") file(GLOB contents \"\${ut_dir}/*\") +list(REMOVE_ITEM contents \"\${ut_dir}/.DS_Store\") list(LENGTH contents n) if(NOT n EQUAL 1 OR NOT IS_DIRECTORY \"\${contents}\") set(contents \"\${ut_dir}\") ----------------------------------------------------------------------- Summary of changes: Modules/ExternalProject.cmake | 1 + 1 file changed, 1 insertion(+) hooks/post-receive -- CMake From chuck.atkins at kitware.com Tue Aug 2 10:42:09 2016 From: chuck.atkins at kitware.com (Chuck Atkins) Date: Tue, 2 Aug 2016 10:42:09 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1044-gdc1dbed Message-ID: <20160802144209.4EDC0F333C@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via dc1dbedc733126da4ed0fff03cefab71b0692d22 (commit) via 8eb0b56c2ace0f005cba436268337f509e06033f (commit) from e6bfb7d0d6a053aeb105a2480687519095b35b70 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=dc1dbedc733126da4ed0fff03cefab71b0692d22 commit dc1dbedc733126da4ed0fff03cefab71b0692d22 Merge: e6bfb7d 8eb0b56 Author: Chuck Atkins AuthorDate: Tue Aug 2 10:42:08 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 10:42:08 2016 -0400 Merge topic 'fix-findhdf5-definitions' into next 8eb0b56c FindHDF5: Make sure compile definition vars keep the -D flag https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8eb0b56c2ace0f005cba436268337f509e06033f commit 8eb0b56c2ace0f005cba436268337f509e06033f Author: Chuck Atkins AuthorDate: Tue Aug 2 10:34:51 2016 -0400 Commit: Chuck Atkins CommitDate: Tue Aug 2 10:34:51 2016 -0400 FindHDF5: Make sure compile definition vars keep the -D flag diff --git a/Modules/FindHDF5.cmake b/Modules/FindHDF5.cmake index 50e1892..a898386 100644 --- a/Modules/FindHDF5.cmake +++ b/Modules/FindHDF5.cmake @@ -332,7 +332,7 @@ macro( _HDF5_parse_compile_line set( RE " -D([^ ]*)") string( REGEX MATCHALL "${RE}" definition_flags "${${compile_line_var}}" ) foreach( DEF IN LISTS definition_flags ) - string( REGEX REPLACE "${RE}" "\\1" DEF "${DEF}" ) + string( STRIP "${DEF}" DEF ) list( APPEND ${definitions} ${DEF} ) endforeach() ----------------------------------------------------------------------- Summary of changes: Modules/FindHDF5.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 2 10:42:50 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 2 Aug 2016 10:42:50 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1046-gd30c1c1 Message-ID: <20160802144250.8277FF34F9@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via d30c1c1e65d3a3cb2599c2b161600f196c059b49 (commit) via 9970cdcb59e5d02da68c195799146f9bc91816e7 (commit) from dc1dbedc733126da4ed0fff03cefab71b0692d22 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d30c1c1e65d3a3cb2599c2b161600f196c059b49 commit d30c1c1e65d3a3cb2599c2b161600f196c059b49 Merge: dc1dbed 9970cdc Author: Brad King AuthorDate: Tue Aug 2 10:42:49 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 10:42:49 2016 -0400 Merge topic 'CMakeFindFrameworks-custom-locations' into next 9970cdcb CMakeFindFrameworks: Allow custom framework locations https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9970cdcb59e5d02da68c195799146f9bc91816e7 commit 9970cdcb59e5d02da68c195799146f9bc91816e7 Author: David Keller AuthorDate: Sat Jul 30 16:48:53 2016 +0200 Commit: Brad King CommitDate: Tue Aug 2 10:41:40 2016 -0400 CMakeFindFrameworks: Allow custom framework locations Read a variable to get non-standard locations to be searched, e.g. brew, port. Signed-off-by: David Keller diff --git a/Modules/CMakeFindFrameworks.cmake b/Modules/CMakeFindFrameworks.cmake index 6a8bcd4..80eb003 100644 --- a/Modules/CMakeFindFrameworks.cmake +++ b/Modules/CMakeFindFrameworks.cmake @@ -3,6 +3,10 @@ # ------------------- # # helper module to find OSX frameworks +# +# This module reads hints about search locations from variables:: +# +# CMAKE_FIND_FRAMEWORK_EXTRA_LOCATIONS - Extra directories #============================================================================= # Copyright 2003-2009 Kitware, Inc. @@ -24,9 +28,11 @@ if(NOT CMAKE_FIND_FRAMEWORKS_INCLUDED) if(APPLE) foreach(dir ~/Library/Frameworks/${fwk}.framework + /usr/local/Frameworks/${fwk}.framework /Library/Frameworks/${fwk}.framework /System/Library/Frameworks/${fwk}.framework - /Network/Library/Frameworks/${fwk}.framework) + /Network/Library/Frameworks/${fwk}.framework + ${CMAKE_FIND_FRAMEWORK_EXTRA_LOCATIONS}) if(EXISTS ${dir}) set(${fwk}_FRAMEWORKS ${${fwk}_FRAMEWORKS} ${dir}) endif() ----------------------------------------------------------------------- Summary of changes: Modules/CMakeFindFrameworks.cmake | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 2 10:50:57 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 2 Aug 2016 10:50:57 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1048-gc6e3049 Message-ID: <20160802145057.5AA1BF4770@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via c6e3049340f37d3a8feb19afc184e335e41fa70e (commit) via 5790d9b6f5ae0b5bb8b0f2e4ec630a690b4b0301 (commit) from d30c1c1e65d3a3cb2599c2b161600f196c059b49 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c6e3049340f37d3a8feb19afc184e335e41fa70e commit c6e3049340f37d3a8feb19afc184e335e41fa70e Merge: d30c1c1 5790d9b Author: Brad King AuthorDate: Tue Aug 2 10:50:56 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 10:50:56 2016 -0400 Merge topic 'FindProtobuf-restore-PROTOBUF_IMPORT_DIRS' into next 5790d9b6 FindProtobuf: Restore support for PROTOBUF_IMPORT_DIRS https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5790d9b6f5ae0b5bb8b0f2e4ec630a690b4b0301 commit 5790d9b6f5ae0b5bb8b0f2e4ec630a690b4b0301 Author: Konstantin Sinitsyn AuthorDate: Fri Jul 29 20:10:04 2016 -0700 Commit: Brad King CommitDate: Tue Aug 2 10:50:24 2016 -0400 FindProtobuf: Restore support for PROTOBUF_IMPORT_DIRS Support was accidentally dropped by commit v3.6.0-rc1~273^2 (FindProtobuf: Rename variables to match case of module name, 2016-03-01). diff --git a/Modules/FindProtobuf.cmake b/Modules/FindProtobuf.cmake index 8042073..2807bb9 100644 --- a/Modules/FindProtobuf.cmake +++ b/Modules/FindProtobuf.cmake @@ -129,6 +129,10 @@ function(PROTOBUF_GENERATE_CPP SRCS HDRS) set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR}) endif() + if(DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS) + set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}") + endif() + if(DEFINED Protobuf_IMPORT_DIRS) foreach(DIR ${Protobuf_IMPORT_DIRS}) get_filename_component(ABS_PATH ${DIR} ABSOLUTE) @@ -183,6 +187,10 @@ function(PROTOBUF_GENERATE_PYTHON SRCS) set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR}) endif() + if(DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS) + set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}") + endif() + if(DEFINED Protobuf_IMPORT_DIRS) foreach(DIR ${Protobuf_IMPORT_DIRS}) get_filename_component(ABS_PATH ${DIR} ABSOLUTE) ----------------------------------------------------------------------- Summary of changes: Modules/FindProtobuf.cmake | 8 ++++++++ 1 file changed, 8 insertions(+) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 2 11:51:07 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 2 Aug 2016 11:51:07 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1050-g972a121 Message-ID: <20160802155107.3D618F46C3@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 972a121a3cac7a461f40c531e9a107af677b2d42 (commit) via d867f8a05a3fd748fbf360de2baf96f8136c5a27 (commit) from c6e3049340f37d3a8feb19afc184e335e41fa70e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=972a121a3cac7a461f40c531e9a107af677b2d42 commit 972a121a3cac7a461f40c531e9a107af677b2d42 Merge: c6e3049 d867f8a Author: Brad King AuthorDate: Tue Aug 2 11:51:06 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 11:51:06 2016 -0400 Merge topic 'ninja-full-path' into next d867f8a0 Ninja: Use full path for all source files https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d867f8a05a3fd748fbf360de2baf96f8136c5a27 commit d867f8a05a3fd748fbf360de2baf96f8136c5a27 Author: Chaoren Lin AuthorDate: Fri Jul 29 14:44:52 2016 -0700 Commit: Brad King CommitDate: Tue Aug 2 11:48:59 2016 -0400 Ninja: Use full path for all source files This is consistent with the behavior of the Makefile generators. Relative paths are difficult for an IDE to parse the output of a build error. diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 855a243..7849c5e 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -529,8 +529,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( cmSourceFile const* source, bool writeOrderDependsTargetForTarget) { std::string const language = source->GetLanguage(); - std::string const sourceFileName = - language == "RC" ? source->GetFullPath() : this->GetSourceFilePath(source); + std::string const sourceFileName = source->GetFullPath(); std::string const objectDir = this->ConvertToNinjaPath(this->GeneratorTarget->GetSupportDirectory()); std::string const objectFileName = ----------------------------------------------------------------------- Summary of changes: Source/cmNinjaTargetGenerator.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 2 13:29:55 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 2 Aug 2016 13:29:55 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1052-g9587f55 Message-ID: <20160802172955.2D956F4EB9@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 9587f55249c7f5c0f1dff25f0181f1e8427448a9 (commit) via db8d5405a0bb2fe72d87aab7c984be3cd7386368 (commit) from 972a121a3cac7a461f40c531e9a107af677b2d42 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9587f55249c7f5c0f1dff25f0181f1e8427448a9 commit 9587f55249c7f5c0f1dff25f0181f1e8427448a9 Merge: 972a121 db8d540 Author: Brad King AuthorDate: Tue Aug 2 13:29:54 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 13:29:54 2016 -0400 Merge topic 'ninja-full-path' into next db8d5405 Revert "Ninja: Use full path for all source files" https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=db8d5405a0bb2fe72d87aab7c984be3cd7386368 commit db8d5405a0bb2fe72d87aab7c984be3cd7386368 Author: Brad King AuthorDate: Tue Aug 2 13:29:26 2016 -0400 Commit: Brad King CommitDate: Tue Aug 2 13:29:36 2016 -0400 Revert "Ninja: Use full path for all source files" This reverts commit d867f8a05a3fd748fbf360de2baf96f8136c5a27. It causes the Qt*Autogen tests to fail. diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 7849c5e..855a243 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -529,7 +529,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( cmSourceFile const* source, bool writeOrderDependsTargetForTarget) { std::string const language = source->GetLanguage(); - std::string const sourceFileName = source->GetFullPath(); + std::string const sourceFileName = + language == "RC" ? source->GetFullPath() : this->GetSourceFilePath(source); std::string const objectDir = this->ConvertToNinjaPath(this->GeneratorTarget->GetSupportDirectory()); std::string const objectFileName = ----------------------------------------------------------------------- Summary of changes: Source/cmNinjaTargetGenerator.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 2 14:28:17 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 2 Aug 2016 14:28:17 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1055-gbfefab9 Message-ID: <20160802182817.763F1F4F3A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via bfefab9fe5a3d517d4aadd02ecde2b064c438fb4 (commit) via 034caa27f1e377ea44a613bc2851a172d9e2afbb (commit) via bc44627b671c48e58dd835115baddb62352f40ab (commit) from 9587f55249c7f5c0f1dff25f0181f1e8427448a9 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bfefab9fe5a3d517d4aadd02ecde2b064c438fb4 commit bfefab9fe5a3d517d4aadd02ecde2b064c438fb4 Merge: 9587f55 034caa2 Author: Brad King AuthorDate: Tue Aug 2 14:28:16 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 14:28:16 2016 -0400 Merge topic 'extra-generator-factories' into next 034caa27 Report more information about extra generators in generator factories bc44627b Refactor extra generator registration to use factories https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=034caa27f1e377ea44a613bc2851a172d9e2afbb commit 034caa27f1e377ea44a613bc2851a172d9e2afbb Author: Tobias Hunger AuthorDate: Thu Jul 21 13:24:11 2016 +0200 Commit: Brad King CommitDate: Tue Aug 2 14:23:20 2016 -0400 Report more information about extra generators in generator factories diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 8cc7ac5..fb0fac1 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -824,6 +824,7 @@ void cmake::GetRegisteredGenerators(std::vector& generators) info.supportsToolset = (*i)->SupportsToolset(); info.supportsPlatform = (*i)->SupportsPlatform(); info.name = names[j]; + info.baseName = names[j]; info.isAlias = false; generators.push_back(info); } @@ -840,6 +841,8 @@ void cmake::GetRegisteredGenerators(std::vector& generators) GeneratorInfo info; info.name = cmExternalMakefileProjectGenerator::CreateFullGeneratorName( (*i)->GetName(), *gen); + info.baseName = *gen; + info.extraName = (*i)->GetName(); info.supportsPlatform = false; info.supportsToolset = false; info.isAlias = false; @@ -849,6 +852,10 @@ void cmake::GetRegisteredGenerators(std::vector& generators) a != (*i)->Aliases.end(); ++a) { GeneratorInfo info; info.name = *a; + if (!genList.empty()) { + info.baseName = genList.at(0); + } + info.extraName = (*i)->GetName(); info.supportsPlatform = false; info.supportsToolset = false; info.isAlias = true; diff --git a/Source/cmake.h b/Source/cmake.h index 0fd2d31..304a15d 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -103,6 +103,8 @@ public: struct GeneratorInfo { std::string name; + std::string baseName; + std::string extraName; bool supportsToolset; bool supportsPlatform; bool isAlias; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bc44627b671c48e58dd835115baddb62352f40ab commit bc44627b671c48e58dd835115baddb62352f40ab Author: Tobias Hunger AuthorDate: Wed Jul 20 18:28:39 2016 +0200 Commit: Brad King CommitDate: Tue Aug 2 14:10:58 2016 -0400 Refactor extra generator registration to use factories This will allow additional information about the availability and capabilities of extra generators to be queried without actually creating them. diff --git a/Source/cmExternalMakefileProjectGenerator.cxx b/Source/cmExternalMakefileProjectGenerator.cxx index 0e42d75..a527e50 100644 --- a/Source/cmExternalMakefileProjectGenerator.cxx +++ b/Source/cmExternalMakefileProjectGenerator.cxx @@ -33,28 +33,37 @@ std::string cmExternalMakefileProjectGenerator::CreateFullGeneratorName( return fullName; } -std::string cmExternalMakefileProjectGenerator::GetGlobalGeneratorName( - const std::string& fullName) +cmExternalMakefileProjectGeneratorFactory:: + cmExternalMakefileProjectGeneratorFactory(const std::string& n, + const std::string& doc) + : Name(n) + , Documentation(doc) { - // at least one global generator must be supported - assert(!this->SupportedGlobalGenerators.empty()); +} - if (fullName.empty()) { - return ""; - } +cmExternalMakefileProjectGeneratorFactory:: + ~cmExternalMakefileProjectGeneratorFactory() +{ +} - // if we get only the short name, take the first global generator as default - if (fullName == this->GetName()) { - return this->SupportedGlobalGenerators[0]; - } +std::string cmExternalMakefileProjectGeneratorFactory::GetName() const +{ + return this->Name; +} - // otherwise search for the matching global generator - for (std::vector::const_iterator it = - this->SupportedGlobalGenerators.begin(); - it != this->SupportedGlobalGenerators.end(); ++it) { - if (this->CreateFullGeneratorName(*it, this->GetName()) == fullName) { - return *it; - } - } - return ""; +std::string cmExternalMakefileProjectGeneratorFactory::GetDocumentation() const +{ + return this->Documentation; +} + +std::vector +cmExternalMakefileProjectGeneratorFactory::GetSupportedGlobalGenerators() const +{ + return this->SupportedGlobalGenerators; +} + +void cmExternalMakefileProjectGeneratorFactory::AddSupportedGlobalGenerator( + const std::string& base) +{ + this->SupportedGlobalGenerators.push_back(base); } diff --git a/Source/cmExternalMakefileProjectGenerator.h b/Source/cmExternalMakefileProjectGenerator.h index 5d4d54d..6ae5533 100644 --- a/Source/cmExternalMakefileProjectGenerator.h +++ b/Source/cmExternalMakefileProjectGenerator.h @@ -35,11 +35,6 @@ class cmExternalMakefileProjectGenerator public: virtual ~cmExternalMakefileProjectGenerator() {} - ///! Get the name for this generator. - virtual std::string GetName() const = 0; - /** Get the documentation entry for this generator. */ - virtual void GetDocumentation(cmDocumentationEntry& entry, - const std::string& fullName) const = 0; virtual void EnableLanguage(std::vector const& languages, cmMakefile*, bool optional); @@ -55,8 +50,6 @@ public: return this->SupportedGlobalGenerators; } - ///! Get the name of the global generator for the given full name - std::string GetGlobalGeneratorName(const std::string& fullName); /** Create a full name from the given global generator name and the * extra generator name */ @@ -66,11 +59,59 @@ public: ///! Generate the project files, the Makefiles have already been generated virtual void Generate() = 0; + void SetName(const std::string& n) { Name = n; } + std::string GetName() const { return Name; } + protected: ///! Contains the names of the global generators support by this generator. std::vector SupportedGlobalGenerators; ///! the global generator which creates the makefiles const cmGlobalGenerator* GlobalGenerator; + + std::string Name; +}; + +class cmExternalMakefileProjectGeneratorFactory +{ +public: + cmExternalMakefileProjectGeneratorFactory(const std::string& n, + const std::string& doc); + virtual ~cmExternalMakefileProjectGeneratorFactory(); + + std::string GetName() const; + std::string GetDocumentation() const; + std::vector GetSupportedGlobalGenerators() const; + std::vector Aliases; + + virtual cmExternalMakefileProjectGenerator* + CreateExternalMakefileProjectGenerator() const = 0; + + void AddSupportedGlobalGenerator(const std::string& base); + +private: + std::string Name; + std::string Documentation; + std::vector SupportedGlobalGenerators; +}; + +template +class cmExternalMakefileProjectGeneratorSimpleFactory + : public cmExternalMakefileProjectGeneratorFactory +{ +public: + cmExternalMakefileProjectGeneratorSimpleFactory(const std::string& n, + const std::string& doc) + : cmExternalMakefileProjectGeneratorFactory(n, doc) + { + } + + cmExternalMakefileProjectGenerator* CreateExternalMakefileProjectGenerator() + const + { + T* p = new T; + p->SetName(GetName()); + return p; + } }; #endif diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index fbfbccc..a846643 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -36,24 +36,30 @@ Discussion: http://forums.codeblocks.org/index.php/topic,6789.0.html */ -void cmExtraCodeBlocksGenerator::GetDocumentation(cmDocumentationEntry& entry, - const std::string&) const +cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator() + : cmExternalMakefileProjectGenerator() { - entry.Name = this->GetName(); - entry.Brief = "Generates CodeBlocks project files."; } -cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator() - : cmExternalMakefileProjectGenerator() +cmExternalMakefileProjectGeneratorFactory* +cmExtraCodeBlocksGenerator::NewFactory() { + static cmExternalMakefileProjectGeneratorSimpleFactory< + cmExtraCodeBlocksGenerator> + factory("CodeBlocks", "Generates CodeBlocks project files."); + + if (factory.GetSupportedGlobalGenerators().empty()) { #if defined(_WIN32) - this->SupportedGlobalGenerators.push_back("MinGW Makefiles"); - this->SupportedGlobalGenerators.push_back("NMake Makefiles"); + factory.AddSupportedGlobalGenerator("MinGW Makefiles"); + factory.AddSupportedGlobalGenerator("NMake Makefiles"); // disable until somebody actually tests it: -// this->SupportedGlobalGenerators.push_back("MSYS Makefiles"); +// this->AddSupportedGlobalGenerator("MSYS Makefiles"); #endif - this->SupportedGlobalGenerators.push_back("Ninja"); - this->SupportedGlobalGenerators.push_back("Unix Makefiles"); + factory.AddSupportedGlobalGenerator("Ninja"); + factory.AddSupportedGlobalGenerator("Unix Makefiles"); + } + + return &factory; } void cmExtraCodeBlocksGenerator::Generate() diff --git a/Source/cmExtraCodeBlocksGenerator.h b/Source/cmExtraCodeBlocksGenerator.h index 31ea500..55e21c6 100644 --- a/Source/cmExtraCodeBlocksGenerator.h +++ b/Source/cmExtraCodeBlocksGenerator.h @@ -28,18 +28,7 @@ class cmExtraCodeBlocksGenerator : public cmExternalMakefileProjectGenerator public: cmExtraCodeBlocksGenerator(); - std::string GetName() const CM_OVERRIDE - { - return cmExtraCodeBlocksGenerator::GetActualName(); - } - static std::string GetActualName() { return "CodeBlocks"; } - static cmExternalMakefileProjectGenerator* New() - { - return new cmExtraCodeBlocksGenerator; - } - /** Get the documentation entry for this generator. */ - void GetDocumentation(cmDocumentationEntry& entry, - const std::string& fullName) const CM_OVERRIDE; + static cmExternalMakefileProjectGeneratorFactory* NewFactory(); void Generate() CM_OVERRIDE; diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx index dd10b65..2bb6ff4 100644 --- a/Source/cmExtraCodeLiteGenerator.cxx +++ b/Source/cmExtraCodeLiteGenerator.cxx @@ -27,24 +27,30 @@ #include #include -void cmExtraCodeLiteGenerator::GetDocumentation(cmDocumentationEntry& entry, - const std::string&) const -{ - entry.Name = this->GetName(); - entry.Brief = "Generates CodeLite project files."; -} - cmExtraCodeLiteGenerator::cmExtraCodeLiteGenerator() : cmExternalMakefileProjectGenerator() , ConfigName("NoConfig") , CpuCount(2) { +} + +cmExternalMakefileProjectGeneratorFactory* +cmExtraCodeLiteGenerator::NewFactory() +{ + static cmExternalMakefileProjectGeneratorSimpleFactory< + cmExtraCodeLiteGenerator> + factory("CodeLite", "Generates CodeLite project files."); + + if (factory.GetSupportedGlobalGenerators().empty()) { #if defined(_WIN32) - this->SupportedGlobalGenerators.push_back("MinGW Makefiles"); - this->SupportedGlobalGenerators.push_back("NMake Makefiles"); + factory.AddSupportedGlobalGenerator("MinGW Makefiles"); + factory.AddSupportedGlobalGenerator("NMake Makefiles"); #endif - this->SupportedGlobalGenerators.push_back("Ninja"); - this->SupportedGlobalGenerators.push_back("Unix Makefiles"); + factory.AddSupportedGlobalGenerator("Ninja"); + factory.AddSupportedGlobalGenerator("Unix Makefiles"); + } + + return &factory; } void cmExtraCodeLiteGenerator::Generate() diff --git a/Source/cmExtraCodeLiteGenerator.h b/Source/cmExtraCodeLiteGenerator.h index f2ee85c..9eb0fb3 100644 --- a/Source/cmExtraCodeLiteGenerator.h +++ b/Source/cmExtraCodeLiteGenerator.h @@ -36,18 +36,7 @@ protected: public: cmExtraCodeLiteGenerator(); - std::string GetName() const CM_OVERRIDE - { - return cmExtraCodeLiteGenerator::GetActualName(); - } - static std::string GetActualName() { return "CodeLite"; } - static cmExternalMakefileProjectGenerator* New() - { - return new cmExtraCodeLiteGenerator; - } - /** Get the documentation entry for this generator. */ - void GetDocumentation(cmDocumentationEntry& entry, - const std::string& fullName) const CM_OVERRIDE; + static cmExternalMakefileProjectGeneratorFactory* NewFactory(); void Generate() CM_OVERRIDE; void CreateProjectFile(const std::vector& lgs); diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index 93c55cc..b26c4d0 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -46,16 +46,6 @@ void AppendDictionary(cmXMLWriter& xml, const char* key, T const& value) cmExtraEclipseCDT4Generator::cmExtraEclipseCDT4Generator() : cmExternalMakefileProjectGenerator() { -// TODO: Verify if __CYGWIN__ should be checked. -//#if defined(_WIN32) && !defined(__CYGWIN__) -#if defined(_WIN32) - this->SupportedGlobalGenerators.push_back("NMake Makefiles"); - this->SupportedGlobalGenerators.push_back("MinGW Makefiles"); -// this->SupportedGlobalGenerators.push_back("MSYS Makefiles"); -#endif - this->SupportedGlobalGenerators.push_back("Ninja"); - this->SupportedGlobalGenerators.push_back("Unix Makefiles"); - this->SupportsVirtualFolders = true; this->GenerateLinkedResources = true; this->SupportsGmakeErrorParser = true; @@ -64,11 +54,26 @@ cmExtraEclipseCDT4Generator::cmExtraEclipseCDT4Generator() this->CXXEnabled = false; } -void cmExtraEclipseCDT4Generator::GetDocumentation(cmDocumentationEntry& entry, - const std::string&) const +cmExternalMakefileProjectGeneratorFactory* +cmExtraEclipseCDT4Generator::NewFactory() { - entry.Name = this->GetName(); - entry.Brief = "Generates Eclipse CDT 4.0 project files."; + static cmExternalMakefileProjectGeneratorSimpleFactory< + cmExtraEclipseCDT4Generator> + factory("Eclipse CDT4", "Generates Eclipse CDT 4.0 project files."); + + if (factory.GetSupportedGlobalGenerators().empty()) { +// TODO: Verify if __CYGWIN__ should be checked. +//#if defined(_WIN32) && !defined(__CYGWIN__) +#if defined(_WIN32) + factory.AddSupportedGlobalGenerator("NMake Makefiles"); + factory.AddSupportedGlobalGenerator("MinGW Makefiles"); +// factory.AddSupportedGlobalGenerator("MSYS Makefiles"); +#endif + factory.AddSupportedGlobalGenerator("Ninja"); + factory.AddSupportedGlobalGenerator("Unix Makefiles"); + } + + return &factory; } void cmExtraEclipseCDT4Generator::EnableLanguage( diff --git a/Source/cmExtraEclipseCDT4Generator.h b/Source/cmExtraEclipseCDT4Generator.h index 0400ad5..d1c4684 100644 --- a/Source/cmExtraEclipseCDT4Generator.h +++ b/Source/cmExtraEclipseCDT4Generator.h @@ -35,20 +35,8 @@ public: cmExtraEclipseCDT4Generator(); - static cmExternalMakefileProjectGenerator* New() - { - return new cmExtraEclipseCDT4Generator; - } - - std::string GetName() const CM_OVERRIDE - { - return cmExtraEclipseCDT4Generator::GetActualName(); - } - - static std::string GetActualName() { return "Eclipse CDT4"; } + static cmExternalMakefileProjectGeneratorFactory* NewFactory(); - void GetDocumentation(cmDocumentationEntry& entry, - const std::string& fullName) const CM_OVERRIDE; void EnableLanguage(std::vector const& languages, cmMakefile*, bool optional) CM_OVERRIDE; diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx index b757a49..8cc2b5e 100644 --- a/Source/cmExtraKateGenerator.cxx +++ b/Source/cmExtraKateGenerator.cxx @@ -22,24 +22,28 @@ #include -void cmExtraKateGenerator::GetDocumentation(cmDocumentationEntry& entry, - const std::string&) const +cmExtraKateGenerator::cmExtraKateGenerator() + : cmExternalMakefileProjectGenerator() { - entry.Name = this->GetName(); - entry.Brief = "Generates Kate project files."; } -cmExtraKateGenerator::cmExtraKateGenerator() - : cmExternalMakefileProjectGenerator() +cmExternalMakefileProjectGeneratorFactory* cmExtraKateGenerator::NewFactory() { + static cmExternalMakefileProjectGeneratorSimpleFactory + factory("Kate", "Generates Kate project files."); + + if (factory.GetSupportedGlobalGenerators().empty()) { #if defined(_WIN32) - this->SupportedGlobalGenerators.push_back("MinGW Makefiles"); - this->SupportedGlobalGenerators.push_back("NMake Makefiles"); + factory.AddSupportedGlobalGenerator("MinGW Makefiles"); + factory.AddSupportedGlobalGenerator("NMake Makefiles"); // disable until somebody actually tests it: -// this->SupportedGlobalGenerators.push_back("MSYS Makefiles"); +// factory.AddSupportedGlobalGenerator("MSYS Makefiles"); #endif - this->SupportedGlobalGenerators.push_back("Ninja"); - this->SupportedGlobalGenerators.push_back("Unix Makefiles"); + factory.AddSupportedGlobalGenerator("Ninja"); + factory.AddSupportedGlobalGenerator("Unix Makefiles"); + } + + return &factory; } void cmExtraKateGenerator::Generate() diff --git a/Source/cmExtraKateGenerator.h b/Source/cmExtraKateGenerator.h index 410d552..1ac1c30 100644 --- a/Source/cmExtraKateGenerator.h +++ b/Source/cmExtraKateGenerator.h @@ -26,18 +26,7 @@ class cmExtraKateGenerator : public cmExternalMakefileProjectGenerator public: cmExtraKateGenerator(); - std::string GetName() const CM_OVERRIDE - { - return cmExtraKateGenerator::GetActualName(); - } - static std::string GetActualName() { return "Kate"; } - static cmExternalMakefileProjectGenerator* New() - { - return new cmExtraKateGenerator; - } - /** Get the documentation entry for this generator. */ - void GetDocumentation(cmDocumentationEntry& entry, - const std::string& fullName) const CM_OVERRIDE; + static cmExternalMakefileProjectGeneratorFactory* NewFactory(); void Generate() CM_OVERRIDE; diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index c166e26..3e1a48e 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -38,24 +38,30 @@ http://www.sublimetext.com/docs/2/projects.html http://sublimetext.info/docs/en/reference/build_systems.html */ -void cmExtraSublimeTextGenerator::GetDocumentation(cmDocumentationEntry& entry, - const std::string&) const +cmExternalMakefileProjectGeneratorFactory* +cmExtraSublimeTextGenerator::NewFactory() { - entry.Name = this->GetName(); - entry.Brief = "Generates Sublime Text 2 project files."; + static cmExternalMakefileProjectGeneratorSimpleFactory< + cmExtraSublimeTextGenerator> + factory("Sublime Text 2", "Generates Sublime Text 2 project files."); + + if (factory.GetSupportedGlobalGenerators().empty()) { +#if defined(_WIN32) + factory.AddSupportedGlobalGenerator("MinGW Makefiles"); + factory.AddSupportedGlobalGenerator("NMake Makefiles"); +// disable until somebody actually tests it: +// factory.AddSupportedGlobalGenerator("MSYS Makefiles"); +#endif + factory.AddSupportedGlobalGenerator("Ninja"); + factory.AddSupportedGlobalGenerator("Unix Makefiles"); + } + + return &factory; } cmExtraSublimeTextGenerator::cmExtraSublimeTextGenerator() : cmExternalMakefileProjectGenerator() { -#if defined(_WIN32) - this->SupportedGlobalGenerators.push_back("MinGW Makefiles"); - this->SupportedGlobalGenerators.push_back("NMake Makefiles"); -// disable until somebody actually tests it: -// this->SupportedGlobalGenerators.push_back("MSYS Makefiles"); -#endif - this->SupportedGlobalGenerators.push_back("Ninja"); - this->SupportedGlobalGenerators.push_back("Unix Makefiles"); } void cmExtraSublimeTextGenerator::Generate() diff --git a/Source/cmExtraSublimeTextGenerator.h b/Source/cmExtraSublimeTextGenerator.h index 26dd138..ea710d9 100644 --- a/Source/cmExtraSublimeTextGenerator.h +++ b/Source/cmExtraSublimeTextGenerator.h @@ -27,22 +27,10 @@ class cmGeneratorTarget; class cmExtraSublimeTextGenerator : public cmExternalMakefileProjectGenerator { public: + static cmExternalMakefileProjectGeneratorFactory* NewFactory(); typedef std::map > MapSourceFileFlags; cmExtraSublimeTextGenerator(); - std::string GetName() const CM_OVERRIDE - { - return cmExtraSublimeTextGenerator::GetActualName(); - } - static std::string GetActualName() { return "Sublime Text 2"; } - static cmExternalMakefileProjectGenerator* New() - { - return new cmExtraSublimeTextGenerator; - } - /** Get the documentation entry for this generator. */ - void GetDocumentation(cmDocumentationEntry& entry, - const std::string& fullName) const CM_OVERRIDE; - void Generate() CM_OVERRIDE; private: diff --git a/Source/cmGlobalKdevelopGenerator.cxx b/Source/cmGlobalKdevelopGenerator.cxx index bbd6baa..b272084 100644 --- a/Source/cmGlobalKdevelopGenerator.cxx +++ b/Source/cmGlobalKdevelopGenerator.cxx @@ -25,20 +25,28 @@ #include #include -void cmGlobalKdevelopGenerator::GetDocumentation(cmDocumentationEntry& entry, - const std::string&) const +cmGlobalKdevelopGenerator::cmGlobalKdevelopGenerator() + : cmExternalMakefileProjectGenerator() { - entry.Name = this->GetName(); - entry.Brief = "Generates KDevelop 3 project files."; } -cmGlobalKdevelopGenerator::cmGlobalKdevelopGenerator() - : cmExternalMakefileProjectGenerator() +cmExternalMakefileProjectGeneratorFactory* +cmGlobalKdevelopGenerator::NewFactory() { - this->SupportedGlobalGenerators.push_back("Unix Makefiles"); + static cmExternalMakefileProjectGeneratorSimpleFactory< + cmGlobalKdevelopGenerator> + factory("KDevelop3", "Generates KDevelop 3 project files."); + + if (factory.GetSupportedGlobalGenerators().empty()) { + factory.AddSupportedGlobalGenerator("Unix Makefiles"); #ifdef CMAKE_USE_NINJA - this->SupportedGlobalGenerators.push_back("Ninja"); + factory.AddSupportedGlobalGenerator("Ninja"); #endif + + factory.Aliases.push_back("KDevelop3"); + } + + return &factory; } void cmGlobalKdevelopGenerator::Generate() diff --git a/Source/cmGlobalKdevelopGenerator.h b/Source/cmGlobalKdevelopGenerator.h index c61cafb..a7d77a9 100644 --- a/Source/cmGlobalKdevelopGenerator.h +++ b/Source/cmGlobalKdevelopGenerator.h @@ -33,18 +33,7 @@ class cmGlobalKdevelopGenerator : public cmExternalMakefileProjectGenerator public: cmGlobalKdevelopGenerator(); - std::string GetName() const CM_OVERRIDE - { - return cmGlobalKdevelopGenerator::GetActualName(); - } - static std::string GetActualName() { return "KDevelop3"; } - static cmExternalMakefileProjectGenerator* New() - { - return new cmGlobalKdevelopGenerator; - } - /** Get the documentation entry for this generator. */ - void GetDocumentation(cmDocumentationEntry& entry, - const std::string& fullName) const CM_OVERRIDE; + static cmExternalMakefileProjectGeneratorFactory* NewFactory(); void Generate() CM_OVERRIDE; diff --git a/Source/cmake.cxx b/Source/cmake.cxx index cdc1284..8cc7ac5 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -793,53 +793,21 @@ int cmake::AddCMakePaths() return 1; } -void cmake::AddExtraGenerator(const std::string& name, - CreateExtraGeneratorFunctionType newFunction) -{ - cmExternalMakefileProjectGenerator* extraGenerator = newFunction(); - const std::vector& supportedGlobalGenerators = - extraGenerator->GetSupportedGlobalGenerators(); - - for (std::vector::const_iterator it = - supportedGlobalGenerators.begin(); - it != supportedGlobalGenerators.end(); ++it) { - std::string fullName = - cmExternalMakefileProjectGenerator::CreateFullGeneratorName(*it, name); - this->ExtraGenerators[fullName] = newFunction; - } - delete extraGenerator; -} - void cmake::AddDefaultExtraGenerators() { #if defined(CMAKE_BUILD_WITH_CMAKE) -#if defined(_WIN32) && !defined(__CYGWIN__) -// e.g. kdevelop4 ? -#endif - - this->AddExtraGenerator(cmExtraCodeBlocksGenerator::GetActualName(), - &cmExtraCodeBlocksGenerator::New); - this->AddExtraGenerator(cmExtraCodeLiteGenerator::GetActualName(), - &cmExtraCodeLiteGenerator::New); - this->AddExtraGenerator(cmExtraSublimeTextGenerator::GetActualName(), - &cmExtraSublimeTextGenerator::New); - this->AddExtraGenerator(cmExtraKateGenerator::GetActualName(), - &cmExtraKateGenerator::New); + this->ExtraGenerators.push_back(cmExtraCodeBlocksGenerator::NewFactory()); + this->ExtraGenerators.push_back(cmExtraCodeLiteGenerator::NewFactory()); + this->ExtraGenerators.push_back(cmExtraSublimeTextGenerator::NewFactory()); + this->ExtraGenerators.push_back(cmExtraKateGenerator::NewFactory()); #ifdef CMAKE_USE_ECLIPSE - this->AddExtraGenerator(cmExtraEclipseCDT4Generator::GetActualName(), - &cmExtraEclipseCDT4Generator::New); + this->ExtraGenerators.push_back(cmExtraEclipseCDT4Generator::NewFactory()); #endif #ifdef CMAKE_USE_KDEVELOP - this->AddExtraGenerator(cmGlobalKdevelopGenerator::GetActualName(), - &cmGlobalKdevelopGenerator::New); - // for kdevelop also add the generator with just the name of the - // extra generator, since it was this way since cmake 2.2 - this->ExtraGenerators[cmGlobalKdevelopGenerator::GetActualName()] = - &cmGlobalKdevelopGenerator::New; + this->ExtraGenerators.push_back(cmGlobalKdevelopGenerator::NewFactory()); #endif - #endif } @@ -856,32 +824,74 @@ void cmake::GetRegisteredGenerators(std::vector& generators) info.supportsToolset = (*i)->SupportsToolset(); info.supportsPlatform = (*i)->SupportsPlatform(); info.name = names[j]; + info.isAlias = false; generators.push_back(info); } } - for (RegisteredExtraGeneratorsMap::const_iterator + for (RegisteredExtraGeneratorsVector::const_iterator i = this->ExtraGenerators.begin(), e = this->ExtraGenerators.end(); i != e; ++i) { - GeneratorInfo info; - info.name = i->first; - info.supportsToolset = false; - info.supportsPlatform = false; - generators.push_back(info); + const std::vector genList = + (*i)->GetSupportedGlobalGenerators(); + for (std::vector::const_iterator gen = genList.begin(); + gen != genList.end(); ++gen) { + GeneratorInfo info; + info.name = cmExternalMakefileProjectGenerator::CreateFullGeneratorName( + (*i)->GetName(), *gen); + info.supportsPlatform = false; + info.supportsToolset = false; + info.isAlias = false; + generators.push_back(info); + } + for (std::vector::const_iterator a = (*i)->Aliases.begin(); + a != (*i)->Aliases.end(); ++a) { + GeneratorInfo info; + info.name = *a; + info.supportsPlatform = false; + info.supportsToolset = false; + info.isAlias = true; + generators.push_back(info); + } } } -cmGlobalGenerator* cmake::CreateGlobalGenerator(const std::string& gname) +static std::pair +createExtraGenerator( + const std::vector& in, + const std::string& name) { - cmExternalMakefileProjectGenerator* extraGenerator = CM_NULLPTR; - std::string name = gname; - RegisteredExtraGeneratorsMap::const_iterator extraGenIt = - this->ExtraGenerators.find(name); - if (extraGenIt != this->ExtraGenerators.end()) { - extraGenerator = (extraGenIt->second)(); - name = extraGenerator->GetGlobalGeneratorName(name); + for (std::vector::const_iterator + i = in.begin(); + i != in.end(); ++i) { + const std::vector generators = + (*i)->GetSupportedGlobalGenerators(); + if ((*i)->GetName() == name) { // Match aliases + return std::make_pair((*i)->CreateExternalMakefileProjectGenerator(), + generators.at(0)); + } + for (std::vector::const_iterator g = generators.begin(); + g != generators.end(); ++g) { + const std::string fullName = + cmExternalMakefileProjectGenerator::CreateFullGeneratorName( + *g, (*i)->GetName()); + if (fullName == name) { + return std::make_pair((*i)->CreateExternalMakefileProjectGenerator(), + *g); + } + } } + return std::make_pair( + static_cast(CM_NULLPTR), name); +} + +cmGlobalGenerator* cmake::CreateGlobalGenerator(const std::string& gname) +{ + std::pair extra = + createExtraGenerator(this->ExtraGenerators, gname); + cmExternalMakefileProjectGenerator* extraGenerator = extra.first; + const std::string name = extra.second; cmGlobalGenerator* generator = CM_NULLPTR; for (RegisteredGeneratorsVector::const_iterator i = this->Generators.begin(); @@ -1651,15 +1661,32 @@ void cmake::GetGeneratorDocumentation(std::vector& v) (*i)->GetDocumentation(e); v.push_back(e); } - for (RegisteredExtraGeneratorsMap::const_iterator i = + for (RegisteredExtraGeneratorsVector::const_iterator i = this->ExtraGenerators.begin(); i != this->ExtraGenerators.end(); ++i) { - cmDocumentationEntry e; - cmExternalMakefileProjectGenerator* generator = (i->second)(); - generator->GetDocumentation(e, i->first); - e.Name = i->first; - delete generator; - v.push_back(e); + const std::string doc = (*i)->GetDocumentation(); + const std::string name = (*i)->GetName(); + + // Aliases: + for (std::vector::const_iterator a = (*i)->Aliases.begin(); + a != (*i)->Aliases.end(); ++a) { + cmDocumentationEntry e; + e.Name = *a; + e.Brief = doc; + v.push_back(e); + } + + // Full names: + const std::vector generators = + (*i)->GetSupportedGlobalGenerators(); + for (std::vector::const_iterator g = generators.begin(); + g != generators.end(); ++g) { + cmDocumentationEntry e; + e.Name = + cmExternalMakefileProjectGenerator::CreateFullGeneratorName(*g, name); + e.Brief = doc; + v.push_back(e); + } } } diff --git a/Source/cmake.h b/Source/cmake.h index 4ca2a80..0fd2d31 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -27,7 +27,7 @@ class cmLocalGenerator; class cmMakefile; class cmVariableWatch; class cmFileTimeComparison; -class cmExternalMakefileProjectGenerator; +class cmExternalMakefileProjectGeneratorFactory; class cmDocumentationSection; class cmTarget; class cmGeneratedFileStream; @@ -105,6 +105,7 @@ public: std::string name; bool supportsToolset; bool supportsPlatform; + bool isAlias; }; typedef std::map InstalledFilesMap; @@ -416,18 +417,14 @@ protected: void InitializeProperties(); int HandleDeleteCacheVariables(const std::string& var); - typedef cmExternalMakefileProjectGenerator* ( - *CreateExtraGeneratorFunctionType)(); - typedef std::map - RegisteredExtraGeneratorsMap; typedef std::vector RegisteredGeneratorsVector; RegisteredGeneratorsVector Generators; - RegisteredExtraGeneratorsMap ExtraGenerators; + typedef std::vector + RegisteredExtraGeneratorsVector; + RegisteredExtraGeneratorsVector ExtraGenerators; void AddDefaultCommands(); void AddDefaultGenerators(); void AddDefaultExtraGenerators(); - void AddExtraGenerator(const std::string& name, - CreateExtraGeneratorFunctionType newFunction); cmGlobalGenerator* GlobalGenerator; std::map DiagLevels; ----------------------------------------------------------------------- Summary of changes: Source/cmExternalMakefileProjectGenerator.cxx | 49 ++++---- Source/cmExternalMakefileProjectGenerator.h | 55 +++++++-- Source/cmExtraCodeBlocksGenerator.cxx | 28 +++-- Source/cmExtraCodeBlocksGenerator.h | 13 +-- Source/cmExtraCodeLiteGenerator.cxx | 28 +++-- Source/cmExtraCodeLiteGenerator.h | 13 +-- Source/cmExtraEclipseCDT4Generator.cxx | 33 +++--- Source/cmExtraEclipseCDT4Generator.h | 14 +-- Source/cmExtraKateGenerator.cxx | 26 +++-- Source/cmExtraKateGenerator.h | 13 +-- Source/cmExtraSublimeTextGenerator.cxx | 30 +++-- Source/cmExtraSublimeTextGenerator.h | 14 +-- Source/cmGlobalKdevelopGenerator.cxx | 24 ++-- Source/cmGlobalKdevelopGenerator.h | 13 +-- Source/cmake.cxx | 152 +++++++++++++++---------- Source/cmake.h | 15 ++- 16 files changed, 285 insertions(+), 235 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 2 14:55:45 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 2 Aug 2016 14:55:45 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1059-g57addbd Message-ID: <20160802185545.B91A5F4B8E@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 57addbd3e72f7f16595ba2245a12da9eeac12535 (commit) via e34e9c2705c9e0bb568f5f69a655a9d425ef8adb (commit) via 9a1b6c6037869edba1c44dcfa06da8201653ce1b (commit) via 31b6cf41c5a4e17ea97e0c94f0e81b9a18ce96b8 (commit) from bfefab9fe5a3d517d4aadd02ecde2b064c438fb4 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=57addbd3e72f7f16595ba2245a12da9eeac12535 commit 57addbd3e72f7f16595ba2245a12da9eeac12535 Merge: bfefab9 e34e9c2 Author: Brad King AuthorDate: Tue Aug 2 14:55:44 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 14:55:44 2016 -0400 Merge topic 'ccmake-vim-navigation' into next e34e9c27 ccmake: Add VIM-like bindings for navigation 9a1b6c60 ccmake: Revise documentation for [d] 31b6cf41 ccmake: Fix typo in help (it's -> its) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e34e9c2705c9e0bb568f5f69a655a9d425ef8adb commit e34e9c2705c9e0bb568f5f69a655a9d425ef8adb Author: Paul Seyfert AuthorDate: Thu Jul 21 21:30:50 2016 +0200 Commit: Brad King CommitDate: Tue Aug 2 14:53:15 2016 -0400 ccmake: Add VIM-like bindings for navigation * scroll with j/k * toggle bool with space, enter insert mode with i * bindings not shown at the bottom of the screen, but given in help diff --git a/Help/release/dev/ccmake-vim-navigation.rst b/Help/release/dev/ccmake-vim-navigation.rst new file mode 100644 index 0000000..8fc1416 --- /dev/null +++ b/Help/release/dev/ccmake-vim-navigation.rst @@ -0,0 +1,4 @@ +ccmake-vim-navigation +--------------------- + +* :manual:`ccmake(1)` learned to support vim-like navigation bindings. diff --git a/Source/CursesDialog/cmCursesBoolWidget.cxx b/Source/CursesDialog/cmCursesBoolWidget.cxx index 9bcf050..e36ac34 100644 --- a/Source/CursesDialog/cmCursesBoolWidget.cxx +++ b/Source/CursesDialog/cmCursesBoolWidget.cxx @@ -27,8 +27,9 @@ cmCursesBoolWidget::cmCursesBoolWidget(int width, int height, int left, bool cmCursesBoolWidget::HandleInput(int& key, cmCursesMainForm*, WINDOW* w) { + // toggle boolean values with enter or space // 10 == enter - if (key == 10 || key == KEY_ENTER) { + if (key == 10 || key == KEY_ENTER || key == ' ') { if (this->GetValueAsBool()) { this->SetValueAsBool(false); } else { diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx index fd19a01..964f3af 100644 --- a/Source/CursesDialog/cmCursesMainForm.cxx +++ b/Source/CursesDialog/cmCursesMainForm.cxx @@ -837,7 +837,9 @@ void cmCursesMainForm::HandleInput() // therefore, the label field for the prev. entry is index-5 // and the label field for the next entry is index+1 // (index always corresponds to the value field) - else if (key == KEY_DOWN || key == ctrl('n')) { + // scroll down with arrow down, ctrl+n (emacs binding), or j (vim + // binding) + else if (key == KEY_DOWN || key == ctrl('n') || key == 'j') { FIELD* cur = current_field(this->Form); size_t findex = field_index(cur); if (findex == 3 * this->NumberOfVisibleEntries - 1) { @@ -854,7 +856,8 @@ void cmCursesMainForm::HandleInput() // therefore, the label field for the prev. entry is index-5 // and the label field for the next entry is index+1 // (index always corresponds to the value field) - else if (key == KEY_UP || key == ctrl('p')) { + // scroll down with arrow up, ctrl+p (emacs binding), or k (vim binding) + else if (key == KEY_UP || key == ctrl('p') || key == 'k') { FIELD* cur = current_field(this->Form); int findex = field_index(cur); if (findex == 2) { @@ -1122,16 +1125,17 @@ const char* cmCursesMainForm::s_ConstHelpMessage = "Navigation: " "You can use the arrow keys and page up, down to navigate the options. " "Alternatively, you can use the following keys: \n" - " C-n : next option\n" - " C-p : previous options\n" + " C-n or j : next option\n" + " C-p or k : previous options\n" " C-d : down one page\n" " C-u : up one page\n\n" "Editing options: " "To change an option press enter or return. If the current options is a " "boolean, this will toggle its value. " - "Otherwise, ccmake will enter edit mode. In this mode you can edit an " - "option using arrow keys and backspace. Alternatively, you can use the " - "following keys:\n" + "Otherwise, ccmake will enter edit mode. Alternatively, you can toggle " + "a bool variable by pressing space, and enter edit mode with i." + "In this mode you can edit an option using arrow keys and backspace. " + "Alternatively, you can use the following keys:\n" " C-b : back one character\n" " C-f : forward one character\n" " C-a : go to the beginning of the field\n" diff --git a/Source/CursesDialog/cmCursesStringWidget.cxx b/Source/CursesDialog/cmCursesStringWidget.cxx index 6eb5310..46b8b86 100644 --- a/Source/CursesDialog/cmCursesStringWidget.cxx +++ b/Source/CursesDialog/cmCursesStringWidget.cxx @@ -67,8 +67,10 @@ bool cmCursesStringWidget::HandleInput(int& key, cmCursesMainForm* fm, int x, y; FORM* form = fm->GetForm(); + // when not in edit mode, edit mode is entered by pressing enter or i (vim + // binding) // 10 == enter - if (!this->InEdit && (key != 10 && key != KEY_ENTER)) { + if (!this->InEdit && (key != 10 && key != KEY_ENTER && key != 'i')) { return false; } @@ -97,11 +99,15 @@ bool cmCursesStringWidget::HandleInput(int& key, cmCursesMainForm* fm, } // If resize occurred during edit, move out of edit mode - if (!this->InEdit && (key != 10 && key != KEY_ENTER)) { + if (!this->InEdit && (key != 10 && key != KEY_ENTER && key != 'i')) { return false; } - // 10 == enter - if (key == 10 || key == KEY_ENTER) { + // enter edit with return and i (vim binding) + if (!this->InEdit && (key == 10 || key == KEY_ENTER || key == 'i')) { + this->OnReturn(fm, w); + } + // leave edit with return (but not i -- not a toggle) + else if (this->InEdit && (key == 10 || key == KEY_ENTER)) { this->OnReturn(fm, w); } else if (key == KEY_DOWN || key == ctrl('n') || key == KEY_UP || key == ctrl('p') || key == KEY_NPAGE || key == ctrl('d') || https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9a1b6c6037869edba1c44dcfa06da8201653ce1b commit 9a1b6c6037869edba1c44dcfa06da8201653ce1b Author: Paul Seyfert AuthorDate: Thu Jul 21 21:29:18 2016 +0200 Commit: Brad King CommitDate: Tue Aug 2 14:53:15 2016 -0400 ccmake: Revise documentation for [d] * list it at the bottom of the screen * different place in help message diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx index b9fd8f8..fd19a01 100644 --- a/Source/CursesDialog/cmCursesMainForm.cxx +++ b/Source/CursesDialog/cmCursesMainForm.cxx @@ -388,7 +388,7 @@ void cmCursesMainForm::PrintKeys(int process /* = 0 */) curses_move(y - 4, 0); char fmt_s[] = "%s"; - char fmt[512] = "Press [enter] to edit option"; + char fmt[512] = "Press [enter] to edit option Press [d] to delete an entry"; if (process) { strcpy(fmt, " "); } @@ -1140,7 +1140,6 @@ const char* cmCursesMainForm::s_ConstHelpMessage = " C-k : kill the rest of the field\n" " Esc : Restore field (discard last changes)\n" " Enter : Leave edit mode\n" - "You can also delete an option by pressing 'd'\n\n" "Commands:\n" " q : quit ccmake without generating build files\n" " h : help, shows this screen\n" @@ -1148,6 +1147,7 @@ const char* cmCursesMainForm::s_ConstHelpMessage = " g : generate build files and exit, only available when there are no " "new options and no errors have been detected during last configuration.\n" " l : shows last errors\n" + " d : delete an option\n" " t : toggles advanced mode. In normal mode, only the most important " "options are shown. In advanced mode, all options are shown. We recommend " "using normal mode unless you are an expert.\n" https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=31b6cf41c5a4e17ea97e0c94f0e81b9a18ce96b8 commit 31b6cf41c5a4e17ea97e0c94f0e81b9a18ce96b8 Author: Paul Seyfert AuthorDate: Tue Aug 2 10:41:06 2016 -0500 Commit: Brad King CommitDate: Tue Aug 2 14:53:06 2016 -0400 ccmake: Fix typo in help (it's -> its) diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx index 9ae38d6..b9fd8f8 100644 --- a/Source/CursesDialog/cmCursesMainForm.cxx +++ b/Source/CursesDialog/cmCursesMainForm.cxx @@ -1128,7 +1128,7 @@ const char* cmCursesMainForm::s_ConstHelpMessage = " C-u : up one page\n\n" "Editing options: " "To change an option press enter or return. If the current options is a " - "boolean, this will toggle it's value. " + "boolean, this will toggle its value. " "Otherwise, ccmake will enter edit mode. In this mode you can edit an " "option using arrow keys and backspace. Alternatively, you can use the " "following keys:\n" ----------------------------------------------------------------------- Summary of changes: Help/release/dev/ccmake-vim-navigation.rst | 4 ++++ Source/CursesDialog/cmCursesBoolWidget.cxx | 3 ++- Source/CursesDialog/cmCursesMainForm.cxx | 24 ++++++++++++++---------- Source/CursesDialog/cmCursesStringWidget.cxx | 14 ++++++++++---- 4 files changed, 30 insertions(+), 15 deletions(-) create mode 100644 Help/release/dev/ccmake-vim-navigation.rst hooks/post-receive -- CMake From ben.boeckel at kitware.com Tue Aug 2 15:13:48 2016 From: ben.boeckel at kitware.com (Ben Boeckel) Date: Tue, 2 Aug 2016 15:13:48 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1063-g55c3ee1 Message-ID: <20160802191348.7B052F3A73@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 55c3ee103dcac6bc4659993deee069b53bcc008b (commit) via 088f14eb725650158d256c28e86e44da3989ad9c (commit) via 27a3ca15e5e92abbdf9228a5ac83c190a5caf0a8 (commit) via cc223e1eed69775a323a59628ad93fc79390c2f2 (commit) from 57addbd3e72f7f16595ba2245a12da9eeac12535 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=55c3ee103dcac6bc4659993deee069b53bcc008b commit 55c3ee103dcac6bc4659993deee069b53bcc008b Merge: 57addbd 088f14e Author: Ben Boeckel AuthorDate: Tue Aug 2 15:13:46 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 15:13:46 2016 -0400 Merge topic 'intel-gnu11-support' into next 088f14eb Intel-C: standard flags are also supported in 12.0 27a3ca15 Intel-C: support gnu89 and gnu99 extension flags cc223e1e Intel-C: declare support for gnu11 https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=088f14eb725650158d256c28e86e44da3989ad9c commit 088f14eb725650158d256c28e86e44da3989ad9c Author: Ben Boeckel AuthorDate: Tue Aug 2 13:10:56 2016 -0400 Commit: Ben Boeckel CommitDate: Tue Aug 2 13:10:56 2016 -0400 Intel-C: standard flags are also supported in 12.0 diff --git a/Modules/Compiler/Intel-C.cmake b/Modules/Compiler/Intel-C.cmake index 0efcbc2..edca154 100644 --- a/Modules/Compiler/Intel-C.cmake +++ b/Modules/Compiler/Intel-C.cmake @@ -19,7 +19,7 @@ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 15.0.0) set(CMAKE_C11_EXTENSION_COMPILE_OPTION "${_std}=gnu11") endif() -if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.1) +if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.0) set(CMAKE_C90_STANDARD_COMPILE_OPTION "${_std}=c89") set(CMAKE_C90_EXTENSION_COMPILE_OPTION "${_std}=gnu89") set(CMAKE_C99_STANDARD_COMPILE_OPTION "${_std}=c99") https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=27a3ca15e5e92abbdf9228a5ac83c190a5caf0a8 commit 27a3ca15e5e92abbdf9228a5ac83c190a5caf0a8 Author: Ben Boeckel AuthorDate: Tue Aug 2 13:10:30 2016 -0400 Commit: Ben Boeckel CommitDate: Tue Aug 2 13:10:41 2016 -0400 Intel-C: support gnu89 and gnu99 extension flags diff --git a/Modules/Compiler/Intel-C.cmake b/Modules/Compiler/Intel-C.cmake index b2ff50d..0efcbc2 100644 --- a/Modules/Compiler/Intel-C.cmake +++ b/Modules/Compiler/Intel-C.cmake @@ -21,9 +21,9 @@ endif() if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.1) set(CMAKE_C90_STANDARD_COMPILE_OPTION "${_std}=c89") - set(CMAKE_C90_EXTENSION_COMPILE_OPTION "${_std}=c89") + set(CMAKE_C90_EXTENSION_COMPILE_OPTION "${_std}=gnu89") set(CMAKE_C99_STANDARD_COMPILE_OPTION "${_std}=c99") - set(CMAKE_C99_EXTENSION_COMPILE_OPTION "${_std}=c99") + set(CMAKE_C99_EXTENSION_COMPILE_OPTION "${_std}=gnu99") endif() if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.1) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cc223e1eed69775a323a59628ad93fc79390c2f2 commit cc223e1eed69775a323a59628ad93fc79390c2f2 Author: Ben Boeckel AuthorDate: Tue Aug 2 11:31:50 2016 -0400 Commit: Ben Boeckel CommitDate: Tue Aug 2 11:42:45 2016 -0400 Intel-C: declare support for gnu11 Without extensions, functions like `strdup` are not available since they are actually controlled by feature flags such as _SVID_SOURCE and _BSD_SOURCE. When using `-std=c11` on Intel, none of these flags are set, so the functions are not declared properly leading to compile errors. Reported-by: Adam J. Stewart Closes: #16226 diff --git a/Modules/Compiler/Intel-C.cmake b/Modules/Compiler/Intel-C.cmake index eb9602a..b2ff50d 100644 --- a/Modules/Compiler/Intel-C.cmake +++ b/Modules/Compiler/Intel-C.cmake @@ -16,7 +16,7 @@ endif() if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 15.0.0) set(CMAKE_C11_STANDARD_COMPILE_OPTION "${_std}=c11") - set(CMAKE_C11_EXTENSION_COMPILE_OPTION "${_std}=c11") + set(CMAKE_C11_EXTENSION_COMPILE_OPTION "${_std}=gnu11") endif() if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.1) ----------------------------------------------------------------------- Summary of changes: Modules/Compiler/Intel-C.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 2 15:33:54 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 2 Aug 2016 15:33:54 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1065-g51985a8 Message-ID: <20160802193400.B1A7BF4F8E@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 51985a880bf3a93b161159cac04e8a2edb268010 (commit) via 7d7446c905623420482dda9eb6e10e0f604f6fd9 (commit) from 55c3ee103dcac6bc4659993deee069b53bcc008b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=51985a880bf3a93b161159cac04e8a2edb268010 commit 51985a880bf3a93b161159cac04e8a2edb268010 Merge: 55c3ee1 7d7446c Author: Brad King AuthorDate: Tue Aug 2 15:33:53 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 15:33:53 2016 -0400 Merge topic 'doc-without-continue' into next 7d7446c9 Utilities/Sphinx: Remove use of continue() method https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7d7446c905623420482dda9eb6e10e0f604f6fd9 commit 7d7446c905623420482dda9eb6e10e0f604f6fd9 Author: Konstantin Podsvirov AuthorDate: Mon Aug 1 23:16:55 2016 +0300 Commit: Brad King CommitDate: Tue Aug 2 15:15:00 2016 -0400 Utilities/Sphinx: Remove use of continue() method We currently only require CMake 2.8.4 which does not provide it. diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt index 257ba62..45f79dd 100644 --- a/Utilities/Sphinx/CMakeLists.txt +++ b/Utilities/Sphinx/CMakeLists.txt @@ -156,18 +156,21 @@ if(SPHINX_MAN) if("x${m}" MATCHES "^x(.+)\\.([1-9])\\.rst$") set(name "${CMAKE_MATCH_1}") set(sec "${CMAKE_MATCH_2}") + set(skip FALSE) if(NOT CMakeHelp_STANDALONE) if(name STREQUAL "ccmake" AND NOT BUILD_CursesDialog) - continue() - endif() - if(name STREQUAL "cmake-gui" AND NOT BUILD_QtDialog) - continue() + set(skip TRUE) + elseif(name STREQUAL "cmake-gui" AND NOT BUILD_QtDialog) + set(skip TRUE) endif() endif() - CMake_OPTIONAL_COMPONENT(sphinx-man) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/${name}.${sec} - DESTINATION ${CMAKE_MAN_DIR}/man${sec} - ${COMPONENT}) + if(NOT skip) + CMake_OPTIONAL_COMPONENT(sphinx-man) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/${name}.${sec} + DESTINATION ${CMAKE_MAN_DIR}/man${sec} + ${COMPONENT}) + endif() + unset(skip) endif() endforeach() endif() ----------------------------------------------------------------------- Summary of changes: Utilities/Sphinx/CMakeLists.txt | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 2 15:36:41 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 2 Aug 2016 15:36:41 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1067-g22a76e3 Message-ID: <20160802193646.74696F515E@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 22a76e3b9116497edf0585ede878f7ce28cba690 (commit) via 15a6ae5cb7d2d7b67ef5704acd01b6f6765fd5d9 (commit) from 51985a880bf3a93b161159cac04e8a2edb268010 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=22a76e3b9116497edf0585ede878f7ce28cba690 commit 22a76e3b9116497edf0585ede878f7ce28cba690 Merge: 51985a8 15a6ae5 Author: Brad King AuthorDate: Tue Aug 2 15:36:39 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 2 15:36:39 2016 -0400 Merge topic 'FindCUDA-arch' into next 15a6ae5c FindCUDA: Add search path for nvcc on Arch https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=15a6ae5cb7d2d7b67ef5704acd01b6f6765fd5d9 commit 15a6ae5cb7d2d7b67ef5704acd01b6f6765fd5d9 Author: Hans Gaiser AuthorDate: Tue Aug 2 11:00:43 2016 +0200 Commit: Brad King CommitDate: Tue Aug 2 15:36:07 2016 -0400 FindCUDA: Add search path for nvcc on Arch diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake index 6d9b833..dbc56bb 100644 --- a/Modules/FindCUDA.cmake +++ b/Modules/FindCUDA.cmake @@ -621,7 +621,8 @@ if(NOT CUDA_TOOLKIT_ROOT_DIR AND NOT CMAKE_CROSSCOMPILING) # Now search default paths find_path(CUDA_TOOLKIT_ROOT_DIR NAMES nvcc nvcc.exe - PATHS /usr/local/bin + PATHS /opt/cuda/bin + /usr/local/bin /usr/local/cuda/bin DOC "Toolkit location." ) ----------------------------------------------------------------------- Summary of changes: Modules/FindCUDA.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) hooks/post-receive -- CMake From kwrobot at kitware.com Wed Aug 3 00:01:07 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Wed, 3 Aug 2016 00:01:07 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-507-g33fe475 Message-ID: <20160803040107.2BB87F479D@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 33fe4751e8ccc1ad5342cb16a192cb3a69479845 (commit) from fd59f9ad519c1c311c54569133797d9061e90558 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=33fe4751e8ccc1ad5342cb16a192cb3a69479845 commit 33fe4751e8ccc1ad5342cb16a192cb3a69479845 Author: Kitware Robot AuthorDate: Wed Aug 3 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Wed Aug 3 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index f203b3c..a742e33 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160802) +set(CMake_VERSION_PATCH 20160803) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:20:22 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:20:22 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-509-ga382c30 Message-ID: <20160803132022.7E0E7F4DC4@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via a382c3013c7b98a95c6d4ceb833721093a5c9ff3 (commit) via 8eb0b56c2ace0f005cba436268337f509e06033f (commit) from 33fe4751e8ccc1ad5342cb16a192cb3a69479845 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a382c3013c7b98a95c6d4ceb833721093a5c9ff3 commit a382c3013c7b98a95c6d4ceb833721093a5c9ff3 Merge: 33fe475 8eb0b56 Author: Brad King AuthorDate: Wed Aug 3 09:20:19 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:20:19 2016 -0400 Merge topic 'fix-findhdf5-definitions' 8eb0b56c FindHDF5: Make sure compile definition vars keep the -D flag ----------------------------------------------------------------------- Summary of changes: Modules/FindHDF5.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:20:27 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:20:27 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-513-g16e449c Message-ID: <20160803132027.76915F4DC6@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 16e449cc7221cbf77a2bac02a91d986703fe6483 (commit) via 088f14eb725650158d256c28e86e44da3989ad9c (commit) via 27a3ca15e5e92abbdf9228a5ac83c190a5caf0a8 (commit) via cc223e1eed69775a323a59628ad93fc79390c2f2 (commit) from a382c3013c7b98a95c6d4ceb833721093a5c9ff3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=16e449cc7221cbf77a2bac02a91d986703fe6483 commit 16e449cc7221cbf77a2bac02a91d986703fe6483 Merge: a382c30 088f14e Author: Brad King AuthorDate: Wed Aug 3 09:20:25 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:20:25 2016 -0400 Merge topic 'intel-gnu11-support' 088f14eb Intel-C: standard flags are also supported in 12.0 27a3ca15 Intel-C: support gnu89 and gnu99 extension flags cc223e1e Intel-C: declare support for gnu11 ----------------------------------------------------------------------- Summary of changes: Modules/Compiler/Intel-C.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:20:31 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:20:31 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-515-g4b0e1dc Message-ID: <20160803132031.A71F2F4DC4@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 4b0e1dc0a4ae5f4fdb680e1ec27cd1f392d64ffb (commit) via 7d7446c905623420482dda9eb6e10e0f604f6fd9 (commit) from 16e449cc7221cbf77a2bac02a91d986703fe6483 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4b0e1dc0a4ae5f4fdb680e1ec27cd1f392d64ffb commit 4b0e1dc0a4ae5f4fdb680e1ec27cd1f392d64ffb Merge: 16e449c 7d7446c Author: Brad King AuthorDate: Wed Aug 3 09:20:29 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:20:29 2016 -0400 Merge topic 'doc-without-continue' 7d7446c9 Utilities/Sphinx: Remove use of continue() method ----------------------------------------------------------------------- Summary of changes: Utilities/Sphinx/CMakeLists.txt | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:20:34 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:20:34 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-517-g573397b Message-ID: <20160803132034.71B35F4DC3@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 573397bb540a1b1bbe991602d58835bb1a9f61e1 (commit) via 15a6ae5cb7d2d7b67ef5704acd01b6f6765fd5d9 (commit) from 4b0e1dc0a4ae5f4fdb680e1ec27cd1f392d64ffb (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=573397bb540a1b1bbe991602d58835bb1a9f61e1 commit 573397bb540a1b1bbe991602d58835bb1a9f61e1 Merge: 4b0e1dc 15a6ae5 Author: Brad King AuthorDate: Wed Aug 3 09:20:32 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:20:32 2016 -0400 Merge topic 'FindCUDA-arch' 15a6ae5c FindCUDA: Add search path for nvcc on Arch ----------------------------------------------------------------------- Summary of changes: Modules/FindCUDA.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:20:37 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:20:37 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-519-g8ba870b Message-ID: <20160803132037.68E80F4E1C@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 8ba870bad6210ae2c053ae4f7c19bcb9d8312eab (commit) via f4e979b126e41384b14f0d5ff8b41d81b6f41a00 (commit) from 573397bb540a1b1bbe991602d58835bb1a9f61e1 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8ba870bad6210ae2c053ae4f7c19bcb9d8312eab commit 8ba870bad6210ae2c053ae4f7c19bcb9d8312eab Merge: 573397b f4e979b Author: Brad King AuthorDate: Wed Aug 3 09:20:35 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:20:35 2016 -0400 Merge topic 'FindCUDA-no-windows-librt' f4e979b1 FindCUDA: Do not look for librt on Windows ----------------------------------------------------------------------- Summary of changes: Modules/FindCUDA.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:20:41 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:20:41 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-521-g7b65e49 Message-ID: <20160803132041.07EF0F4E20@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 7b65e49529bbc384b2f241685d647f26ac041d5b (commit) via e29bfbf272dbf4ea5f6a89084ec1f503fcf0e4f7 (commit) from 8ba870bad6210ae2c053ae4f7c19bcb9d8312eab (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7b65e49529bbc384b2f241685d647f26ac041d5b commit 7b65e49529bbc384b2f241685d647f26ac041d5b Merge: 8ba870b e29bfbf Author: Brad King AuthorDate: Wed Aug 3 09:20:38 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:20:38 2016 -0400 Merge topic 'wix-root-description' e29bfbf2 CPackWIX: Support custom title and description for the root feature ----------------------------------------------------------------------- Summary of changes: Help/release/dev/wix-root-description.rst | 7 +++++++ Modules/CPackWIX.cmake | 11 +++++++++++ Source/CPack/WiX/cmCPackWIXGenerator.cxx | 9 ++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 Help/release/dev/wix-root-description.rst hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:20:43 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:20:43 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-524-gf8792c1 Message-ID: <20160803132043.D8C67F4E1C@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via f8792c12b9e57dafcee2306e12dec268f9e147f2 (commit) via 35995fa6b5872b58f086d16b16ca90d7d259d9b0 (commit) via 6bc3073e23af70bde3e8a7659aa51a784deeec9c (commit) from 7b65e49529bbc384b2f241685d647f26ac041d5b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f8792c12b9e57dafcee2306e12dec268f9e147f2 commit f8792c12b9e57dafcee2306e12dec268f9e147f2 Merge: 7b65e49 35995fa Author: Brad King AuthorDate: Wed Aug 3 09:20:41 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:20:41 2016 -0400 Merge topic 'update-kwsys' 35995fa6 Merge branch 'upstream-KWSys' into update-kwsys 6bc3073e KWSys 2016-08-01 (560bcdbb) ----------------------------------------------------------------------- Summary of changes: Source/kwsys/Directory.cxx | 31 +++++++++++++++++++++---------- Source/kwsys/SystemTools.cxx | 9 +++++++-- Source/kwsys/SystemTools.hxx.in | 1 + 3 files changed, 29 insertions(+), 12 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:20:46 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:20:46 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-526-gef729c5 Message-ID: <20160803132046.B9B7AF4E2B@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via ef729c5bc2591542eacbe2aaf46bde9b4ae6d2ed (commit) via 52aecc0c382384d5bea3c18d7894e80bc573d8d7 (commit) from f8792c12b9e57dafcee2306e12dec268f9e147f2 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ef729c5bc2591542eacbe2aaf46bde9b4ae6d2ed commit ef729c5bc2591542eacbe2aaf46bde9b4ae6d2ed Merge: f8792c1 52aecc0 Author: Brad King AuthorDate: Wed Aug 3 09:20:44 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:20:44 2016 -0400 Merge topic 'ExternalProject-no-DS_Store' 52aecc0c ExternalProject: Ignore macOS .DS_Store files in tarball extraction ----------------------------------------------------------------------- Summary of changes: Modules/ExternalProject.cmake | 1 + 1 file changed, 1 insertion(+) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:20:49 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:20:49 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-529-gec807f6 Message-ID: <20160803132049.7866BF4E26@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via ec807f6edf7ddd49fc82638f176ac58d6eab6b80 (commit) via 56539d89da4f8f0834a17faee14ef88f3b232048 (commit) via 16a3a73508e8109e453e35288c37fe545a8ab59e (commit) from ef729c5bc2591542eacbe2aaf46bde9b4ae6d2ed (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ec807f6edf7ddd49fc82638f176ac58d6eab6b80 commit ec807f6edf7ddd49fc82638f176ac58d6eab6b80 Merge: ef729c5 56539d8 Author: Brad King AuthorDate: Wed Aug 3 09:20:47 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:20:47 2016 -0400 Merge topic 'port-to-sco' 56539d89 SCO_SV: Enable so filename versioning 16a3a735 cmELF: Port to SCO OpenServer 5.0.7/3.2 ----------------------------------------------------------------------- Summary of changes: Modules/Platform/SCO_SV.cmake | 1 + Source/cmELF.cxx | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:20:52 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:20:52 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-531-ga85e2a8 Message-ID: <20160803132052.AFD8DF4E1C@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via a85e2a89de3d394d084703b29cd7e0ef3bf8f570 (commit) via 5790d9b6f5ae0b5bb8b0f2e4ec630a690b4b0301 (commit) from ec807f6edf7ddd49fc82638f176ac58d6eab6b80 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a85e2a89de3d394d084703b29cd7e0ef3bf8f570 commit a85e2a89de3d394d084703b29cd7e0ef3bf8f570 Merge: ec807f6 5790d9b Author: Brad King AuthorDate: Wed Aug 3 09:20:50 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:20:50 2016 -0400 Merge topic 'FindProtobuf-restore-PROTOBUF_IMPORT_DIRS' 5790d9b6 FindProtobuf: Restore support for PROTOBUF_IMPORT_DIRS ----------------------------------------------------------------------- Summary of changes: Modules/FindProtobuf.cmake | 8 ++++++++ 1 file changed, 8 insertions(+) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:20:55 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:20:55 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-533-gaabf877 Message-ID: <20160803132056.028B9F4DD7@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via aabf8772fd3a2dde07d48d41658db728755e3041 (commit) via 85e0314201005c923420eb650a9629e38356b77a (commit) from a85e2a89de3d394d084703b29cd7e0ef3bf8f570 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=aabf8772fd3a2dde07d48d41658db728755e3041 commit aabf8772fd3a2dde07d48d41658db728755e3041 Merge: a85e2a8 85e0314 Author: Brad King AuthorDate: Wed Aug 3 09:20:54 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:20:54 2016 -0400 Merge topic 'gcc-fvisibility-version' 85e03142 GNU: Use -fvisibility on GCC 4.0 and 4.1 too ----------------------------------------------------------------------- Summary of changes: Modules/Compiler/GNU.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:20:58 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:20:58 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-535-gc2bc47f Message-ID: <20160803132058.93A16F4DC3@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via c2bc47f2662ec7e80469bee634c2444ee3d28bcc (commit) via 9970cdcb59e5d02da68c195799146f9bc91816e7 (commit) from aabf8772fd3a2dde07d48d41658db728755e3041 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c2bc47f2662ec7e80469bee634c2444ee3d28bcc commit c2bc47f2662ec7e80469bee634c2444ee3d28bcc Merge: aabf877 9970cdc Author: Brad King AuthorDate: Wed Aug 3 09:20:56 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:20:56 2016 -0400 Merge topic 'CMakeFindFrameworks-custom-locations' 9970cdcb CMakeFindFrameworks: Allow custom framework locations ----------------------------------------------------------------------- Summary of changes: Modules/CMakeFindFrameworks.cmake | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:21:01 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:21:01 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-539-g382c4fc Message-ID: <20160803132101.75678F4DC7@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 382c4fca6b895c2c7a68445918a8fd73a15e1f91 (commit) via e34e9c2705c9e0bb568f5f69a655a9d425ef8adb (commit) via 9a1b6c6037869edba1c44dcfa06da8201653ce1b (commit) via 31b6cf41c5a4e17ea97e0c94f0e81b9a18ce96b8 (commit) from c2bc47f2662ec7e80469bee634c2444ee3d28bcc (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=382c4fca6b895c2c7a68445918a8fd73a15e1f91 commit 382c4fca6b895c2c7a68445918a8fd73a15e1f91 Merge: c2bc47f e34e9c2 Author: Brad King AuthorDate: Wed Aug 3 09:20:59 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:20:59 2016 -0400 Merge topic 'ccmake-vim-navigation' e34e9c27 ccmake: Add VIM-like bindings for navigation 9a1b6c60 ccmake: Revise documentation for [d] 31b6cf41 ccmake: Fix typo in help (it's -> its) ----------------------------------------------------------------------- Summary of changes: Help/release/dev/ccmake-vim-navigation.rst | 4 ++++ Source/CursesDialog/cmCursesBoolWidget.cxx | 3 ++- Source/CursesDialog/cmCursesMainForm.cxx | 24 ++++++++++++++---------- Source/CursesDialog/cmCursesStringWidget.cxx | 14 ++++++++++---- 4 files changed, 30 insertions(+), 15 deletions(-) create mode 100644 Help/release/dev/ccmake-vim-navigation.rst hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:26:32 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:26:32 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1082-gb9b2345 Message-ID: <20160803132632.B279DF53DF@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via b9b234532cf6602938d843ae24915222af7b11ac (commit) via 382c4fca6b895c2c7a68445918a8fd73a15e1f91 (commit) via c2bc47f2662ec7e80469bee634c2444ee3d28bcc (commit) via aabf8772fd3a2dde07d48d41658db728755e3041 (commit) via a85e2a89de3d394d084703b29cd7e0ef3bf8f570 (commit) via ec807f6edf7ddd49fc82638f176ac58d6eab6b80 (commit) via ef729c5bc2591542eacbe2aaf46bde9b4ae6d2ed (commit) via f8792c12b9e57dafcee2306e12dec268f9e147f2 (commit) via 7b65e49529bbc384b2f241685d647f26ac041d5b (commit) via 8ba870bad6210ae2c053ae4f7c19bcb9d8312eab (commit) via 573397bb540a1b1bbe991602d58835bb1a9f61e1 (commit) via 4b0e1dc0a4ae5f4fdb680e1ec27cd1f392d64ffb (commit) via 16e449cc7221cbf77a2bac02a91d986703fe6483 (commit) via a382c3013c7b98a95c6d4ceb833721093a5c9ff3 (commit) via 33fe4751e8ccc1ad5342cb16a192cb3a69479845 (commit) from 22a76e3b9116497edf0585ede878f7ce28cba690 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b9b234532cf6602938d843ae24915222af7b11ac commit b9b234532cf6602938d843ae24915222af7b11ac Merge: 22a76e3 382c4fc Author: Brad King AuthorDate: Wed Aug 3 09:26:19 2016 -0400 Commit: Brad King CommitDate: Wed Aug 3 09:26:19 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:35:12 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:35:12 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1084-gd259460 Message-ID: <20160803133512.8E5E5F55B9@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via d2594605c46f3f388b9a13f9cea69ca774fa0f78 (commit) via c4f92c25d9222a8f6c6bcc112146b6784c61bb29 (commit) from b9b234532cf6602938d843ae24915222af7b11ac (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d2594605c46f3f388b9a13f9cea69ca774fa0f78 commit d2594605c46f3f388b9a13f9cea69ca774fa0f78 Merge: b9b2345 c4f92c2 Author: Brad King AuthorDate: Wed Aug 3 09:35:11 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:35:11 2016 -0400 Merge topic 'add-findszip' into next c4f92c25 Revert "FindSZIP: Add a new find module to locate the SZIP library." https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c4f92c25d9222a8f6c6bcc112146b6784c61bb29 commit c4f92c25d9222a8f6c6bcc112146b6784c61bb29 Author: Brad King AuthorDate: Wed Aug 3 09:34:55 2016 -0400 Commit: Brad King CommitDate: Wed Aug 3 09:34:55 2016 -0400 Revert "FindSZIP: Add a new find module to locate the SZIP library." This reverts commit 412f76c6b8a713a158396f385bc0521cd3d39f7c. It will be revised and restored. diff --git a/Modules/FindSZIP.cmake b/Modules/FindSZIP.cmake deleted file mode 100644 index db0a3c7..0000000 --- a/Modules/FindSZIP.cmake +++ /dev/null @@ -1,128 +0,0 @@ -#.rst: -# FindSZIP -# --------- -# -# Find SZIP, a compression library developed by HDF5. -# -# Once done this will define -# -# :: -# SZIP_FOUND - System has SZIP -# SZIP_INCLUDE_DIRS - The SZIP include directories to use -# SZIP_LIBRARIES - Link these to use SZIP -# SZIP_VERSION - The version of SZIP found -# :: -# -# The following imported target is also created: -# -# :: -# SZIP::SZIP -# :: -# -# The following variable can be set to guide the search for SZIP libraries and -# includes: -# SZIP_ROOT_DIR - -# Search order preference is SZIP_ROOT_DIR followed by ENV{SZIP_INSTALL}. -# If SZIP_ROOT_DIR is specified then it is searched exclusively, ignoring -# default search paths. - -#============================================================================= -# Copyright 2006-2016 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -function(_SZIP_get_version) - set(scratch_dir ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/szip) - set(test_file ${scratch_dir}/cmake_szip_version.c) - file(WRITE ${test_file} - "#include \n" - "#include \n" - "int main(void) {\n" - " char const* info_ver = \"INFO\" \":\" SZLIB_VERSION;\n" - " return 0;\n" - "}") - try_compile(szip_version_test ${scratch_dir} ${test_file} - CMAKE_FLAGS -DINCLUDE_DIRECTORIES=${SZIP_INCLUDE_DIR} - COPY_FILE ${scratch_dir}/cmake_szip_version) - if(szip_version_test) - file(STRINGS ${scratch_dir}/cmake_szip_version INFO_VER - REGEX "^INFO:([0-9]+(\\.[0-9]+(\\.[0-9]+)?)?)$") - string(REGEX MATCH "^INFO:([0-9]+(\\.[0-9]+(\\.[0-9]+)?)?)$" - INFO_VER "${INFO_VER}") - set(SZIP_VERSION ${CMAKE_MATCH_1} PARENT_SCOPE) - endif() -endfunction() - -# If the root dir is explicitly specified, then ONLY look there -message("SZIP_ROOT_DIR: ${SZIP_ROOT_DIR}") -message("ENV{SZIP_INSTALL}: $ENV{SZIP_INSTALL}") -if(SZIP_ROOT_DIR) - set(SZIP_SEARCH_OPTS PATHS ${SZIP_ROOT_DIR} NO_DEFAULT_PATH) -elseif(NOT ("$ENV{SZIP_INSTALL}" STREQUAL "")) - message("DEBUG: ENV{SZIP_INSTALL}") - set(SZIP_SEARCH_OPTS HINTS ENV SZIP_INSTALL) -endif() - -# Find the main header -find_path(SZIP_INCLUDE_DIR NAMES szlib.h - ${SZIP_SEARCH_OPTS} PATH_SUFFIXES include include/szip Include Include/szip) -mark_as_advanced(SZIP_INCLUDE_DIR) - -# Find the release library -set(SZIP_LIBRARY_RELEASE_NAMES sz szip) -if(WIN32) - list(APPEND SZIP_LIBRARY_RELEASE_NAMES libsz libszip) -endif() -find_library(SZIP_LIBRARY_RELEASE NAMES ${SZIP_LIBRARY_RELEASE_NAMES} - ${SZIP_SEARCH_OPTS} PATH_SUFFIXES lib Lib) - -# Find the debug library -set(SZIP_LIBRARY_DEBUG_NAMES sz_d szip_d) -if(WIN32) - list(APPEND SZIP_LIBARY_DEBUG_NAMES libsz_d libszip_d) -endif() -find_library(SZIP_LIBRARY_DEBUG NAMES ${SZIP_LIBRARY_DEBUG_NAMES} - ${SZIP_SEARCH_OPTS} PATH_SUFFIXES lib Lib) - -include(SelectLibraryConfigurations) -select_library_configurations(SZIP) - -if(SZIP_INCLUDE_DIR) - _SZIP_get_version() -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(SZIP - REQUIRED_VARS SZIP_LIBRARY SZIP_INCLUDE_DIR - VERSION_VAR SZIP_VERSION) - -# Set up the appropriate import target -if(SZIP_FOUND) - set(SZIP_LIBRARIES ${SZIP_LIBRARY}) - set(SZIP_INCLUDE_DIRS ${SZIP_INCLUDE_DIR}) - if(NOT TARGET SZIP::SZIP) - add_library(SZIP::SZIP UNKNOWN IMPORTED) - set_target_properties(SZIP::SZIP PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES ${SZIP_INCLUDE_DIR}) - if(SZIP_VERSION) - set_target_properties(SZIP::SZIP PROPERTIES - VERSION ${SZIP_VERSION}) - endif() - if(SZIP_LIBRARY_RELEASE) - set_target_properties(SZIP::SZIP PROPERTIES - IMPORTED_LOCATION_RELEASE ${SZIP_LIBRARY_RELEASE}) - endif() - if(SZIP_LIBRARY_DEBUG) - set_target_properties(SZIP::SZIP PROPERTIES - IMPORTED_LOCATION_DEBUG ${SZIP_LIBRARY_DEBUG}) - endif() - endif() -endif() ----------------------------------------------------------------------- Summary of changes: Modules/FindSZIP.cmake | 128 ------------------------------------------------ 1 file changed, 128 deletions(-) delete mode 100644 Modules/FindSZIP.cmake hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:42:37 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:42:37 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1086-g636110a Message-ID: <20160803134237.D6053F38D6@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 636110ae1f022f80fba39365240e1153b8633332 (commit) via 41a8b8826b8977446cf5a95b77c59949674ab63a (commit) from d2594605c46f3f388b9a13f9cea69ca774fa0f78 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=636110ae1f022f80fba39365240e1153b8633332 commit 636110ae1f022f80fba39365240e1153b8633332 Merge: d259460 41a8b88 Author: Brad King AuthorDate: Wed Aug 3 09:42:36 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:42:36 2016 -0400 Merge topic 'extra-generator-factories' into next 41a8b882 fixup! Refactor extra generator registration to use factories https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=41a8b8826b8977446cf5a95b77c59949674ab63a commit 41a8b8826b8977446cf5a95b77c59949674ab63a Author: Brad King AuthorDate: Wed Aug 3 09:41:58 2016 -0400 Commit: Brad King CommitDate: Wed Aug 3 09:41:58 2016 -0400 fixup! Refactor extra generator registration to use factories diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index a846643..3a9bb9b 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -42,7 +42,7 @@ cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator() } cmExternalMakefileProjectGeneratorFactory* -cmExtraCodeBlocksGenerator::NewFactory() +cmExtraCodeBlocksGenerator::GetFactory() { static cmExternalMakefileProjectGeneratorSimpleFactory< cmExtraCodeBlocksGenerator> diff --git a/Source/cmExtraCodeBlocksGenerator.h b/Source/cmExtraCodeBlocksGenerator.h index 55e21c6..b39080c 100644 --- a/Source/cmExtraCodeBlocksGenerator.h +++ b/Source/cmExtraCodeBlocksGenerator.h @@ -28,7 +28,7 @@ class cmExtraCodeBlocksGenerator : public cmExternalMakefileProjectGenerator public: cmExtraCodeBlocksGenerator(); - static cmExternalMakefileProjectGeneratorFactory* NewFactory(); + static cmExternalMakefileProjectGeneratorFactory* GetFactory(); void Generate() CM_OVERRIDE; diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx index 2bb6ff4..eda6867 100644 --- a/Source/cmExtraCodeLiteGenerator.cxx +++ b/Source/cmExtraCodeLiteGenerator.cxx @@ -35,7 +35,7 @@ cmExtraCodeLiteGenerator::cmExtraCodeLiteGenerator() } cmExternalMakefileProjectGeneratorFactory* -cmExtraCodeLiteGenerator::NewFactory() +cmExtraCodeLiteGenerator::GetFactory() { static cmExternalMakefileProjectGeneratorSimpleFactory< cmExtraCodeLiteGenerator> diff --git a/Source/cmExtraCodeLiteGenerator.h b/Source/cmExtraCodeLiteGenerator.h index 9eb0fb3..e20e745 100644 --- a/Source/cmExtraCodeLiteGenerator.h +++ b/Source/cmExtraCodeLiteGenerator.h @@ -36,7 +36,7 @@ protected: public: cmExtraCodeLiteGenerator(); - static cmExternalMakefileProjectGeneratorFactory* NewFactory(); + static cmExternalMakefileProjectGeneratorFactory* GetFactory(); void Generate() CM_OVERRIDE; void CreateProjectFile(const std::vector& lgs); diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index b26c4d0..8091bcf 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -55,7 +55,7 @@ cmExtraEclipseCDT4Generator::cmExtraEclipseCDT4Generator() } cmExternalMakefileProjectGeneratorFactory* -cmExtraEclipseCDT4Generator::NewFactory() +cmExtraEclipseCDT4Generator::GetFactory() { static cmExternalMakefileProjectGeneratorSimpleFactory< cmExtraEclipseCDT4Generator> diff --git a/Source/cmExtraEclipseCDT4Generator.h b/Source/cmExtraEclipseCDT4Generator.h index d1c4684..4b585c3 100644 --- a/Source/cmExtraEclipseCDT4Generator.h +++ b/Source/cmExtraEclipseCDT4Generator.h @@ -35,7 +35,7 @@ public: cmExtraEclipseCDT4Generator(); - static cmExternalMakefileProjectGeneratorFactory* NewFactory(); + static cmExternalMakefileProjectGeneratorFactory* GetFactory(); void EnableLanguage(std::vector const& languages, cmMakefile*, bool optional) CM_OVERRIDE; diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx index 8cc2b5e..4e72504 100644 --- a/Source/cmExtraKateGenerator.cxx +++ b/Source/cmExtraKateGenerator.cxx @@ -27,7 +27,7 @@ cmExtraKateGenerator::cmExtraKateGenerator() { } -cmExternalMakefileProjectGeneratorFactory* cmExtraKateGenerator::NewFactory() +cmExternalMakefileProjectGeneratorFactory* cmExtraKateGenerator::GetFactory() { static cmExternalMakefileProjectGeneratorSimpleFactory factory("Kate", "Generates Kate project files."); diff --git a/Source/cmExtraKateGenerator.h b/Source/cmExtraKateGenerator.h index 1ac1c30..3d16052 100644 --- a/Source/cmExtraKateGenerator.h +++ b/Source/cmExtraKateGenerator.h @@ -26,7 +26,7 @@ class cmExtraKateGenerator : public cmExternalMakefileProjectGenerator public: cmExtraKateGenerator(); - static cmExternalMakefileProjectGeneratorFactory* NewFactory(); + static cmExternalMakefileProjectGeneratorFactory* GetFactory(); void Generate() CM_OVERRIDE; diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index 3e1a48e..b6bad60 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -39,7 +39,7 @@ http://sublimetext.info/docs/en/reference/build_systems.html */ cmExternalMakefileProjectGeneratorFactory* -cmExtraSublimeTextGenerator::NewFactory() +cmExtraSublimeTextGenerator::GetFactory() { static cmExternalMakefileProjectGeneratorSimpleFactory< cmExtraSublimeTextGenerator> diff --git a/Source/cmExtraSublimeTextGenerator.h b/Source/cmExtraSublimeTextGenerator.h index ea710d9..c087825 100644 --- a/Source/cmExtraSublimeTextGenerator.h +++ b/Source/cmExtraSublimeTextGenerator.h @@ -27,7 +27,7 @@ class cmGeneratorTarget; class cmExtraSublimeTextGenerator : public cmExternalMakefileProjectGenerator { public: - static cmExternalMakefileProjectGeneratorFactory* NewFactory(); + static cmExternalMakefileProjectGeneratorFactory* GetFactory(); typedef std::map > MapSourceFileFlags; cmExtraSublimeTextGenerator(); diff --git a/Source/cmGlobalKdevelopGenerator.cxx b/Source/cmGlobalKdevelopGenerator.cxx index b272084..daf7003 100644 --- a/Source/cmGlobalKdevelopGenerator.cxx +++ b/Source/cmGlobalKdevelopGenerator.cxx @@ -31,7 +31,7 @@ cmGlobalKdevelopGenerator::cmGlobalKdevelopGenerator() } cmExternalMakefileProjectGeneratorFactory* -cmGlobalKdevelopGenerator::NewFactory() +cmGlobalKdevelopGenerator::GetFactory() { static cmExternalMakefileProjectGeneratorSimpleFactory< cmGlobalKdevelopGenerator> diff --git a/Source/cmGlobalKdevelopGenerator.h b/Source/cmGlobalKdevelopGenerator.h index a7d77a9..666527c 100644 --- a/Source/cmGlobalKdevelopGenerator.h +++ b/Source/cmGlobalKdevelopGenerator.h @@ -33,7 +33,7 @@ class cmGlobalKdevelopGenerator : public cmExternalMakefileProjectGenerator public: cmGlobalKdevelopGenerator(); - static cmExternalMakefileProjectGeneratorFactory* NewFactory(); + static cmExternalMakefileProjectGeneratorFactory* GetFactory(); void Generate() CM_OVERRIDE; diff --git a/Source/cmake.cxx b/Source/cmake.cxx index fb0fac1..b11f4f6 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -796,17 +796,17 @@ int cmake::AddCMakePaths() void cmake::AddDefaultExtraGenerators() { #if defined(CMAKE_BUILD_WITH_CMAKE) - this->ExtraGenerators.push_back(cmExtraCodeBlocksGenerator::NewFactory()); - this->ExtraGenerators.push_back(cmExtraCodeLiteGenerator::NewFactory()); - this->ExtraGenerators.push_back(cmExtraSublimeTextGenerator::NewFactory()); - this->ExtraGenerators.push_back(cmExtraKateGenerator::NewFactory()); + this->ExtraGenerators.push_back(cmExtraCodeBlocksGenerator::GetFactory()); + this->ExtraGenerators.push_back(cmExtraCodeLiteGenerator::GetFactory()); + this->ExtraGenerators.push_back(cmExtraSublimeTextGenerator::GetFactory()); + this->ExtraGenerators.push_back(cmExtraKateGenerator::GetFactory()); #ifdef CMAKE_USE_ECLIPSE - this->ExtraGenerators.push_back(cmExtraEclipseCDT4Generator::NewFactory()); + this->ExtraGenerators.push_back(cmExtraEclipseCDT4Generator::GetFactory()); #endif #ifdef CMAKE_USE_KDEVELOP - this->ExtraGenerators.push_back(cmGlobalKdevelopGenerator::NewFactory()); + this->ExtraGenerators.push_back(cmGlobalKdevelopGenerator::GetFactory()); #endif #endif } ----------------------------------------------------------------------- Summary of changes: Source/cmExtraCodeBlocksGenerator.cxx | 2 +- Source/cmExtraCodeBlocksGenerator.h | 2 +- Source/cmExtraCodeLiteGenerator.cxx | 2 +- Source/cmExtraCodeLiteGenerator.h | 2 +- Source/cmExtraEclipseCDT4Generator.cxx | 2 +- Source/cmExtraEclipseCDT4Generator.h | 2 +- Source/cmExtraKateGenerator.cxx | 2 +- Source/cmExtraKateGenerator.h | 2 +- Source/cmExtraSublimeTextGenerator.cxx | 2 +- Source/cmExtraSublimeTextGenerator.h | 2 +- Source/cmGlobalKdevelopGenerator.cxx | 2 +- Source/cmGlobalKdevelopGenerator.h | 2 +- Source/cmake.cxx | 12 ++++++------ 13 files changed, 18 insertions(+), 18 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 09:45:04 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 09:45:04 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1089-g7b960cc Message-ID: <20160803134505.012C1F4314@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 7b960cc5502785e6bf4e7e0a4d166c71330bda55 (commit) via cd52a225d298dc1a4924b82ebac0ac74fccf3356 (commit) via a354f60ce07cd67bd60161824a4e74bf9068fea4 (commit) from 636110ae1f022f80fba39365240e1153b8633332 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7b960cc5502785e6bf4e7e0a4d166c71330bda55 commit 7b960cc5502785e6bf4e7e0a4d166c71330bda55 Merge: 636110a cd52a22 Author: Brad King AuthorDate: Wed Aug 3 09:45:03 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 09:45:03 2016 -0400 Merge topic 'extra-generator-factories' into next cd52a225 Report more information about extra generators in generator factories a354f60c Refactor extra generator registration to use factories https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cd52a225d298dc1a4924b82ebac0ac74fccf3356 commit cd52a225d298dc1a4924b82ebac0ac74fccf3356 Author: Tobias Hunger AuthorDate: Thu Jul 21 13:24:11 2016 +0200 Commit: Brad King CommitDate: Wed Aug 3 09:44:40 2016 -0400 Report more information about extra generators in generator factories diff --git a/Source/cmake.cxx b/Source/cmake.cxx index fb77043..b11f4f6 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -824,6 +824,7 @@ void cmake::GetRegisteredGenerators(std::vector& generators) info.supportsToolset = (*i)->SupportsToolset(); info.supportsPlatform = (*i)->SupportsPlatform(); info.name = names[j]; + info.baseName = names[j]; info.isAlias = false; generators.push_back(info); } @@ -840,6 +841,8 @@ void cmake::GetRegisteredGenerators(std::vector& generators) GeneratorInfo info; info.name = cmExternalMakefileProjectGenerator::CreateFullGeneratorName( (*i)->GetName(), *gen); + info.baseName = *gen; + info.extraName = (*i)->GetName(); info.supportsPlatform = false; info.supportsToolset = false; info.isAlias = false; @@ -849,6 +852,10 @@ void cmake::GetRegisteredGenerators(std::vector& generators) a != (*i)->Aliases.end(); ++a) { GeneratorInfo info; info.name = *a; + if (!genList.empty()) { + info.baseName = genList.at(0); + } + info.extraName = (*i)->GetName(); info.supportsPlatform = false; info.supportsToolset = false; info.isAlias = true; diff --git a/Source/cmake.h b/Source/cmake.h index 0fd2d31..304a15d 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -103,6 +103,8 @@ public: struct GeneratorInfo { std::string name; + std::string baseName; + std::string extraName; bool supportsToolset; bool supportsPlatform; bool isAlias; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a354f60ce07cd67bd60161824a4e74bf9068fea4 commit a354f60ce07cd67bd60161824a4e74bf9068fea4 Author: Tobias Hunger AuthorDate: Wed Jul 20 18:28:39 2016 +0200 Commit: Brad King CommitDate: Wed Aug 3 09:43:00 2016 -0400 Refactor extra generator registration to use factories This will allow additional information about the availability and capabilities of extra generators to be queried without actually creating them. Instead of a static NewFactory() method like the main generator factories have, use a static GetFactory() method to get a pointer to a statically allocated extra generator factory. This simplifies memory management. diff --git a/Source/cmExternalMakefileProjectGenerator.cxx b/Source/cmExternalMakefileProjectGenerator.cxx index 0e42d75..a527e50 100644 --- a/Source/cmExternalMakefileProjectGenerator.cxx +++ b/Source/cmExternalMakefileProjectGenerator.cxx @@ -33,28 +33,37 @@ std::string cmExternalMakefileProjectGenerator::CreateFullGeneratorName( return fullName; } -std::string cmExternalMakefileProjectGenerator::GetGlobalGeneratorName( - const std::string& fullName) +cmExternalMakefileProjectGeneratorFactory:: + cmExternalMakefileProjectGeneratorFactory(const std::string& n, + const std::string& doc) + : Name(n) + , Documentation(doc) { - // at least one global generator must be supported - assert(!this->SupportedGlobalGenerators.empty()); +} - if (fullName.empty()) { - return ""; - } +cmExternalMakefileProjectGeneratorFactory:: + ~cmExternalMakefileProjectGeneratorFactory() +{ +} - // if we get only the short name, take the first global generator as default - if (fullName == this->GetName()) { - return this->SupportedGlobalGenerators[0]; - } +std::string cmExternalMakefileProjectGeneratorFactory::GetName() const +{ + return this->Name; +} - // otherwise search for the matching global generator - for (std::vector::const_iterator it = - this->SupportedGlobalGenerators.begin(); - it != this->SupportedGlobalGenerators.end(); ++it) { - if (this->CreateFullGeneratorName(*it, this->GetName()) == fullName) { - return *it; - } - } - return ""; +std::string cmExternalMakefileProjectGeneratorFactory::GetDocumentation() const +{ + return this->Documentation; +} + +std::vector +cmExternalMakefileProjectGeneratorFactory::GetSupportedGlobalGenerators() const +{ + return this->SupportedGlobalGenerators; +} + +void cmExternalMakefileProjectGeneratorFactory::AddSupportedGlobalGenerator( + const std::string& base) +{ + this->SupportedGlobalGenerators.push_back(base); } diff --git a/Source/cmExternalMakefileProjectGenerator.h b/Source/cmExternalMakefileProjectGenerator.h index 5d4d54d..6ae5533 100644 --- a/Source/cmExternalMakefileProjectGenerator.h +++ b/Source/cmExternalMakefileProjectGenerator.h @@ -35,11 +35,6 @@ class cmExternalMakefileProjectGenerator public: virtual ~cmExternalMakefileProjectGenerator() {} - ///! Get the name for this generator. - virtual std::string GetName() const = 0; - /** Get the documentation entry for this generator. */ - virtual void GetDocumentation(cmDocumentationEntry& entry, - const std::string& fullName) const = 0; virtual void EnableLanguage(std::vector const& languages, cmMakefile*, bool optional); @@ -55,8 +50,6 @@ public: return this->SupportedGlobalGenerators; } - ///! Get the name of the global generator for the given full name - std::string GetGlobalGeneratorName(const std::string& fullName); /** Create a full name from the given global generator name and the * extra generator name */ @@ -66,11 +59,59 @@ public: ///! Generate the project files, the Makefiles have already been generated virtual void Generate() = 0; + void SetName(const std::string& n) { Name = n; } + std::string GetName() const { return Name; } + protected: ///! Contains the names of the global generators support by this generator. std::vector SupportedGlobalGenerators; ///! the global generator which creates the makefiles const cmGlobalGenerator* GlobalGenerator; + + std::string Name; +}; + +class cmExternalMakefileProjectGeneratorFactory +{ +public: + cmExternalMakefileProjectGeneratorFactory(const std::string& n, + const std::string& doc); + virtual ~cmExternalMakefileProjectGeneratorFactory(); + + std::string GetName() const; + std::string GetDocumentation() const; + std::vector GetSupportedGlobalGenerators() const; + std::vector Aliases; + + virtual cmExternalMakefileProjectGenerator* + CreateExternalMakefileProjectGenerator() const = 0; + + void AddSupportedGlobalGenerator(const std::string& base); + +private: + std::string Name; + std::string Documentation; + std::vector SupportedGlobalGenerators; +}; + +template +class cmExternalMakefileProjectGeneratorSimpleFactory + : public cmExternalMakefileProjectGeneratorFactory +{ +public: + cmExternalMakefileProjectGeneratorSimpleFactory(const std::string& n, + const std::string& doc) + : cmExternalMakefileProjectGeneratorFactory(n, doc) + { + } + + cmExternalMakefileProjectGenerator* CreateExternalMakefileProjectGenerator() + const + { + T* p = new T; + p->SetName(GetName()); + return p; + } }; #endif diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index fbfbccc..3a9bb9b 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -36,24 +36,30 @@ Discussion: http://forums.codeblocks.org/index.php/topic,6789.0.html */ -void cmExtraCodeBlocksGenerator::GetDocumentation(cmDocumentationEntry& entry, - const std::string&) const +cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator() + : cmExternalMakefileProjectGenerator() { - entry.Name = this->GetName(); - entry.Brief = "Generates CodeBlocks project files."; } -cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator() - : cmExternalMakefileProjectGenerator() +cmExternalMakefileProjectGeneratorFactory* +cmExtraCodeBlocksGenerator::GetFactory() { + static cmExternalMakefileProjectGeneratorSimpleFactory< + cmExtraCodeBlocksGenerator> + factory("CodeBlocks", "Generates CodeBlocks project files."); + + if (factory.GetSupportedGlobalGenerators().empty()) { #if defined(_WIN32) - this->SupportedGlobalGenerators.push_back("MinGW Makefiles"); - this->SupportedGlobalGenerators.push_back("NMake Makefiles"); + factory.AddSupportedGlobalGenerator("MinGW Makefiles"); + factory.AddSupportedGlobalGenerator("NMake Makefiles"); // disable until somebody actually tests it: -// this->SupportedGlobalGenerators.push_back("MSYS Makefiles"); +// this->AddSupportedGlobalGenerator("MSYS Makefiles"); #endif - this->SupportedGlobalGenerators.push_back("Ninja"); - this->SupportedGlobalGenerators.push_back("Unix Makefiles"); + factory.AddSupportedGlobalGenerator("Ninja"); + factory.AddSupportedGlobalGenerator("Unix Makefiles"); + } + + return &factory; } void cmExtraCodeBlocksGenerator::Generate() diff --git a/Source/cmExtraCodeBlocksGenerator.h b/Source/cmExtraCodeBlocksGenerator.h index 31ea500..b39080c 100644 --- a/Source/cmExtraCodeBlocksGenerator.h +++ b/Source/cmExtraCodeBlocksGenerator.h @@ -28,18 +28,7 @@ class cmExtraCodeBlocksGenerator : public cmExternalMakefileProjectGenerator public: cmExtraCodeBlocksGenerator(); - std::string GetName() const CM_OVERRIDE - { - return cmExtraCodeBlocksGenerator::GetActualName(); - } - static std::string GetActualName() { return "CodeBlocks"; } - static cmExternalMakefileProjectGenerator* New() - { - return new cmExtraCodeBlocksGenerator; - } - /** Get the documentation entry for this generator. */ - void GetDocumentation(cmDocumentationEntry& entry, - const std::string& fullName) const CM_OVERRIDE; + static cmExternalMakefileProjectGeneratorFactory* GetFactory(); void Generate() CM_OVERRIDE; diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx index dd10b65..eda6867 100644 --- a/Source/cmExtraCodeLiteGenerator.cxx +++ b/Source/cmExtraCodeLiteGenerator.cxx @@ -27,24 +27,30 @@ #include #include -void cmExtraCodeLiteGenerator::GetDocumentation(cmDocumentationEntry& entry, - const std::string&) const -{ - entry.Name = this->GetName(); - entry.Brief = "Generates CodeLite project files."; -} - cmExtraCodeLiteGenerator::cmExtraCodeLiteGenerator() : cmExternalMakefileProjectGenerator() , ConfigName("NoConfig") , CpuCount(2) { +} + +cmExternalMakefileProjectGeneratorFactory* +cmExtraCodeLiteGenerator::GetFactory() +{ + static cmExternalMakefileProjectGeneratorSimpleFactory< + cmExtraCodeLiteGenerator> + factory("CodeLite", "Generates CodeLite project files."); + + if (factory.GetSupportedGlobalGenerators().empty()) { #if defined(_WIN32) - this->SupportedGlobalGenerators.push_back("MinGW Makefiles"); - this->SupportedGlobalGenerators.push_back("NMake Makefiles"); + factory.AddSupportedGlobalGenerator("MinGW Makefiles"); + factory.AddSupportedGlobalGenerator("NMake Makefiles"); #endif - this->SupportedGlobalGenerators.push_back("Ninja"); - this->SupportedGlobalGenerators.push_back("Unix Makefiles"); + factory.AddSupportedGlobalGenerator("Ninja"); + factory.AddSupportedGlobalGenerator("Unix Makefiles"); + } + + return &factory; } void cmExtraCodeLiteGenerator::Generate() diff --git a/Source/cmExtraCodeLiteGenerator.h b/Source/cmExtraCodeLiteGenerator.h index f2ee85c..e20e745 100644 --- a/Source/cmExtraCodeLiteGenerator.h +++ b/Source/cmExtraCodeLiteGenerator.h @@ -36,18 +36,7 @@ protected: public: cmExtraCodeLiteGenerator(); - std::string GetName() const CM_OVERRIDE - { - return cmExtraCodeLiteGenerator::GetActualName(); - } - static std::string GetActualName() { return "CodeLite"; } - static cmExternalMakefileProjectGenerator* New() - { - return new cmExtraCodeLiteGenerator; - } - /** Get the documentation entry for this generator. */ - void GetDocumentation(cmDocumentationEntry& entry, - const std::string& fullName) const CM_OVERRIDE; + static cmExternalMakefileProjectGeneratorFactory* GetFactory(); void Generate() CM_OVERRIDE; void CreateProjectFile(const std::vector& lgs); diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index 93c55cc..8091bcf 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -46,16 +46,6 @@ void AppendDictionary(cmXMLWriter& xml, const char* key, T const& value) cmExtraEclipseCDT4Generator::cmExtraEclipseCDT4Generator() : cmExternalMakefileProjectGenerator() { -// TODO: Verify if __CYGWIN__ should be checked. -//#if defined(_WIN32) && !defined(__CYGWIN__) -#if defined(_WIN32) - this->SupportedGlobalGenerators.push_back("NMake Makefiles"); - this->SupportedGlobalGenerators.push_back("MinGW Makefiles"); -// this->SupportedGlobalGenerators.push_back("MSYS Makefiles"); -#endif - this->SupportedGlobalGenerators.push_back("Ninja"); - this->SupportedGlobalGenerators.push_back("Unix Makefiles"); - this->SupportsVirtualFolders = true; this->GenerateLinkedResources = true; this->SupportsGmakeErrorParser = true; @@ -64,11 +54,26 @@ cmExtraEclipseCDT4Generator::cmExtraEclipseCDT4Generator() this->CXXEnabled = false; } -void cmExtraEclipseCDT4Generator::GetDocumentation(cmDocumentationEntry& entry, - const std::string&) const +cmExternalMakefileProjectGeneratorFactory* +cmExtraEclipseCDT4Generator::GetFactory() { - entry.Name = this->GetName(); - entry.Brief = "Generates Eclipse CDT 4.0 project files."; + static cmExternalMakefileProjectGeneratorSimpleFactory< + cmExtraEclipseCDT4Generator> + factory("Eclipse CDT4", "Generates Eclipse CDT 4.0 project files."); + + if (factory.GetSupportedGlobalGenerators().empty()) { +// TODO: Verify if __CYGWIN__ should be checked. +//#if defined(_WIN32) && !defined(__CYGWIN__) +#if defined(_WIN32) + factory.AddSupportedGlobalGenerator("NMake Makefiles"); + factory.AddSupportedGlobalGenerator("MinGW Makefiles"); +// factory.AddSupportedGlobalGenerator("MSYS Makefiles"); +#endif + factory.AddSupportedGlobalGenerator("Ninja"); + factory.AddSupportedGlobalGenerator("Unix Makefiles"); + } + + return &factory; } void cmExtraEclipseCDT4Generator::EnableLanguage( diff --git a/Source/cmExtraEclipseCDT4Generator.h b/Source/cmExtraEclipseCDT4Generator.h index 0400ad5..4b585c3 100644 --- a/Source/cmExtraEclipseCDT4Generator.h +++ b/Source/cmExtraEclipseCDT4Generator.h @@ -35,20 +35,8 @@ public: cmExtraEclipseCDT4Generator(); - static cmExternalMakefileProjectGenerator* New() - { - return new cmExtraEclipseCDT4Generator; - } - - std::string GetName() const CM_OVERRIDE - { - return cmExtraEclipseCDT4Generator::GetActualName(); - } - - static std::string GetActualName() { return "Eclipse CDT4"; } + static cmExternalMakefileProjectGeneratorFactory* GetFactory(); - void GetDocumentation(cmDocumentationEntry& entry, - const std::string& fullName) const CM_OVERRIDE; void EnableLanguage(std::vector const& languages, cmMakefile*, bool optional) CM_OVERRIDE; diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx index b757a49..4e72504 100644 --- a/Source/cmExtraKateGenerator.cxx +++ b/Source/cmExtraKateGenerator.cxx @@ -22,24 +22,28 @@ #include -void cmExtraKateGenerator::GetDocumentation(cmDocumentationEntry& entry, - const std::string&) const +cmExtraKateGenerator::cmExtraKateGenerator() + : cmExternalMakefileProjectGenerator() { - entry.Name = this->GetName(); - entry.Brief = "Generates Kate project files."; } -cmExtraKateGenerator::cmExtraKateGenerator() - : cmExternalMakefileProjectGenerator() +cmExternalMakefileProjectGeneratorFactory* cmExtraKateGenerator::GetFactory() { + static cmExternalMakefileProjectGeneratorSimpleFactory + factory("Kate", "Generates Kate project files."); + + if (factory.GetSupportedGlobalGenerators().empty()) { #if defined(_WIN32) - this->SupportedGlobalGenerators.push_back("MinGW Makefiles"); - this->SupportedGlobalGenerators.push_back("NMake Makefiles"); + factory.AddSupportedGlobalGenerator("MinGW Makefiles"); + factory.AddSupportedGlobalGenerator("NMake Makefiles"); // disable until somebody actually tests it: -// this->SupportedGlobalGenerators.push_back("MSYS Makefiles"); +// factory.AddSupportedGlobalGenerator("MSYS Makefiles"); #endif - this->SupportedGlobalGenerators.push_back("Ninja"); - this->SupportedGlobalGenerators.push_back("Unix Makefiles"); + factory.AddSupportedGlobalGenerator("Ninja"); + factory.AddSupportedGlobalGenerator("Unix Makefiles"); + } + + return &factory; } void cmExtraKateGenerator::Generate() diff --git a/Source/cmExtraKateGenerator.h b/Source/cmExtraKateGenerator.h index 410d552..3d16052 100644 --- a/Source/cmExtraKateGenerator.h +++ b/Source/cmExtraKateGenerator.h @@ -26,18 +26,7 @@ class cmExtraKateGenerator : public cmExternalMakefileProjectGenerator public: cmExtraKateGenerator(); - std::string GetName() const CM_OVERRIDE - { - return cmExtraKateGenerator::GetActualName(); - } - static std::string GetActualName() { return "Kate"; } - static cmExternalMakefileProjectGenerator* New() - { - return new cmExtraKateGenerator; - } - /** Get the documentation entry for this generator. */ - void GetDocumentation(cmDocumentationEntry& entry, - const std::string& fullName) const CM_OVERRIDE; + static cmExternalMakefileProjectGeneratorFactory* GetFactory(); void Generate() CM_OVERRIDE; diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index c166e26..b6bad60 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -38,24 +38,30 @@ http://www.sublimetext.com/docs/2/projects.html http://sublimetext.info/docs/en/reference/build_systems.html */ -void cmExtraSublimeTextGenerator::GetDocumentation(cmDocumentationEntry& entry, - const std::string&) const +cmExternalMakefileProjectGeneratorFactory* +cmExtraSublimeTextGenerator::GetFactory() { - entry.Name = this->GetName(); - entry.Brief = "Generates Sublime Text 2 project files."; + static cmExternalMakefileProjectGeneratorSimpleFactory< + cmExtraSublimeTextGenerator> + factory("Sublime Text 2", "Generates Sublime Text 2 project files."); + + if (factory.GetSupportedGlobalGenerators().empty()) { +#if defined(_WIN32) + factory.AddSupportedGlobalGenerator("MinGW Makefiles"); + factory.AddSupportedGlobalGenerator("NMake Makefiles"); +// disable until somebody actually tests it: +// factory.AddSupportedGlobalGenerator("MSYS Makefiles"); +#endif + factory.AddSupportedGlobalGenerator("Ninja"); + factory.AddSupportedGlobalGenerator("Unix Makefiles"); + } + + return &factory; } cmExtraSublimeTextGenerator::cmExtraSublimeTextGenerator() : cmExternalMakefileProjectGenerator() { -#if defined(_WIN32) - this->SupportedGlobalGenerators.push_back("MinGW Makefiles"); - this->SupportedGlobalGenerators.push_back("NMake Makefiles"); -// disable until somebody actually tests it: -// this->SupportedGlobalGenerators.push_back("MSYS Makefiles"); -#endif - this->SupportedGlobalGenerators.push_back("Ninja"); - this->SupportedGlobalGenerators.push_back("Unix Makefiles"); } void cmExtraSublimeTextGenerator::Generate() diff --git a/Source/cmExtraSublimeTextGenerator.h b/Source/cmExtraSublimeTextGenerator.h index 26dd138..c087825 100644 --- a/Source/cmExtraSublimeTextGenerator.h +++ b/Source/cmExtraSublimeTextGenerator.h @@ -27,22 +27,10 @@ class cmGeneratorTarget; class cmExtraSublimeTextGenerator : public cmExternalMakefileProjectGenerator { public: + static cmExternalMakefileProjectGeneratorFactory* GetFactory(); typedef std::map > MapSourceFileFlags; cmExtraSublimeTextGenerator(); - std::string GetName() const CM_OVERRIDE - { - return cmExtraSublimeTextGenerator::GetActualName(); - } - static std::string GetActualName() { return "Sublime Text 2"; } - static cmExternalMakefileProjectGenerator* New() - { - return new cmExtraSublimeTextGenerator; - } - /** Get the documentation entry for this generator. */ - void GetDocumentation(cmDocumentationEntry& entry, - const std::string& fullName) const CM_OVERRIDE; - void Generate() CM_OVERRIDE; private: diff --git a/Source/cmGlobalKdevelopGenerator.cxx b/Source/cmGlobalKdevelopGenerator.cxx index bbd6baa..daf7003 100644 --- a/Source/cmGlobalKdevelopGenerator.cxx +++ b/Source/cmGlobalKdevelopGenerator.cxx @@ -25,20 +25,28 @@ #include #include -void cmGlobalKdevelopGenerator::GetDocumentation(cmDocumentationEntry& entry, - const std::string&) const +cmGlobalKdevelopGenerator::cmGlobalKdevelopGenerator() + : cmExternalMakefileProjectGenerator() { - entry.Name = this->GetName(); - entry.Brief = "Generates KDevelop 3 project files."; } -cmGlobalKdevelopGenerator::cmGlobalKdevelopGenerator() - : cmExternalMakefileProjectGenerator() +cmExternalMakefileProjectGeneratorFactory* +cmGlobalKdevelopGenerator::GetFactory() { - this->SupportedGlobalGenerators.push_back("Unix Makefiles"); + static cmExternalMakefileProjectGeneratorSimpleFactory< + cmGlobalKdevelopGenerator> + factory("KDevelop3", "Generates KDevelop 3 project files."); + + if (factory.GetSupportedGlobalGenerators().empty()) { + factory.AddSupportedGlobalGenerator("Unix Makefiles"); #ifdef CMAKE_USE_NINJA - this->SupportedGlobalGenerators.push_back("Ninja"); + factory.AddSupportedGlobalGenerator("Ninja"); #endif + + factory.Aliases.push_back("KDevelop3"); + } + + return &factory; } void cmGlobalKdevelopGenerator::Generate() diff --git a/Source/cmGlobalKdevelopGenerator.h b/Source/cmGlobalKdevelopGenerator.h index c61cafb..666527c 100644 --- a/Source/cmGlobalKdevelopGenerator.h +++ b/Source/cmGlobalKdevelopGenerator.h @@ -33,18 +33,7 @@ class cmGlobalKdevelopGenerator : public cmExternalMakefileProjectGenerator public: cmGlobalKdevelopGenerator(); - std::string GetName() const CM_OVERRIDE - { - return cmGlobalKdevelopGenerator::GetActualName(); - } - static std::string GetActualName() { return "KDevelop3"; } - static cmExternalMakefileProjectGenerator* New() - { - return new cmGlobalKdevelopGenerator; - } - /** Get the documentation entry for this generator. */ - void GetDocumentation(cmDocumentationEntry& entry, - const std::string& fullName) const CM_OVERRIDE; + static cmExternalMakefileProjectGeneratorFactory* GetFactory(); void Generate() CM_OVERRIDE; diff --git a/Source/cmake.cxx b/Source/cmake.cxx index cdc1284..fb77043 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -793,53 +793,21 @@ int cmake::AddCMakePaths() return 1; } -void cmake::AddExtraGenerator(const std::string& name, - CreateExtraGeneratorFunctionType newFunction) -{ - cmExternalMakefileProjectGenerator* extraGenerator = newFunction(); - const std::vector& supportedGlobalGenerators = - extraGenerator->GetSupportedGlobalGenerators(); - - for (std::vector::const_iterator it = - supportedGlobalGenerators.begin(); - it != supportedGlobalGenerators.end(); ++it) { - std::string fullName = - cmExternalMakefileProjectGenerator::CreateFullGeneratorName(*it, name); - this->ExtraGenerators[fullName] = newFunction; - } - delete extraGenerator; -} - void cmake::AddDefaultExtraGenerators() { #if defined(CMAKE_BUILD_WITH_CMAKE) -#if defined(_WIN32) && !defined(__CYGWIN__) -// e.g. kdevelop4 ? -#endif - - this->AddExtraGenerator(cmExtraCodeBlocksGenerator::GetActualName(), - &cmExtraCodeBlocksGenerator::New); - this->AddExtraGenerator(cmExtraCodeLiteGenerator::GetActualName(), - &cmExtraCodeLiteGenerator::New); - this->AddExtraGenerator(cmExtraSublimeTextGenerator::GetActualName(), - &cmExtraSublimeTextGenerator::New); - this->AddExtraGenerator(cmExtraKateGenerator::GetActualName(), - &cmExtraKateGenerator::New); + this->ExtraGenerators.push_back(cmExtraCodeBlocksGenerator::GetFactory()); + this->ExtraGenerators.push_back(cmExtraCodeLiteGenerator::GetFactory()); + this->ExtraGenerators.push_back(cmExtraSublimeTextGenerator::GetFactory()); + this->ExtraGenerators.push_back(cmExtraKateGenerator::GetFactory()); #ifdef CMAKE_USE_ECLIPSE - this->AddExtraGenerator(cmExtraEclipseCDT4Generator::GetActualName(), - &cmExtraEclipseCDT4Generator::New); + this->ExtraGenerators.push_back(cmExtraEclipseCDT4Generator::GetFactory()); #endif #ifdef CMAKE_USE_KDEVELOP - this->AddExtraGenerator(cmGlobalKdevelopGenerator::GetActualName(), - &cmGlobalKdevelopGenerator::New); - // for kdevelop also add the generator with just the name of the - // extra generator, since it was this way since cmake 2.2 - this->ExtraGenerators[cmGlobalKdevelopGenerator::GetActualName()] = - &cmGlobalKdevelopGenerator::New; + this->ExtraGenerators.push_back(cmGlobalKdevelopGenerator::GetFactory()); #endif - #endif } @@ -856,32 +824,74 @@ void cmake::GetRegisteredGenerators(std::vector& generators) info.supportsToolset = (*i)->SupportsToolset(); info.supportsPlatform = (*i)->SupportsPlatform(); info.name = names[j]; + info.isAlias = false; generators.push_back(info); } } - for (RegisteredExtraGeneratorsMap::const_iterator + for (RegisteredExtraGeneratorsVector::const_iterator i = this->ExtraGenerators.begin(), e = this->ExtraGenerators.end(); i != e; ++i) { - GeneratorInfo info; - info.name = i->first; - info.supportsToolset = false; - info.supportsPlatform = false; - generators.push_back(info); + const std::vector genList = + (*i)->GetSupportedGlobalGenerators(); + for (std::vector::const_iterator gen = genList.begin(); + gen != genList.end(); ++gen) { + GeneratorInfo info; + info.name = cmExternalMakefileProjectGenerator::CreateFullGeneratorName( + (*i)->GetName(), *gen); + info.supportsPlatform = false; + info.supportsToolset = false; + info.isAlias = false; + generators.push_back(info); + } + for (std::vector::const_iterator a = (*i)->Aliases.begin(); + a != (*i)->Aliases.end(); ++a) { + GeneratorInfo info; + info.name = *a; + info.supportsPlatform = false; + info.supportsToolset = false; + info.isAlias = true; + generators.push_back(info); + } } } -cmGlobalGenerator* cmake::CreateGlobalGenerator(const std::string& gname) +static std::pair +createExtraGenerator( + const std::vector& in, + const std::string& name) { - cmExternalMakefileProjectGenerator* extraGenerator = CM_NULLPTR; - std::string name = gname; - RegisteredExtraGeneratorsMap::const_iterator extraGenIt = - this->ExtraGenerators.find(name); - if (extraGenIt != this->ExtraGenerators.end()) { - extraGenerator = (extraGenIt->second)(); - name = extraGenerator->GetGlobalGeneratorName(name); + for (std::vector::const_iterator + i = in.begin(); + i != in.end(); ++i) { + const std::vector generators = + (*i)->GetSupportedGlobalGenerators(); + if ((*i)->GetName() == name) { // Match aliases + return std::make_pair((*i)->CreateExternalMakefileProjectGenerator(), + generators.at(0)); + } + for (std::vector::const_iterator g = generators.begin(); + g != generators.end(); ++g) { + const std::string fullName = + cmExternalMakefileProjectGenerator::CreateFullGeneratorName( + *g, (*i)->GetName()); + if (fullName == name) { + return std::make_pair((*i)->CreateExternalMakefileProjectGenerator(), + *g); + } + } } + return std::make_pair( + static_cast(CM_NULLPTR), name); +} + +cmGlobalGenerator* cmake::CreateGlobalGenerator(const std::string& gname) +{ + std::pair extra = + createExtraGenerator(this->ExtraGenerators, gname); + cmExternalMakefileProjectGenerator* extraGenerator = extra.first; + const std::string name = extra.second; cmGlobalGenerator* generator = CM_NULLPTR; for (RegisteredGeneratorsVector::const_iterator i = this->Generators.begin(); @@ -1651,15 +1661,32 @@ void cmake::GetGeneratorDocumentation(std::vector& v) (*i)->GetDocumentation(e); v.push_back(e); } - for (RegisteredExtraGeneratorsMap::const_iterator i = + for (RegisteredExtraGeneratorsVector::const_iterator i = this->ExtraGenerators.begin(); i != this->ExtraGenerators.end(); ++i) { - cmDocumentationEntry e; - cmExternalMakefileProjectGenerator* generator = (i->second)(); - generator->GetDocumentation(e, i->first); - e.Name = i->first; - delete generator; - v.push_back(e); + const std::string doc = (*i)->GetDocumentation(); + const std::string name = (*i)->GetName(); + + // Aliases: + for (std::vector::const_iterator a = (*i)->Aliases.begin(); + a != (*i)->Aliases.end(); ++a) { + cmDocumentationEntry e; + e.Name = *a; + e.Brief = doc; + v.push_back(e); + } + + // Full names: + const std::vector generators = + (*i)->GetSupportedGlobalGenerators(); + for (std::vector::const_iterator g = generators.begin(); + g != generators.end(); ++g) { + cmDocumentationEntry e; + e.Name = + cmExternalMakefileProjectGenerator::CreateFullGeneratorName(*g, name); + e.Brief = doc; + v.push_back(e); + } } } diff --git a/Source/cmake.h b/Source/cmake.h index 4ca2a80..0fd2d31 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -27,7 +27,7 @@ class cmLocalGenerator; class cmMakefile; class cmVariableWatch; class cmFileTimeComparison; -class cmExternalMakefileProjectGenerator; +class cmExternalMakefileProjectGeneratorFactory; class cmDocumentationSection; class cmTarget; class cmGeneratedFileStream; @@ -105,6 +105,7 @@ public: std::string name; bool supportsToolset; bool supportsPlatform; + bool isAlias; }; typedef std::map InstalledFilesMap; @@ -416,18 +417,14 @@ protected: void InitializeProperties(); int HandleDeleteCacheVariables(const std::string& var); - typedef cmExternalMakefileProjectGenerator* ( - *CreateExtraGeneratorFunctionType)(); - typedef std::map - RegisteredExtraGeneratorsMap; typedef std::vector RegisteredGeneratorsVector; RegisteredGeneratorsVector Generators; - RegisteredExtraGeneratorsMap ExtraGenerators; + typedef std::vector + RegisteredExtraGeneratorsVector; + RegisteredExtraGeneratorsVector ExtraGenerators; void AddDefaultCommands(); void AddDefaultGenerators(); void AddDefaultExtraGenerators(); - void AddExtraGenerator(const std::string& name, - CreateExtraGeneratorFunctionType newFunction); cmGlobalGenerator* GlobalGenerator; std::map DiagLevels; ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 10:10:54 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 10:10:54 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1092-g74da9df Message-ID: <20160803141054.EB8D4C0893@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 74da9df98805c96d2846be6c7f735aa9bd0f8030 (commit) via b602cb85c90bba26bff04d570bf108658016cf07 (commit) via 3e6ec47c421808123efac2cf67850f8b75839c67 (commit) from 7b960cc5502785e6bf4e7e0a4d166c71330bda55 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=74da9df98805c96d2846be6c7f735aa9bd0f8030 commit 74da9df98805c96d2846be6c7f735aa9bd0f8030 Merge: 7b960cc b602cb8 Author: Brad King AuthorDate: Wed Aug 3 10:10:53 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 10:10:53 2016 -0400 Merge topic 'update-kwsys' into next b602cb85 Merge branch 'upstream-KWSys' into update-kwsys 3e6ec47c KWSys 2016-08-02 (3f55579d) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b602cb85c90bba26bff04d570bf108658016cf07 commit b602cb85c90bba26bff04d570bf108658016cf07 Merge: 382c4fc 3e6ec47 Author: Brad King AuthorDate: Wed Aug 3 10:10:28 2016 -0400 Commit: Brad King CommitDate: Wed Aug 3 10:10:28 2016 -0400 Merge branch 'upstream-KWSys' into update-kwsys * upstream-KWSys: KWSys 2016-08-02 (3f55579d) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3e6ec47c421808123efac2cf67850f8b75839c67 commit 3e6ec47c421808123efac2cf67850f8b75839c67 Author: KWSys Upstream AuthorDate: Tue Aug 2 09:52:06 2016 -0400 Commit: Brad King CommitDate: Wed Aug 3 10:10:21 2016 -0400 KWSys 2016-08-02 (3f55579d) Code extracted from: http://public.kitware.com/KWSys.git at commit 3f55579d113f92fcda8f9eff7046c36873c121f6 (master). Upstream Shortlog ----------------- Patrick Welche (3): 8a989b44 SystemInformation: Treat BSDs more uniformly 2ce319a6 SystemInformation: Treat Solaris the same as Linux 3f55579d SystemTools: Fix FileExists for some SCO OpenServer file permissions diff --git a/SystemInformation.cxx b/SystemInformation.cxx index 81fb2f9..56a635a 100644 --- a/SystemInformation.cxx +++ b/SystemInformation.cxx @@ -79,9 +79,9 @@ typedef int siginfo_t; # undef _WIN32 #endif -#ifdef __FreeBSD__ +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +# include # include -# include # include # include # include @@ -91,19 +91,10 @@ typedef int siginfo_t; # endif #endif -#if defined(__OpenBSD__) || defined(__NetBSD__) -# include -# include -#endif - #if defined(KWSYS_SYS_HAS_MACHINE_CPU_H) # include #endif -#if defined(__DragonFly__) -# include -#endif - #ifdef __APPLE__ # include # include @@ -123,7 +114,7 @@ typedef int siginfo_t; # endif #endif -#ifdef __linux +#if defined(__linux) || defined (__sun) || defined(_SCO_DS) # include # include # include diff --git a/SystemTools.cxx b/SystemTools.cxx index 9b56db0..d479ee1 100644 --- a/SystemTools.cxx +++ b/SystemTools.cxx @@ -1321,8 +1321,13 @@ bool SystemTools::FileExists(const std::string& filename) SystemTools::ConvertToWindowsExtendedPath(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 } //---------------------------------------------------------------------------- ----------------------------------------------------------------------- Summary of changes: Source/kwsys/SystemInformation.cxx | 15 +++------------ Source/kwsys/SystemTools.cxx | 5 +++++ 2 files changed, 8 insertions(+), 12 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 11:16:16 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 11:16:16 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1094-gf07f592 Message-ID: <20160803151616.A7CE8F418F@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via f07f592ef88d4db60780a737c78b2fc0aae3fec7 (commit) via ff386d1121ec52854d522d3bb9c86fab286d58ef (commit) from 74da9df98805c96d2846be6c7f735aa9bd0f8030 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f07f592ef88d4db60780a737c78b2fc0aae3fec7 commit f07f592ef88d4db60780a737c78b2fc0aae3fec7 Merge: 74da9df ff386d1 Author: Brad King AuthorDate: Wed Aug 3 11:16:15 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 11:16:15 2016 -0400 Merge topic 'find-module-imported-fallback-to-release' into next ff386d11 Modules: Make imported targets fall back to `Release` https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ff386d1121ec52854d522d3bb9c86fab286d58ef commit ff386d1121ec52854d522d3bb9c86fab286d58ef Author: Brad King AuthorDate: Wed Aug 3 11:12:01 2016 -0400 Commit: Brad King CommitDate: Wed Aug 3 11:14:29 2016 -0400 Modules: Make imported targets fall back to `Release` Find modules only detect Debug and Release configurations. All other configurations will fall back to the configuration listed as the first entry in `IMPORTED_CONFIGURATIONS`. Switch the order so that `Release` is listed first, as this is a better fallback than `Debug` for the `RelWithDebInfo` and `MinSizeRel` configurations. See issue #16091. This approach is recommended by documentation in `cmake-developer(7)` added by commit v3.2.0-rc1~286^2~1 (Help: Document IMPORTED_CONFIGURATIONS target property for Find modules, 2014-12-04). diff --git a/Modules/FindGTest.cmake b/Modules/FindGTest.cmake index a7ffcfe..72032c7 100644 --- a/Modules/FindGTest.cmake +++ b/Modules/FindGTest.cmake @@ -226,13 +226,6 @@ if(GTEST_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" IMPORTED_LOCATION "${GTEST_LIBRARY}") endif() - if(EXISTS "${GTEST_LIBRARY_DEBUG}") - set_property(TARGET GTest::GTest APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(GTest::GTest PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" - IMPORTED_LOCATION_DEBUG "${GTEST_LIBRARY_DEBUG}") - endif() if(EXISTS "${GTEST_LIBRARY_RELEASE}") set_property(TARGET GTest::GTest APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) @@ -240,6 +233,13 @@ if(GTEST_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" IMPORTED_LOCATION_RELEASE "${GTEST_LIBRARY_RELEASE}") endif() + if(EXISTS "${GTEST_LIBRARY_DEBUG}") + set_property(TARGET GTest::GTest APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(GTest::GTest PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" + IMPORTED_LOCATION_DEBUG "${GTEST_LIBRARY_DEBUG}") + endif() endif() if(NOT TARGET GTest::Main) add_library(GTest::Main UNKNOWN IMPORTED) @@ -250,13 +250,6 @@ if(GTEST_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" IMPORTED_LOCATION "${GTEST_MAIN_LIBRARY}") endif() - if(EXISTS "${GTEST_MAIN_LIBRARY_DEBUG}") - set_property(TARGET GTest::Main APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(GTest::Main PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" - IMPORTED_LOCATION_DEBUG "${GTEST_MAIN_LIBRARY_DEBUG}") - endif() if(EXISTS "${GTEST_MAIN_LIBRARY_RELEASE}") set_property(TARGET GTest::Main APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) @@ -264,5 +257,12 @@ if(GTEST_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" IMPORTED_LOCATION_RELEASE "${GTEST_MAIN_LIBRARY_RELEASE}") endif() + if(EXISTS "${GTEST_MAIN_LIBRARY_DEBUG}") + set_property(TARGET GTest::Main APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(GTest::Main PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" + IMPORTED_LOCATION_DEBUG "${GTEST_MAIN_LIBRARY_DEBUG}") + endif() endif() endif() diff --git a/Modules/FindIce.cmake b/Modules/FindIce.cmake index 8f548cd..2bd39e8 100644 --- a/Modules/FindIce.cmake +++ b/Modules/FindIce.cmake @@ -466,13 +466,6 @@ if(Ice_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" IMPORTED_LOCATION "${${_Ice_component_cache}}") endif() - if(EXISTS "${${_Ice_component_cache_debug}}") - set_property(TARGET ${_Ice_imported_target} APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(${_Ice_imported_target} PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" - IMPORTED_LOCATION_DEBUG "${${_Ice_component_cache_debug}}") - endif() if(EXISTS "${${_Ice_component_cache_release}}") set_property(TARGET ${_Ice_imported_target} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) @@ -480,6 +473,13 @@ if(Ice_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" IMPORTED_LOCATION_RELEASE "${${_Ice_component_cache_release}}") endif() + if(EXISTS "${${_Ice_component_cache_debug}}") + set_property(TARGET ${_Ice_imported_target} APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(${_Ice_imported_target} PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" + IMPORTED_LOCATION_DEBUG "${${_Ice_component_cache_debug}}") + endif() endif() endif() unset(_Ice_component_upcase) diff --git a/Modules/FindOpenSSL.cmake b/Modules/FindOpenSSL.cmake index 6393f2e..10b62ff 100644 --- a/Modules/FindOpenSSL.cmake +++ b/Modules/FindOpenSSL.cmake @@ -399,13 +399,6 @@ if(OPENSSL_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES "C" IMPORTED_LOCATION "${OPENSSL_CRYPTO_LIBRARY}") endif() - if(EXISTS "${LIB_EAY_LIBRARY_DEBUG}") - set_property(TARGET OpenSSL::Crypto APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(OpenSSL::Crypto PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" - IMPORTED_LOCATION_DEBUG "${LIB_EAY_LIBRARY_DEBUG}") - endif() if(EXISTS "${LIB_EAY_LIBRARY_RELEASE}") set_property(TARGET OpenSSL::Crypto APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) @@ -413,6 +406,13 @@ if(OPENSSL_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" IMPORTED_LOCATION_RELEASE "${LIB_EAY_LIBRARY_RELEASE}") endif() + if(EXISTS "${LIB_EAY_LIBRARY_DEBUG}") + set_property(TARGET OpenSSL::Crypto APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(OpenSSL::Crypto PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" + IMPORTED_LOCATION_DEBUG "${LIB_EAY_LIBRARY_DEBUG}") + endif() endif() if(NOT TARGET OpenSSL::SSL AND (EXISTS "${OPENSSL_SSL_LIBRARY}" OR @@ -427,13 +427,6 @@ if(OPENSSL_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES "C" IMPORTED_LOCATION "${OPENSSL_SSL_LIBRARY}") endif() - if(EXISTS "${SSL_EAY_LIBRARY_DEBUG}") - set_property(TARGET OpenSSL::SSL APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(OpenSSL::SSL PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" - IMPORTED_LOCATION_DEBUG "${SSL_EAY_LIBRARY_DEBUG}") - endif() if(EXISTS "${SSL_EAY_LIBRARY_RELEASE}") set_property(TARGET OpenSSL::SSL APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) @@ -441,6 +434,13 @@ if(OPENSSL_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" IMPORTED_LOCATION_RELEASE "${SSL_EAY_LIBRARY_RELEASE}") endif() + if(EXISTS "${SSL_EAY_LIBRARY_DEBUG}") + set_property(TARGET OpenSSL::SSL APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(OpenSSL::SSL PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" + IMPORTED_LOCATION_DEBUG "${SSL_EAY_LIBRARY_DEBUG}") + endif() if(TARGET OpenSSL::Crypto) set_target_properties(OpenSSL::SSL PROPERTIES INTERFACE_LINK_LIBRARIES OpenSSL::Crypto) diff --git a/Modules/FindPNG.cmake b/Modules/FindPNG.cmake index 5050d91..d0dd870 100644 --- a/Modules/FindPNG.cmake +++ b/Modules/FindPNG.cmake @@ -126,13 +126,6 @@ if(ZLIB_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES "C" IMPORTED_LOCATION "${PNG_LIBRARY}") endif() - if(EXISTS "${PNG_LIBRARY_DEBUG}") - set_property(TARGET PNG::PNG APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(PNG::PNG PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" - IMPORTED_LOCATION_DEBUG "${PNG_LIBRARY_DEBUG}") - endif() if(EXISTS "${PNG_LIBRARY_RELEASE}") set_property(TARGET PNG::PNG APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) @@ -140,6 +133,13 @@ if(ZLIB_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" IMPORTED_LOCATION_RELEASE "${PNG_LIBRARY_RELEASE}") endif() + if(EXISTS "${PNG_LIBRARY_DEBUG}") + set_property(TARGET PNG::PNG APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(PNG::PNG PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" + IMPORTED_LOCATION_DEBUG "${PNG_LIBRARY_DEBUG}") + endif() endif() endif () diff --git a/Modules/FindTIFF.cmake b/Modules/FindTIFF.cmake index e600498..6c760db 100644 --- a/Modules/FindTIFF.cmake +++ b/Modules/FindTIFF.cmake @@ -98,13 +98,6 @@ if(TIFF_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES "C" IMPORTED_LOCATION "${TIFF_LIBRARY}") endif() - if(EXISTS "${TIFF_LIBRARY_DEBUG}") - set_property(TARGET TIFF::TIFF APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(TIFF::TIFF PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" - IMPORTED_LOCATION_DEBUG "${TIFF_LIBRARY_DEBUG}") - endif() if(EXISTS "${TIFF_LIBRARY_RELEASE}") set_property(TARGET TIFF::TIFF APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) @@ -112,6 +105,13 @@ if(TIFF_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" IMPORTED_LOCATION_RELEASE "${TIFF_LIBRARY_RELEASE}") endif() + if(EXISTS "${TIFF_LIBRARY_DEBUG}") + set_property(TARGET TIFF::TIFF APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(TIFF::TIFF PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" + IMPORTED_LOCATION_DEBUG "${TIFF_LIBRARY_DEBUG}") + endif() endif() endif() diff --git a/Modules/FindXalanC.cmake b/Modules/FindXalanC.cmake index 016b7aa..f5061d3 100644 --- a/Modules/FindXalanC.cmake +++ b/Modules/FindXalanC.cmake @@ -143,13 +143,6 @@ if(XalanC_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" IMPORTED_LOCATION "${XalanC_LIBRARY}") endif() - if(EXISTS "${XalanC_LIBRARY_DEBUG}") - set_property(TARGET XalanC::XalanC APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(XalanC::XalanC PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" - IMPORTED_LOCATION_DEBUG "${XalanC_LIBRARY_DEBUG}") - endif() if(EXISTS "${XalanC_LIBRARY_RELEASE}") set_property(TARGET XalanC::XalanC APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) @@ -157,6 +150,13 @@ if(XalanC_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" IMPORTED_LOCATION_RELEASE "${XalanC_LIBRARY_RELEASE}") endif() + if(EXISTS "${XalanC_LIBRARY_DEBUG}") + set_property(TARGET XalanC::XalanC APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(XalanC::XalanC PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" + IMPORTED_LOCATION_DEBUG "${XalanC_LIBRARY_DEBUG}") + endif() set_target_properties(XalanC::XalanC PROPERTIES INTERFACE_LINK_LIBRARIES XercesC::XercesC) endif() endif() diff --git a/Modules/FindXercesC.cmake b/Modules/FindXercesC.cmake index a4b80e5..25e79d1 100644 --- a/Modules/FindXercesC.cmake +++ b/Modules/FindXercesC.cmake @@ -122,13 +122,6 @@ if(XercesC_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" IMPORTED_LOCATION "${XercesC_LIBRARY}") endif() - if(EXISTS "${XercesC_LIBRARY_DEBUG}") - set_property(TARGET XercesC::XercesC APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(XercesC::XercesC PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" - IMPORTED_LOCATION_DEBUG "${XercesC_LIBRARY_DEBUG}") - endif() if(EXISTS "${XercesC_LIBRARY_RELEASE}") set_property(TARGET XercesC::XercesC APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) @@ -136,5 +129,12 @@ if(XercesC_FOUND) IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" IMPORTED_LOCATION_RELEASE "${XercesC_LIBRARY_RELEASE}") endif() + if(EXISTS "${XercesC_LIBRARY_DEBUG}") + set_property(TARGET XercesC::XercesC APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(XercesC::XercesC PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" + IMPORTED_LOCATION_DEBUG "${XercesC_LIBRARY_DEBUG}") + endif() endif() endif() ----------------------------------------------------------------------- Summary of changes: Modules/FindGTest.cmake | 28 ++++++++++++++-------------- Modules/FindIce.cmake | 14 +++++++------- Modules/FindOpenSSL.cmake | 28 ++++++++++++++-------------- Modules/FindPNG.cmake | 14 +++++++------- Modules/FindTIFF.cmake | 14 +++++++------- Modules/FindXalanC.cmake | 14 +++++++------- Modules/FindXercesC.cmake | 14 +++++++------- 7 files changed, 63 insertions(+), 63 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 3 15:08:44 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 3 Aug 2016 15:08:44 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1102-g13ce471 Message-ID: <20160803190844.63944F512C@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 13ce471eee787ca728646f4eec102f5ffc327efa (commit) via f59ab43370dc9bff7e6480032c95505cdd00e3cd (commit) via f53f4a8a2d215dac634effea575a27e000dfcb29 (commit) via 202adcfe056681109fe61569ecdb3bd69f0b4f97 (commit) via e1c11352f231ae310339cd539ed59cb302bd4dbe (commit) via a51c6c5394169f34480e7261ef666eb4bf898c67 (commit) via 7ec709d3d7cc988d4cf6dc2c49713d4c55f09542 (commit) via 3e9b03439f6fa16abf555f37016e0f45f2073b78 (commit) from f07f592ef88d4db60780a737c78b2fc0aae3fec7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=13ce471eee787ca728646f4eec102f5ffc327efa commit 13ce471eee787ca728646f4eec102f5ffc327efa Merge: f07f592 f59ab43 Author: Brad King AuthorDate: Wed Aug 3 15:08:31 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 3 15:08:31 2016 -0400 Merge topic 'update-curl' into next f59ab433 curl: Remove CMake-specific README f53f4a8a Merge branch 'upstream-curl' into update-curl 202adcfe curl 2016-08-03 (f2cb3a01) e1c11352 curl: Update script to get curl 7.50.1 a51c6c53 Merge branch 'upstream-curl' into update-curl 7ec709d3 curl 2015-08-11 (1a7f66a3) 3e9b0343 Add script to update curl from upstream https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f59ab43370dc9bff7e6480032c95505cdd00e3cd commit f59ab43370dc9bff7e6480032c95505cdd00e3cd Author: Brad King AuthorDate: Wed Aug 3 14:31:05 2016 -0400 Commit: Brad King CommitDate: Wed Aug 3 14:31:05 2016 -0400 curl: Remove CMake-specific README We will now manage the curl source tree updates using the `Utilities/Scripts/update-curl.bash` script. Drop the README that covered the old method. diff --git a/Utilities/cmcurl/README-CMake.txt b/Utilities/cmcurl/README-CMake.txt deleted file mode 100644 index 1e75672..0000000 --- a/Utilities/cmcurl/README-CMake.txt +++ /dev/null @@ -1,66 +0,0 @@ -The Utilities/cmcurl directory contains a reduced distribution -of the curl source tree with only the library source code and -CMake build system. It is not a submodule; the actual content is part -of our source tree and changes can be made and committed directly. - -We update from upstream using Git's "subtree" merge strategy. A -special branch contains commits of upstream curl snapshots and -nothing else. No Git ref points explicitly to the head of this -branch, but it is merged into our history. - -Update curl from upstream as follows. Create a local branch to -explicitly reference the upstream snapshot branch head: - - git branch curl-upstream 70654261 - -Use a temporary directory to checkout the branch: - - mkdir curl-tmp - cd curl-tmp - git init - git pull .. curl-upstream - rm -rf * - -Now place the (reduced) curl content in this directory. See -instructions shown by - - git log 70654261 - -for help extracting the content from the upstream repo. Then run -the following commands to commit the new version. Substitute the -appropriate date and version number: - - git add --all - - GIT_AUTHOR_NAME='Curl Upstream' \ - GIT_AUTHOR_EMAIL='curl-library at cool.haxx.se' \ - GIT_AUTHOR_DATE='Tue Aug 11 20:13:01 2015 +0200' \ - git commit -m 'curl 7.44.0 (reduced)' && - git commit --amend - -Edit the commit message to describe the procedure used to obtain the -content. Then push the changes back up to the main local repository: - - git push .. HEAD:curl-upstream - cd .. - rm -rf curl-tmp - -Create a topic in the main repository on which to perform the update: - - git checkout -b update-curl master - -Merge the curl-upstream branch as a subtree: - - git merge -s recursive -X subtree=Utilities/cmcurl \ - curl-upstream - -If there are conflicts, resolve them and commit. Build and test the -tree. Commit any additional changes needed to succeed. - -Finally, run - - git rev-parse --short=8 curl-upstream - -to get the commit from which the curl-upstream branch must be started -on the next update. Edit the "git branch curl-upstream" line above to -record it, and commit this file. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f53f4a8a2d215dac634effea575a27e000dfcb29 commit f53f4a8a2d215dac634effea575a27e000dfcb29 Merge: e1c1135 202adcf Author: Brad King AuthorDate: Wed Aug 3 14:26:53 2016 -0400 Commit: Brad King CommitDate: Wed Aug 3 14:26:53 2016 -0400 Merge branch 'upstream-curl' into update-curl * upstream-curl: curl 2016-08-03 (f2cb3a01) diff --cc Utilities/cmcurl/CMakeLists.txt index 39b70c0,0000000..9031181 mode 100644,000000..100644 --- a/Utilities/cmcurl/CMakeLists.txt +++ b/Utilities/cmcurl/CMakeLists.txt @@@ -1,1261 -1,0 +1,1267 @@@ +# Set curl options as needed for CMake build +set(BUILD_CURL_EXE OFF CACHE INTERNAL "No curl exe") - set(BUILD_CURL_TESTS OFF CACHE INTERNAL "No curl tests") +set(BUILD_DASHBOARD_REPORTS OFF CACHE INTERNAL "No curl dashboard reports") +set(BUILD_RELEASE_DEBUG_DIRS OFF CACHE INTERNAL "No curl release/debug dirs") +set(CMAKE_USE_GSSAPI OFF CACHE INTERNAL "Disable curl gssapi") +set(CMAKE_USE_LIBSSH2 OFF CACHE INTERNAL "Disable curl libssh2") +set(CMAKE_USE_OPENLDAP OFF CACHE INTERNAL "No curl OpenLDAP") +set(CURL_DISABLE_COOKIES OFF CACHE INTERNAL "Do not disable curl cookie support") +set(CURL_DISABLE_CRYPTO_AUTH OFF CACHE INTERNAL "Do not disable curl crypto auth") +set(CURL_DISABLE_DICT ON CACHE INTERNAL "Disable curl dict protocol?") +set(CURL_DISABLE_FILE OFF CACHE INTERNAL "Disable curl file protocol?") +set(CURL_DISABLE_FTP OFF CACHE INTERNAL "Disable curl ftp protocol?") +set(CURL_DISABLE_GOPHER ON CACHE INTERNAL "Disable curl gopher protocol?") +set(CURL_DISABLE_HTTP OFF CACHE INTERNAL "Disable curl http protocol?") +set(CURL_DISABLE_IMAP ON CACHE INTERNAL "Disable curl imap protocol?") +set(CURL_DISABLE_LDAP ON CACHE INTERNAL "Disable curl ldap protocol?") +set(CURL_DISABLE_LDAPS ON CACHE INTERNAL "Disable curl ldaps protocol?") +set(CURL_DISABLE_POP3 ON CACHE INTERNAL "Disable curl pop3 protocol?") +set(CURL_DISABLE_PROXY OFF CACHE INTERNAL "Do not disable curl proxy") +set(CURL_DISABLE_RTSP ON CACHE INTERNAL "Disable curl rtsp protocol?") +set(CURL_DISABLE_SMTP ON CACHE INTERNAL "Disable curl smtp protocol?") +set(CURL_DISABLE_TELNET ON CACHE INTERNAL "Disable curl telnet protocol?") +set(CURL_DISABLE_TFTP ON CACHE INTERNAL "Disable curl tftp protocol?") +set(CURL_DISABLE_VERBOSE_STRINGS OFF CACHE INTERNAL "Do not disable curl verbosity") +set(CURL_HIDDEN_SYMBOLS OFF CACHE INTERNAL "No curl hidden symbols") +set(CURL_STATICLIB ON CACHE INTERNAL "Static curl") +set(DISABLED_THREADSAFE OFF CACHE INTERNAL "Curl can use thread-safe functions") +set(ENABLE_ARES OFF CACHE INTERNAL "No curl c-ares support") +set(ENABLE_CURLDEBUG OFF CACHE INTERNAL "No curl TrackMemory features") +set(ENABLE_DEBUG OFF CACHE INTERNAL "No curl debug features") +set(ENABLE_IPV6 OFF CACHE INTERNAL "No curl IPv6 support") +set(ENABLE_MANUAL OFF CACHE INTERNAL "No curl built-in manual") +set(ENABLE_THREADED_RESOLVER OFF CACHE INTERNAL "No curl POSIX threaded DNS lookup") +set(ENABLE_UNIX_SOCKETS OFF CACHE INTERNAL "No curl Unix domain sockets support") +set(HTTP_ONLY OFF CACHE INTERNAL "Curl is not http-only") +set(USE_WIN32_LDAP OFF CACHE INTERNAL "No curl Windows LDAP") + +# Windows Vista and above have inet_pton, but this will link on +# older versions and then the executable will fail to launch at +# runtime on older versions because no DLL provides the symbol. +if(WIN32) + set(HAVE_INET_PTON 0 CACHE INTERNAL "Do not use inet_pton") +endif() + +# Starting with OSX 10.11 there is an unrelated libnetwork library which will +# be picked up during curl configuration. Linking against this library is +# unnecessary and breaks backward compatibility of the resulting binaries +# because libnetwork is unavailable on older OSX versions. +if(APPLE) + set(HAVE_LIBNETWORK 0 CACHE INTERNAL "Do not use libnetwork") +endif(APPLE) + +# Disable warnings to avoid changing 3rd party code. +if(CMAKE_C_COMPILER_ID MATCHES + "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w") +elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall") +endif() + +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms - # are also available at http://curl.haxx.se/docs/copyright.html. ++# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### +# cURL/libcurl CMake script +# by Tetetest and Sukender (Benoit Neil) + +# TODO: +# The output .so file lacks the soname number which we currently have within the lib/Makefile.am file +# Add full (4 or 5 libs) SSL support +# Add INSTALL target (EXTRA_DIST variables in Makefile.am may be moved to Makefile.inc so that CMake/CPack is aware of what's to include). +# Add CTests(?) +# Check on all possible platforms +# Test with as many configurations possible (With or without any option) +# Create scripts that help keeping the CMake build system up to date (to reduce maintenance). According to Tetetest: +# - lists of headers that 'configure' checks for; +# - curl-specific tests (the ones that are in m4/curl-*.m4 files); +# - (most obvious thing:) curl version numbers. +# Add documentation subproject +# +# To check: +# (From Daniel Stenberg) The cmake build selected to run gcc with -fPIC on my box while the plain configure script did not. +# (From Daniel Stenberg) The gcc command line use neither -g nor any -O options. As a developer, I also treasure our configure scripts's --enable-debug option that sets a long range of "picky" compiler options. +cmake_minimum_required(VERSION 2.8 FATAL_ERROR) +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") +include(Utilities) +include(Macros) + +project( CURL C ) + +if(0) # This code not needed for building within CMake. +message(WARNING "the curl cmake build system is poorly maintained. Be aware") +endif() + +file (READ ${CURL_SOURCE_DIR}/include/curl/curlver.h CURL_VERSION_H_CONTENTS) +string (REGEX MATCH "#define LIBCURL_VERSION \"[^\"]*" + CURL_VERSION ${CURL_VERSION_H_CONTENTS}) +string (REGEX REPLACE "[^\"]+\"" "" CURL_VERSION ${CURL_VERSION}) +string (REGEX MATCH "#define LIBCURL_VERSION_NUM 0x[0-9a-fA-F]+" + CURL_VERSION_NUM ${CURL_VERSION_H_CONTENTS}) +string (REGEX REPLACE "[^0]+0x" "" CURL_VERSION_NUM ${CURL_VERSION_NUM}) + +include_regular_expression("^.*$") # Sukender: Is it necessary? + +# Setup package meta-data +# SET(PACKAGE "curl") +if(0) # This code not needed for building within CMake. +message(STATUS "curl version=[${CURL_VERSION}]") +endif() +# SET(PACKAGE_TARNAME "curl") +# SET(PACKAGE_NAME "curl") +# SET(PACKAGE_VERSION "-") +# SET(PACKAGE_STRING "curl-") - # SET(PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/") ++# SET(PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.haxx.se/mail/") +set(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}") +set(OS "\"${CMAKE_SYSTEM_NAME}\"") + +include_directories(${PROJECT_BINARY_DIR}/include/curl) +include_directories( ${CURL_SOURCE_DIR}/include ) + +option(BUILD_CURL_EXE "Set to ON to build cURL executable." ON) - option(BUILD_CURL_TESTS "Set to ON to build cURL tests." ON) +option(CURL_STATICLIB "Set to ON to build libcurl with static linking." OFF) +option(ENABLE_ARES "Set to ON to enable c-ares support" OFF) +option(ENABLE_THREADED_RESOLVER "Set to ON to enable POSIX threaded DNS lookup" OFF) + +option(ENABLE_DEBUG "Set to ON to enable curl debug features" OFF) +option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OFF) + +if (ENABLE_DEBUG) + # DEBUGBUILD will be defined only for Debug builds + if(NOT CMAKE_VERSION VERSION_LESS 3.0) + set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$:DEBUGBUILD>) + else() + set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUGBUILD) + endif() + set(ENABLE_CURLDEBUG ON) +endif() + +if (ENABLE_CURLDEBUG) + set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS CURLDEBUG) +endif() + +# initialize CURL_LIBS +set(CURL_LIBS "") + +if(ENABLE_THREADED_RESOLVER AND ENABLE_ARES) + message(FATAL_ERROR "Options ENABLE_THREADED_RESOLVER and ENABLE_ARES are mutually exclusive") +endif() + +if(ENABLE_ARES) + set(USE_ARES 1) + find_package(CARES REQUIRED) + list(APPEND CURL_LIBS ${CARES_LIBRARY} ) + set(CURL_LIBS ${CURL_LIBS} ${CARES_LIBRARY}) +endif() + - option(BUILD_DASHBOARD_REPORTS "Set to ON to activate reporting of cURL builds here http://www.cdash.org/CDashPublic/index.php?project=CURL" OFF) - if(BUILD_DASHBOARD_REPORTS) - #INCLUDE(Dart) - include(CTest) - endif(BUILD_DASHBOARD_REPORTS) - +if(MSVC) + option(BUILD_RELEASE_DEBUG_DIRS "Set OFF to build each configuration to a separate directory" OFF) + mark_as_advanced(BUILD_RELEASE_DEBUG_DIRS) +endif() + +option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON) +mark_as_advanced(CURL_HIDDEN_SYMBOLS) + - # IF(WIN32) - # OPTION(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without openssl" ON) - # MARK_AS_ADVANCED(CURL_WINDOWS_SSPI) - # ENDIF() - +option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" OFF) +mark_as_advanced(HTTP_ONLY) +option(CURL_DISABLE_FTP "disables FTP" OFF) +mark_as_advanced(CURL_DISABLE_FTP) +option(CURL_DISABLE_LDAP "disables LDAP" OFF) +mark_as_advanced(CURL_DISABLE_LDAP) +option(CURL_DISABLE_TELNET "disables Telnet" OFF) +mark_as_advanced(CURL_DISABLE_TELNET) +option(CURL_DISABLE_DICT "disables DICT" OFF) +mark_as_advanced(CURL_DISABLE_DICT) +option(CURL_DISABLE_FILE "disables FILE" OFF) +mark_as_advanced(CURL_DISABLE_FILE) +option(CURL_DISABLE_TFTP "disables TFTP" OFF) +mark_as_advanced(CURL_DISABLE_TFTP) +option(CURL_DISABLE_HTTP "disables HTTP" OFF) +mark_as_advanced(CURL_DISABLE_HTTP) + +option(CURL_DISABLE_LDAPS "to disable LDAPS" OFF) +mark_as_advanced(CURL_DISABLE_LDAPS) + +option(CURL_DISABLE_RTSP "to disable RTSP" OFF) +mark_as_advanced(CURL_DISABLE_RTSP) +option(CURL_DISABLE_PROXY "to disable proxy" OFF) +mark_as_advanced(CURL_DISABLE_PROXY) +option(CURL_DISABLE_POP3 "to disable POP3" OFF) +mark_as_advanced(CURL_DISABLE_POP3) +option(CURL_DISABLE_IMAP "to disable IMAP" OFF) +mark_as_advanced(CURL_DISABLE_IMAP) +option(CURL_DISABLE_SMTP "to disable SMTP" OFF) +mark_as_advanced(CURL_DISABLE_SMTP) +option(CURL_DISABLE_GOPHER "to disable Gopher" OFF) +mark_as_advanced(CURL_DISABLE_GOPHER) + +if(HTTP_ONLY) + set(CURL_DISABLE_FTP ON) + set(CURL_DISABLE_LDAP ON) + set(CURL_DISABLE_LDAPS ON) + set(CURL_DISABLE_TELNET ON) + set(CURL_DISABLE_DICT ON) + set(CURL_DISABLE_FILE ON) + set(CURL_DISABLE_TFTP ON) + set(CURL_DISABLE_RTSP ON) + set(CURL_DISABLE_POP3 ON) + set(CURL_DISABLE_IMAP ON) + set(CURL_DISABLE_SMTP ON) + set(CURL_DISABLE_GOPHER ON) +endif() + +option(CURL_DISABLE_COOKIES "to disable cookies support" OFF) +mark_as_advanced(CURL_DISABLE_COOKIES) + +option(CURL_DISABLE_CRYPTO_AUTH "to disable cryptographic authentication" OFF) +mark_as_advanced(CURL_DISABLE_CRYPTO_AUTH) +option(CURL_DISABLE_VERBOSE_STRINGS "to disable verbose strings" OFF) +mark_as_advanced(CURL_DISABLE_VERBOSE_STRINGS) +option(DISABLED_THREADSAFE "Set to explicitly specify we don't want to use thread-safe functions" OFF) +mark_as_advanced(DISABLED_THREADSAFE) +option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON) +mark_as_advanced(ENABLE_IPV6) - if(ENABLE_IPV6) ++if(ENABLE_IPV6 AND NOT WIN32) + include(CheckStructHasMember) + check_struct_has_member("struct sockaddr_in6" sin6_addr "netinet/in.h" + HAVE_SOCKADDR_IN6_SIN6_ADDR) + check_struct_has_member("struct sockaddr_in6" sin6_scope_id "netinet/in.h" + HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) + if(NOT HAVE_SOCKADDR_IN6_SIN6_ADDR) + message(WARNING "struct sockaddr_in6 not available, disabling IPv6 support") + # Force the feature off as this name is used as guard macro... + set(ENABLE_IPV6 OFF + CACHE BOOL "Define if you want to enable IPv6 support" FORCE) + endif() +endif() + +option(ENABLE_MANUAL "to provide the built-in manual" ON) +unset(USE_MANUAL CACHE) # TODO: cache NROFF/NROFF_MANOPT/USE_MANUAL vars? +if(ENABLE_MANUAL) + find_program(NROFF NAMES gnroff nroff) + if(NROFF) + # Need a way to write to stdin, this will do + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt" "test") + # Tests for a valid nroff option to generate a manpage + foreach(_MANOPT "-man" "-mandoc") + execute_process(COMMAND "${NROFF}" ${_MANOPT} + OUTPUT_VARIABLE NROFF_MANOPT_OUTPUT + INPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt" + ERROR_QUIET) + # Save the option if it was valid + if(NROFF_MANOPT_OUTPUT) + message("Found *nroff option: -- ${_MANOPT}") + set(NROFF_MANOPT ${_MANOPT}) + set(USE_MANUAL 1) + break() + endif() + endforeach() + # No need for the temporary file + file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt") + if(NOT USE_MANUAL) + message(WARNING "Found no *nroff option to get plaintext from man pages") + endif() + else() + message(WARNING "Found no *nroff program") + endif() +endif() + +# We need ansi c-flags, especially on HP +set(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}") +set(CMAKE_REQUIRED_FLAGS ${CMAKE_ANSI_CFLAGS}) + +# Disable warnings on Borland to avoid changing 3rd party code. +if(BORLAND) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-") +endif(BORLAND) + +# If we are on AIX, do the _ALL_SOURCE magic +if(${CMAKE_SYSTEM_NAME} MATCHES AIX) + set(_ALL_SOURCE 1) +endif(${CMAKE_SYSTEM_NAME} MATCHES AIX) + +# Include all the necessary files for macros +include (CheckFunctionExists) +include (CheckIncludeFile) +include (CheckIncludeFiles) +include (CheckLibraryExists) +include (CheckSymbolExists) +include (CheckTypeSize) +include (CheckCSourceCompiles) + +# On windows preload settings +if(WIN32) + set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D_WINSOCKAPI_") + include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/Platforms/WindowsCache.cmake) +endif(WIN32) + +if(ENABLE_THREADED_RESOLVER) + check_include_file_concat("pthread.h" HAVE_PTHREAD_H) + if(HAVE_PTHREAD_H) + set(CMAKE_THREAD_PREFER_PTHREAD 1) + find_package(Threads) + if(CMAKE_USE_PTHREADS_INIT) + set(CURL_LIBS ${CURL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) + set(USE_THREADS_POSIX 1) + endif() + endif() +endif() + +# Check for all needed libraries +if(0) # This code not needed for building within CMake. +check_library_exists_concat("dl" dlopen HAVE_LIBDL) +else() + # Use the cmake-defined dl libs as dl is should not be used + # on HPUX, but rather dld this avoids a warning + list(APPEND CURL_LIBS ${CMAKE_DL_LIBS}) +endif() +check_library_exists_concat("socket" connect HAVE_LIBSOCKET) +check_library_exists("c" gethostbyname "" NOT_NEED_LIBNSL) + +# Yellowtab Zeta needs different libraries than BeOS 5. +if(BEOS) + set(NOT_NEED_LIBNSL 1) + check_library_exists_concat("bind" gethostbyname HAVE_LIBBIND) + check_library_exists_concat("bnetapi" closesocket HAVE_LIBBNETAPI) +endif(BEOS) + +check_library_exists_concat("network" recv HAVE_LIBNETWORK) + +if(NOT NOT_NEED_LIBNSL) + check_library_exists_concat("nsl" gethostbyname HAVE_LIBNSL) +endif(NOT NOT_NEED_LIBNSL) + +check_function_exists(gethostname HAVE_GETHOSTNAME) + +if(WIN32) + check_library_exists_concat("ws2_32" getch HAVE_LIBWS2_32) + check_library_exists_concat("winmm" getch HAVE_LIBWINMM) +endif() + +set(USE_OPENSSL OFF) +set(HAVE_LIBCRYPTO OFF) +set(HAVE_LIBSSL OFF) + +if(CMAKE_USE_OPENSSL) + find_package(OpenSSL) + if(OPENSSL_FOUND) + list(APPEND CURL_LIBS ${OPENSSL_LIBRARIES}) + set(USE_OPENSSL ON) + set(HAVE_LIBCRYPTO ON) + set(HAVE_LIBSSL ON) + include_directories(${OPENSSL_INCLUDE_DIR}) + set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) + check_include_file("openssl/crypto.h" HAVE_OPENSSL_CRYPTO_H) + check_include_file("openssl/engine.h" HAVE_OPENSSL_ENGINE_H) + check_include_file("openssl/err.h" HAVE_OPENSSL_ERR_H) + check_include_file("openssl/pem.h" HAVE_OPENSSL_PEM_H) + check_include_file("openssl/pkcs12.h" HAVE_OPENSSL_PKCS12_H) + check_include_file("openssl/rsa.h" HAVE_OPENSSL_RSA_H) + check_include_file("openssl/ssl.h" HAVE_OPENSSL_SSL_H) + check_include_file("openssl/x509.h" HAVE_OPENSSL_X509_H) + check_include_file("openssl/rand.h" HAVE_OPENSSL_RAND_H) + + # Optionally build with a specific CA cert bundle. + if(CURL_CA_BUNDLE) + add_definitions(-DCURL_CA_BUNDLE="${CURL_CA_BUNDLE}") + endif() + # Optionally build with a specific CA cert dir. + if(CURL_CA_PATH) + add_definitions(-DCURL_CA_PATH="${CURL_CA_PATH}") + endif() + endif() +elseif(WIN32) + # Use Windows SSL/TLS native implementation. - add_definitions(-DUSE_SCHANNEL) - set(USE_WINDOWS_SSPI 1) ++ set(CURL_WINDOWS_SSPI ON) +elseif(APPLE) + # Use OS X SSL/TLS native implementation if available on target version. + if(CMAKE_OSX_DEPLOYMENT_TARGET) + set(OSX_VERSION ${CMAKE_OSX_DEPLOYMENT_TARGET}) + else() + execute_process( + COMMAND sw_vers -productVersion + OUTPUT_VARIABLE OSX_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + endif() + if(NOT OSX_VERSION VERSION_LESS 10.6 AND + CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|AppleClang") + add_definitions(-DUSE_DARWINSSL) + list(APPEND CURL_LIBS + "-framework CoreFoundation" + "-framework Security" + ) + endif() +endif() + +if(NOT CURL_DISABLE_LDAP) - + if(WIN32) + option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON) + if(USE_WIN32_LDAP) - check_library_exists("wldap32" cldap_open "" HAVE_WLDAP32) ++ check_library_exists_concat("wldap32" cldap_open HAVE_WLDAP32) + if(NOT HAVE_WLDAP32) + set(USE_WIN32_LDAP OFF) + endif() + endif() + endif() + + option(CMAKE_USE_OPENLDAP "Use OpenLDAP code." OFF) + mark_as_advanced(CMAKE_USE_OPENLDAP) + set(CMAKE_LDAP_LIB "ldap" CACHE STRING "Name or full path to ldap library") + set(CMAKE_LBER_LIB "lber" CACHE STRING "Name or full path to lber library") + + if(CMAKE_USE_OPENLDAP AND USE_WIN32_LDAP) + message(FATAL_ERROR "Cannot use USE_WIN32_LDAP and CMAKE_USE_OPENLDAP at the same time") + endif() - ++ + # Now that we know, we're not using windows LDAP... - if(NOT USE_WIN32_LDAP) ++ if(USE_WIN32_LDAP) ++ check_include_file_concat("winldap.h" HAVE_WINLDAP_H) ++ check_include_file_concat("winber.h" HAVE_WINBER_H) ++ else() + # Check for LDAP + set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES}) + check_library_exists_concat(${CMAKE_LDAP_LIB} ldap_init HAVE_LIBLDAP) + check_library_exists_concat(${CMAKE_LBER_LIB} ber_init HAVE_LIBLBER) - else() - check_include_file_concat("winldap.h" HAVE_WINLDAP_H) - check_include_file_concat("winber.h" HAVE_WINBER_H) - endif() - - set(CMAKE_LDAP_INCLUDE_DIR "" CACHE STRING "Path to LDAP include directory") - if(CMAKE_LDAP_INCLUDE_DIR) - set(CMAKE_REQUIRED_INCLUDES ${CMAKE_LDAP_INCLUDE_DIR}) - endif() - check_include_file_concat("ldap.h" HAVE_LDAP_H) - check_include_file_concat("lber.h" HAVE_LBER_H) - - if(NOT HAVE_LDAP_H) - message(STATUS "LDAP_H not found CURL_DISABLE_LDAP set ON") - set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE) - elseif(NOT HAVE_LIBLDAP) - message(STATUS "LDAP library '${CMAKE_LDAP_LIB}' not found CURL_DISABLE_LDAP set ON") - set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE) - else() - if(CMAKE_USE_OPENLDAP) - set(USE_OPENLDAP ON) - endif() ++ ++ set(CMAKE_REQUIRED_INCLUDES_BAK ${CMAKE_REQUIRED_INCLUDES}) ++ set(CMAKE_LDAP_INCLUDE_DIR "" CACHE STRING "Path to LDAP include directory") + if(CMAKE_LDAP_INCLUDE_DIR) - include_directories(${CMAKE_LDAP_INCLUDE_DIR}) ++ list(APPEND CMAKE_REQUIRED_INCLUDES ${CMAKE_LDAP_INCLUDE_DIR}) + endif() - set(NEED_LBER_H ON) - set(_HEADER_LIST) - if(HAVE_WINDOWS_H) - list(APPEND _HEADER_LIST "windows.h") - endif() - if(HAVE_SYS_TYPES_H) - list(APPEND _HEADER_LIST "sys/types.h") - endif() - list(APPEND _HEADER_LIST "ldap.h") ++ check_include_file_concat("ldap.h" HAVE_LDAP_H) ++ check_include_file_concat("lber.h" HAVE_LBER_H) ++ ++ if(NOT HAVE_LDAP_H) ++ message(STATUS "LDAP_H not found CURL_DISABLE_LDAP set ON") ++ set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE) ++ set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used ++ elseif(NOT HAVE_LIBLDAP) ++ message(STATUS "LDAP library '${CMAKE_LDAP_LIB}' not found CURL_DISABLE_LDAP set ON") ++ set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE) ++ set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used ++ else() ++ if(CMAKE_USE_OPENLDAP) ++ set(USE_OPENLDAP ON) ++ endif() ++ if(CMAKE_LDAP_INCLUDE_DIR) ++ include_directories(${CMAKE_LDAP_INCLUDE_DIR}) ++ endif() ++ set(NEED_LBER_H ON) ++ set(_HEADER_LIST) ++ if(HAVE_WINDOWS_H) ++ list(APPEND _HEADER_LIST "windows.h") ++ endif() ++ if(HAVE_SYS_TYPES_H) ++ list(APPEND _HEADER_LIST "sys/types.h") ++ endif() ++ list(APPEND _HEADER_LIST "ldap.h") + - set(_SRC_STRING "") - foreach(_HEADER ${_HEADER_LIST}) - set(_INCLUDE_STRING "${_INCLUDE_STRING}#include <${_HEADER}>\n") - endforeach() ++ set(_SRC_STRING "") ++ foreach(_HEADER ${_HEADER_LIST}) ++ set(_INCLUDE_STRING "${_INCLUDE_STRING}#include <${_HEADER}>\n") ++ endforeach() + - set(_SRC_STRING - " - ${_INCLUDE_STRING} - int main(int argc, char ** argv) - { - BerValue *bvp = NULL; - BerElement *bep = ber_init(bvp); - ber_free(bep, 1); - return 0; - }" - ) - set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DLDAP_DEPRECATED=1") - list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB}) - if(HAVE_LIBLBER) - list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB}) - endif() - check_c_source_compiles("${_SRC_STRING}" NOT_NEED_LBER_H) ++ set(_SRC_STRING ++ " ++ ${_INCLUDE_STRING} ++ int main(int argc, char ** argv) ++ { ++ BerValue *bvp = NULL; ++ BerElement *bep = ber_init(bvp); ++ ber_free(bep, 1); ++ return 0; ++ }" ++ ) ++ set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DLDAP_DEPRECATED=1") ++ list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB}) ++ if(HAVE_LIBLBER) ++ list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB}) ++ endif() ++ check_c_source_compiles("${_SRC_STRING}" NOT_NEED_LBER_H) + - if(NOT_NEED_LBER_H) - set(NEED_LBER_H OFF) - else() - set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DNEED_LBER_H") ++ if(NOT_NEED_LBER_H) ++ set(NEED_LBER_H OFF) ++ else() ++ set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DNEED_LBER_H") ++ endif() + endif() + endif() + +endif() + +# No ldap, no ldaps. +if(CURL_DISABLE_LDAP) + if(NOT CURL_DISABLE_LDAPS) + message(STATUS "LDAP needs to be enabled to support LDAPS") + set(CURL_DISABLE_LDAPS ON CACHE BOOL "" FORCE) + endif() +endif() + +if(NOT CURL_DISABLE_LDAPS) + check_include_file_concat("ldap_ssl.h" HAVE_LDAP_SSL_H) + check_include_file_concat("ldapssl.h" HAVE_LDAPSSL_H) +endif() + +# Check for idn +check_library_exists_concat("idn" idna_to_ascii_lz HAVE_LIBIDN) + +# Check for symbol dlopen (same as HAVE_LIBDL) +check_library_exists("${CURL_LIBS}" dlopen "" HAVE_DLOPEN) + +if(0) # This code not needed for building within CMake. +option(CURL_ZLIB "Set to ON to enable building cURL with zlib support." ON) +set(HAVE_LIBZ OFF) +set(HAVE_ZLIB_H OFF) +set(HAVE_ZLIB OFF) +if(CURL_ZLIB) + find_package(ZLIB QUIET) + if(ZLIB_FOUND) + set(HAVE_ZLIB_H ON) + set(HAVE_ZLIB ON) + set(HAVE_LIBZ ON) + list(APPEND CURL_LIBS ${ZLIB_LIBRARIES}) + include_directories(${ZLIB_INCLUDE_DIRS}) ++ list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS}) + endif() +endif() +endif() + +#----------------------------------------------------------------------------- +# CMake-specific curl code. + +if(CURL_SPECIAL_LIBZ) + set(CURL_LIBS ${CURL_LIBS} "${CURL_SPECIAL_LIBZ}") + include_directories(${CURL_SPECIAL_LIBZ_INCLUDES}) + set(HAVE_LIBZ 0) + set(HAVE_ZLIB_H 0) +endif() + +#libSSH2 +option(CMAKE_USE_LIBSSH2 "Use libSSH2" ON) +mark_as_advanced(CMAKE_USE_LIBSSH2) +set(USE_LIBSSH2 OFF) +set(HAVE_LIBSSH2 OFF) +set(HAVE_LIBSSH2_H OFF) + +if(CMAKE_USE_LIBSSH2) + find_package(LibSSH2) + if(LIBSSH2_FOUND) + list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY}) + set(CMAKE_REQUIRED_LIBRARIES ${LIBSSH2_LIBRARY}) - set(CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}") ++ list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}") + include_directories("${LIBSSH2_INCLUDE_DIR}") + set(HAVE_LIBSSH2 ON) + set(USE_LIBSSH2 ON) + + # find_package has already found the headers + set(HAVE_LIBSSH2_H ON) + set(CURL_INCLUDES ${CURL_INCLUDES} "${LIBSSH2_INCLUDE_DIR}/libssh2.h") + set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DHAVE_LIBSSH2_H") + + # now check for specific libssh2 symbols as they were added in different versions + set(CMAKE_EXTRA_INCLUDE_FILES "libssh2.h") + check_function_exists(libssh2_version HAVE_LIBSSH2_VERSION) + check_function_exists(libssh2_init HAVE_LIBSSH2_INIT) + check_function_exists(libssh2_exit HAVE_LIBSSH2_EXIT) + check_function_exists(libssh2_scp_send64 HAVE_LIBSSH2_SCP_SEND64) + check_function_exists(libssh2_session_handshake HAVE_LIBSSH2_SESSION_HANDSHAKE) + set(CMAKE_EXTRA_INCLUDE_FILES "") + + endif(LIBSSH2_FOUND) +endif(CMAKE_USE_LIBSSH2) + +option(CMAKE_USE_GSSAPI "Use GSSAPI implementation (right now only Heimdal is supported with CMake build)" OFF) +mark_as_advanced(CMAKE_USE_GSSAPI) + +if(CMAKE_USE_GSSAPI) + find_package(GSS) + + set(HAVE_GSSAPI ${GSS_FOUND}) + if(GSS_FOUND) + + message(STATUS "Found ${GSS_FLAVOUR} GSSAPI version: \"${GSS_VERSION}\"") + - set(CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIR}) ++ list(APPEND CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIRECTORIES}) + check_include_file_concat("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H) + check_include_file_concat("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H) + check_include_file_concat("gssapi/gssapi_krb5.h" HAVE_GSSAPI_GSSAPI_KRB5_H) + + if(GSS_FLAVOUR STREQUAL "Heimdal") + set(HAVE_GSSHEIMDAL ON) + else() # MIT + set(HAVE_GSSMIT ON) + set(_INCLUDE_LIST "") + if(HAVE_GSSAPI_GSSAPI_H) + list(APPEND _INCLUDE_LIST "gssapi/gssapi.h") + endif() + if(HAVE_GSSAPI_GSSAPI_GENERIC_H) + list(APPEND _INCLUDE_LIST "gssapi/gssapi_generic.h") + endif() + if(HAVE_GSSAPI_GSSAPI_KRB5_H) + list(APPEND _INCLUDE_LIST "gssapi/gssapi_krb5.h") + endif() + + string(REPLACE ";" " " _COMPILER_FLAGS_STR "${GSS_COMPILER_FLAGS}") + string(REPLACE ";" " " _LINKER_FLAGS_STR "${GSS_LINKER_FLAGS}") + + foreach(_dir ${GSS_LINK_DIRECTORIES}) + set(_LINKER_FLAGS_STR "${_LINKER_FLAGS_STR} -L\"${_dir}\"") + endforeach() + + set(CMAKE_REQUIRED_FLAGS "${_COMPILER_FLAGS_STR} ${_LINKER_FLAGS_STR}") + set(CMAKE_REQUIRED_LIBRARIES ${GSS_LIBRARIES}) + check_symbol_exists("GSS_C_NT_HOSTBASED_SERVICE" ${_INCLUDE_LIST} HAVE_GSS_C_NT_HOSTBASED_SERVICE) + if(NOT HAVE_GSS_C_NT_HOSTBASED_SERVICE) + set(HAVE_OLD_GSSMIT ON) + endif() + + endif() + - include_directories(${GSS_INCLUDE_DIR}) ++ include_directories(${GSS_INCLUDE_DIRECTORIES}) + link_directories(${GSS_LINK_DIRECTORIES}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_COMPILER_FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GSS_LINKER_FLAGS}") + list(APPEND CURL_LIBS ${GSS_LIBRARIES}) + + else() + message(WARNING "GSSAPI support has been requested but no supporting libraries found. Skipping.") + endif() +endif() + +option(ENABLE_UNIX_SOCKETS "Define if you want Unix domain sockets support" ON) +if(ENABLE_UNIX_SOCKETS) + include(CheckStructHasMember) + check_struct_has_member("struct sockaddr_un" sun_path "sys/un.h" USE_UNIX_SOCKETS) +else() + unset(USE_UNIX_SOCKETS CACHE) +endif() + ++ +# Check for header files +if(NOT UNIX) + check_include_file_concat("windows.h" HAVE_WINDOWS_H) + check_include_file_concat("winsock.h" HAVE_WINSOCK_H) + check_include_file_concat("ws2tcpip.h" HAVE_WS2TCPIP_H) + check_include_file_concat("winsock2.h" HAVE_WINSOCK2_H) ++ if(CURL_WINDOWS_SSPI) ++ set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DSECURITY_WIN32") ++ check_include_file_concat("sspi.h" HAVE_SSPI_H) ++ if(HAVE_SSPI_H) ++ check_include_file_concat("schannel.h" HAVE_SCHANNEL_H) ++ set(USE_WINDOWS_SSPI ON) ++ if(HAVE_SCHANNEL_H) ++ set(USE_SCHANNEL ON) ++ set(SSL_ENABLED ON) ++ set(CURL_LIBS ${CURL_LIBS} "crypt32") ++ endif() ++ endif() ++ endif() +else() + set(HAVE_WINDOWS_H 0) + set(HAVE_WINSOCK_H 0) + set(HAVE_WS2TCPIP_H 0) + set(HAVE_WINSOCK2_H 0) +endif() + +check_include_file_concat("stdio.h" HAVE_STDIO_H) +check_include_file_concat("inttypes.h" HAVE_INTTYPES_H) +check_include_file_concat("sys/filio.h" HAVE_SYS_FILIO_H) +check_include_file_concat("sys/ioctl.h" HAVE_SYS_IOCTL_H) +check_include_file_concat("sys/param.h" HAVE_SYS_PARAM_H) +check_include_file_concat("sys/poll.h" HAVE_SYS_POLL_H) +check_include_file_concat("sys/resource.h" HAVE_SYS_RESOURCE_H) +check_include_file_concat("sys/select.h" HAVE_SYS_SELECT_H) +check_include_file_concat("sys/socket.h" HAVE_SYS_SOCKET_H) +check_include_file_concat("sys/sockio.h" HAVE_SYS_SOCKIO_H) +check_include_file_concat("sys/stat.h" HAVE_SYS_STAT_H) +check_include_file_concat("sys/time.h" HAVE_SYS_TIME_H) +check_include_file_concat("sys/types.h" HAVE_SYS_TYPES_H) +check_include_file_concat("sys/uio.h" HAVE_SYS_UIO_H) +check_include_file_concat("sys/un.h" HAVE_SYS_UN_H) +check_include_file_concat("sys/utime.h" HAVE_SYS_UTIME_H) +check_include_file_concat("alloca.h" HAVE_ALLOCA_H) +check_include_file_concat("arpa/inet.h" HAVE_ARPA_INET_H) +check_include_file_concat("arpa/tftp.h" HAVE_ARPA_TFTP_H) +check_include_file_concat("assert.h" HAVE_ASSERT_H) +check_include_file_concat("crypto.h" HAVE_CRYPTO_H) +check_include_file_concat("des.h" HAVE_DES_H) +check_include_file_concat("err.h" HAVE_ERR_H) +check_include_file_concat("errno.h" HAVE_ERRNO_H) +check_include_file_concat("fcntl.h" HAVE_FCNTL_H) +check_include_file_concat("idn-free.h" HAVE_IDN_FREE_H) +check_include_file_concat("ifaddrs.h" HAVE_IFADDRS_H) +check_include_file_concat("io.h" HAVE_IO_H) +check_include_file_concat("krb.h" HAVE_KRB_H) +check_include_file_concat("libgen.h" HAVE_LIBGEN_H) +check_include_file_concat("limits.h" HAVE_LIMITS_H) +check_include_file_concat("locale.h" HAVE_LOCALE_H) +check_include_file_concat("net/if.h" HAVE_NET_IF_H) +check_include_file_concat("netdb.h" HAVE_NETDB_H) +check_include_file_concat("netinet/in.h" HAVE_NETINET_IN_H) +check_include_file_concat("netinet/tcp.h" HAVE_NETINET_TCP_H) + +check_include_file_concat("pem.h" HAVE_PEM_H) +check_include_file_concat("poll.h" HAVE_POLL_H) +check_include_file_concat("pwd.h" HAVE_PWD_H) +check_include_file_concat("rsa.h" HAVE_RSA_H) +check_include_file_concat("setjmp.h" HAVE_SETJMP_H) +check_include_file_concat("sgtty.h" HAVE_SGTTY_H) +check_include_file_concat("signal.h" HAVE_SIGNAL_H) +check_include_file_concat("ssl.h" HAVE_SSL_H) +check_include_file_concat("stdbool.h" HAVE_STDBOOL_H) +check_include_file_concat("stdint.h" HAVE_STDINT_H) +check_include_file_concat("stdio.h" HAVE_STDIO_H) +check_include_file_concat("stdlib.h" HAVE_STDLIB_H) +check_include_file_concat("string.h" HAVE_STRING_H) +check_include_file_concat("strings.h" HAVE_STRINGS_H) +check_include_file_concat("stropts.h" HAVE_STROPTS_H) +check_include_file_concat("termio.h" HAVE_TERMIO_H) +check_include_file_concat("termios.h" HAVE_TERMIOS_H) +check_include_file_concat("time.h" HAVE_TIME_H) +check_include_file_concat("tld.h" HAVE_TLD_H) +check_include_file_concat("unistd.h" HAVE_UNISTD_H) +check_include_file_concat("utime.h" HAVE_UTIME_H) +check_include_file_concat("x509.h" HAVE_X509_H) + +check_include_file_concat("process.h" HAVE_PROCESS_H) +check_include_file_concat("stddef.h" HAVE_STDDEF_H) +check_include_file_concat("dlfcn.h" HAVE_DLFCN_H) +check_include_file_concat("malloc.h" HAVE_MALLOC_H) +check_include_file_concat("memory.h" HAVE_MEMORY_H) +check_include_file_concat("netinet/if_ether.h" HAVE_NETINET_IF_ETHER_H) +check_include_file_concat("stdint.h" HAVE_STDINT_H) +check_include_file_concat("sockio.h" HAVE_SOCKIO_H) +check_include_file_concat("sys/utsname.h" HAVE_SYS_UTSNAME_H) +check_include_file_concat("idna.h" HAVE_IDNA_H) + + + +check_type_size(size_t SIZEOF_SIZE_T) +check_type_size(ssize_t SIZEOF_SSIZE_T) +check_type_size("long long" SIZEOF_LONG_LONG) +check_type_size("long" SIZEOF_LONG) +check_type_size("short" SIZEOF_SHORT) +check_type_size("int" SIZEOF_INT) +check_type_size("__int64" SIZEOF___INT64) +check_type_size("time_t" SIZEOF_TIME_T) +check_type_size("off_t" SIZEOF_OFF_T) + +# Make public versions of some type sizes for curlbuild.h. +foreach(t INT LONG LONG_LONG SSIZE_T) + string(REPLACE "SIZEOF_" "CURL_SIZEOF_" CURL_SIZEOF_${t}_CODE "${SIZEOF_${t}_CODE}") +endforeach() + +if(HAVE_SIZEOF_LONG_LONG) + set(HAVE_LONGLONG 1) + set(HAVE_LL 1) +endif(HAVE_SIZEOF_LONG_LONG) + +find_file(RANDOM_FILE urandom /dev) +mark_as_advanced(RANDOM_FILE) + +# Check for some functions that are used +if(HAVE_LIBWS2_32) + set(CMAKE_REQUIRED_LIBRARIES ws2_32) +elseif(HAVE_LIBSOCKET) + set(CMAKE_REQUIRED_LIBRARIES socket) +endif() + +check_symbol_exists(basename "${CURL_INCLUDES}" HAVE_BASENAME) +check_symbol_exists(socket "${CURL_INCLUDES}" HAVE_SOCKET) +check_symbol_exists(poll "${CURL_INCLUDES}" HAVE_POLL) +check_symbol_exists(select "${CURL_INCLUDES}" HAVE_SELECT) +check_symbol_exists(strdup "${CURL_INCLUDES}" HAVE_STRDUP) +check_symbol_exists(strstr "${CURL_INCLUDES}" HAVE_STRSTR) +check_symbol_exists(strtok_r "${CURL_INCLUDES}" HAVE_STRTOK_R) +check_symbol_exists(strftime "${CURL_INCLUDES}" HAVE_STRFTIME) +check_symbol_exists(uname "${CURL_INCLUDES}" HAVE_UNAME) +check_symbol_exists(strcasecmp "${CURL_INCLUDES}" HAVE_STRCASECMP) +check_symbol_exists(stricmp "${CURL_INCLUDES}" HAVE_STRICMP) +check_symbol_exists(strcmpi "${CURL_INCLUDES}" HAVE_STRCMPI) +check_symbol_exists(strncmpi "${CURL_INCLUDES}" HAVE_STRNCMPI) +check_symbol_exists(alarm "${CURL_INCLUDES}" HAVE_ALARM) +if(NOT HAVE_STRNCMPI) + set(HAVE_STRCMPI) +endif(NOT HAVE_STRNCMPI) +check_symbol_exists(gethostbyaddr "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR) +check_symbol_exists(gethostbyaddr_r "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR_R) +check_symbol_exists(gettimeofday "${CURL_INCLUDES}" HAVE_GETTIMEOFDAY) +check_symbol_exists(inet_addr "${CURL_INCLUDES}" HAVE_INET_ADDR) +check_symbol_exists(inet_ntoa "${CURL_INCLUDES}" HAVE_INET_NTOA) +check_symbol_exists(inet_ntoa_r "${CURL_INCLUDES}" HAVE_INET_NTOA_R) +check_symbol_exists(tcsetattr "${CURL_INCLUDES}" HAVE_TCSETATTR) +check_symbol_exists(tcgetattr "${CURL_INCLUDES}" HAVE_TCGETATTR) +check_symbol_exists(perror "${CURL_INCLUDES}" HAVE_PERROR) +check_symbol_exists(closesocket "${CURL_INCLUDES}" HAVE_CLOSESOCKET) +check_symbol_exists(setvbuf "${CURL_INCLUDES}" HAVE_SETVBUF) +check_symbol_exists(sigsetjmp "${CURL_INCLUDES}" HAVE_SIGSETJMP) +check_symbol_exists(getpass_r "${CURL_INCLUDES}" HAVE_GETPASS_R) +check_symbol_exists(strlcat "${CURL_INCLUDES}" HAVE_STRLCAT) +check_symbol_exists(getpwuid "${CURL_INCLUDES}" HAVE_GETPWUID) +check_symbol_exists(geteuid "${CURL_INCLUDES}" HAVE_GETEUID) +check_symbol_exists(utime "${CURL_INCLUDES}" HAVE_UTIME) +if(CMAKE_USE_OPENSSL) + check_symbol_exists(RAND_status "${CURL_INCLUDES}" HAVE_RAND_STATUS) + check_symbol_exists(RAND_screen "${CURL_INCLUDES}" HAVE_RAND_SCREEN) + check_symbol_exists(RAND_egd "${CURL_INCLUDES}" HAVE_RAND_EGD) + check_symbol_exists(CRYPTO_cleanup_all_ex_data "${CURL_INCLUDES}" + HAVE_CRYPTO_CLEANUP_ALL_EX_DATA) + if(HAVE_LIBCRYPTO AND HAVE_LIBSSL) + set(USE_OPENSSL 1) + endif(HAVE_LIBCRYPTO AND HAVE_LIBSSL) +endif(CMAKE_USE_OPENSSL) +check_symbol_exists(gmtime_r "${CURL_INCLUDES}" HAVE_GMTIME_R) +check_symbol_exists(localtime_r "${CURL_INCLUDES}" HAVE_LOCALTIME_R) + +check_symbol_exists(gethostbyname "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME) +check_symbol_exists(gethostbyname_r "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R) + +check_symbol_exists(signal "${CURL_INCLUDES}" HAVE_SIGNAL_FUNC) +check_symbol_exists(SIGALRM "${CURL_INCLUDES}" HAVE_SIGNAL_MACRO) +if(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO) + set(HAVE_SIGNAL 1) +endif(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO) +check_symbol_exists(uname "${CURL_INCLUDES}" HAVE_UNAME) +check_symbol_exists(strtoll "${CURL_INCLUDES}" HAVE_STRTOLL) +check_symbol_exists(_strtoi64 "${CURL_INCLUDES}" HAVE__STRTOI64) +check_symbol_exists(strerror_r "${CURL_INCLUDES}" HAVE_STRERROR_R) +check_symbol_exists(siginterrupt "${CURL_INCLUDES}" HAVE_SIGINTERRUPT) +check_symbol_exists(perror "${CURL_INCLUDES}" HAVE_PERROR) +check_symbol_exists(fork "${CURL_INCLUDES}" HAVE_FORK) +check_symbol_exists(getaddrinfo "${CURL_INCLUDES}" HAVE_GETADDRINFO) +check_symbol_exists(freeaddrinfo "${CURL_INCLUDES}" HAVE_FREEADDRINFO) +check_symbol_exists(freeifaddrs "${CURL_INCLUDES}" HAVE_FREEIFADDRS) +check_symbol_exists(pipe "${CURL_INCLUDES}" HAVE_PIPE) +check_symbol_exists(ftruncate "${CURL_INCLUDES}" HAVE_FTRUNCATE) +check_symbol_exists(getprotobyname "${CURL_INCLUDES}" HAVE_GETPROTOBYNAME) +check_symbol_exists(getrlimit "${CURL_INCLUDES}" HAVE_GETRLIMIT) +check_symbol_exists(idn_free "${CURL_INCLUDES}" HAVE_IDN_FREE) +check_symbol_exists(idna_strerror "${CURL_INCLUDES}" HAVE_IDNA_STRERROR) +check_symbol_exists(tld_strerror "${CURL_INCLUDES}" HAVE_TLD_STRERROR) +check_symbol_exists(setlocale "${CURL_INCLUDES}" HAVE_SETLOCALE) +check_symbol_exists(setrlimit "${CURL_INCLUDES}" HAVE_SETRLIMIT) +check_symbol_exists(fcntl "${CURL_INCLUDES}" HAVE_FCNTL) +check_symbol_exists(ioctl "${CURL_INCLUDES}" HAVE_IOCTL) +check_symbol_exists(setsockopt "${CURL_INCLUDES}" HAVE_SETSOCKOPT) + +# symbol exists in win32, but function does not. +check_function_exists(inet_pton HAVE_INET_PTON) + +# sigaction and sigsetjmp are special. Use special mechanism for +# detecting those, but only if previous attempt failed. +if(HAVE_SIGNAL_H) + check_symbol_exists(sigaction "signal.h" HAVE_SIGACTION) +endif(HAVE_SIGNAL_H) + +if(NOT HAVE_SIGSETJMP) + if(HAVE_SETJMP_H) + check_symbol_exists(sigsetjmp "setjmp.h" HAVE_MACRO_SIGSETJMP) + if(HAVE_MACRO_SIGSETJMP) + set(HAVE_SIGSETJMP 1) + endif(HAVE_MACRO_SIGSETJMP) + endif(HAVE_SETJMP_H) +endif(NOT HAVE_SIGSETJMP) + +# If there is no stricmp(), do not allow LDAP to parse URLs +if(NOT HAVE_STRICMP) + set(HAVE_LDAP_URL_PARSE 1) +endif(NOT HAVE_STRICMP) + +# Do curl specific tests +foreach(CURL_TEST + HAVE_FCNTL_O_NONBLOCK + HAVE_IOCTLSOCKET + HAVE_IOCTLSOCKET_CAMEL + HAVE_IOCTLSOCKET_CAMEL_FIONBIO + HAVE_IOCTLSOCKET_FIONBIO + HAVE_IOCTL_FIONBIO + HAVE_IOCTL_SIOCGIFADDR + HAVE_SETSOCKOPT_SO_NONBLOCK + HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID + TIME_WITH_SYS_TIME + HAVE_O_NONBLOCK + HAVE_GETHOSTBYADDR_R_5 + HAVE_GETHOSTBYADDR_R_7 + HAVE_GETHOSTBYADDR_R_8 + HAVE_GETHOSTBYADDR_R_5_REENTRANT + HAVE_GETHOSTBYADDR_R_7_REENTRANT + HAVE_GETHOSTBYADDR_R_8_REENTRANT + HAVE_GETHOSTBYNAME_R_3 + HAVE_GETHOSTBYNAME_R_5 + HAVE_GETHOSTBYNAME_R_6 + HAVE_GETHOSTBYNAME_R_3_REENTRANT + HAVE_GETHOSTBYNAME_R_5_REENTRANT + HAVE_GETHOSTBYNAME_R_6_REENTRANT + HAVE_SOCKLEN_T + HAVE_IN_ADDR_T + HAVE_BOOL_T + STDC_HEADERS + RETSIGTYPE_TEST + HAVE_INET_NTOA_R_DECL + HAVE_INET_NTOA_R_DECL_REENTRANT + HAVE_GETADDRINFO + HAVE_FILE_OFFSET_BITS + ) + curl_internal_test(${CURL_TEST}) +endforeach(CURL_TEST) +if(HAVE_FILE_OFFSET_BITS) + set(_FILE_OFFSET_BITS 64) +endif(HAVE_FILE_OFFSET_BITS) +foreach(CURL_TEST + HAVE_GLIBC_STRERROR_R + HAVE_POSIX_STRERROR_R + ) + curl_internal_test_run(${CURL_TEST}) +endforeach(CURL_TEST) + +# Check for reentrant +foreach(CURL_TEST + HAVE_GETHOSTBYADDR_R_5 + HAVE_GETHOSTBYADDR_R_7 + HAVE_GETHOSTBYADDR_R_8 + HAVE_GETHOSTBYNAME_R_3 + HAVE_GETHOSTBYNAME_R_5 + HAVE_GETHOSTBYNAME_R_6 + HAVE_INET_NTOA_R_DECL_REENTRANT) + if(NOT ${CURL_TEST}) + if(${CURL_TEST}_REENTRANT) + set(NEED_REENTRANT 1) + endif(${CURL_TEST}_REENTRANT) + endif(NOT ${CURL_TEST}) +endforeach(CURL_TEST) + +if(NEED_REENTRANT) + foreach(CURL_TEST + HAVE_GETHOSTBYADDR_R_5 + HAVE_GETHOSTBYADDR_R_7 + HAVE_GETHOSTBYADDR_R_8 + HAVE_GETHOSTBYNAME_R_3 + HAVE_GETHOSTBYNAME_R_5 + HAVE_GETHOSTBYNAME_R_6) + set(${CURL_TEST} 0) + if(${CURL_TEST}_REENTRANT) + set(${CURL_TEST} 1) + endif(${CURL_TEST}_REENTRANT) + endforeach(CURL_TEST) +endif(NEED_REENTRANT) + +if(HAVE_INET_NTOA_R_DECL_REENTRANT) + set(HAVE_INET_NTOA_R_DECL 1) + set(NEED_REENTRANT 1) +endif(HAVE_INET_NTOA_R_DECL_REENTRANT) + +# Some other minor tests + +if(NOT HAVE_IN_ADDR_T) + set(in_addr_t "unsigned long") +endif(NOT HAVE_IN_ADDR_T) + +# Fix libz / zlib.h + +if(NOT CURL_SPECIAL_LIBZ) + if(NOT HAVE_LIBZ) + set(HAVE_ZLIB_H 0) + endif(NOT HAVE_LIBZ) + + if(NOT HAVE_ZLIB_H) + set(HAVE_LIBZ 0) + endif(NOT HAVE_ZLIB_H) +endif(NOT CURL_SPECIAL_LIBZ) + +if(_FILE_OFFSET_BITS) + set(_FILE_OFFSET_BITS 64) +endif(_FILE_OFFSET_BITS) +set(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64") +set(CMAKE_EXTRA_INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/curl/curl.h") +check_type_size("curl_off_t" SIZEOF_CURL_OFF_T) +set(CMAKE_EXTRA_INCLUDE_FILES) +set(CMAKE_REQUIRED_FLAGS) + + +# Check for nonblocking +set(HAVE_DISABLED_NONBLOCKING 1) +if(HAVE_FIONBIO OR + HAVE_IOCTLSOCKET OR + HAVE_IOCTLSOCKET_CASE OR + HAVE_O_NONBLOCK) + set(HAVE_DISABLED_NONBLOCKING) +endif(HAVE_FIONBIO OR + HAVE_IOCTLSOCKET OR + HAVE_IOCTLSOCKET_CASE OR + HAVE_O_NONBLOCK) + +if(RETSIGTYPE_TEST) + set(RETSIGTYPE void) +else(RETSIGTYPE_TEST) + set(RETSIGTYPE int) +endif(RETSIGTYPE_TEST) + +if(CMAKE_COMPILER_IS_GNUCC AND APPLE) + include(CheckCCompilerFlag) + check_c_compiler_flag(-Wno-long-double HAVE_C_FLAG_Wno_long_double) + if(HAVE_C_FLAG_Wno_long_double) + # The Mac version of GCC warns about use of long double. Disable it. + get_source_file_property(MPRINTF_COMPILE_FLAGS mprintf.c COMPILE_FLAGS) + if(MPRINTF_COMPILE_FLAGS) + set(MPRINTF_COMPILE_FLAGS "${MPRINTF_COMPILE_FLAGS} -Wno-long-double") + else(MPRINTF_COMPILE_FLAGS) + set(MPRINTF_COMPILE_FLAGS "-Wno-long-double") + endif(MPRINTF_COMPILE_FLAGS) + set_source_files_properties(mprintf.c PROPERTIES + COMPILE_FLAGS ${MPRINTF_COMPILE_FLAGS}) + endif(HAVE_C_FLAG_Wno_long_double) +endif(CMAKE_COMPILER_IS_GNUCC AND APPLE) + +if(HAVE_SOCKLEN_T) + set(CURL_HAVE_SOCKLEN_T 1) + set(CURL_TYPEOF_CURL_SOCKLEN_T "socklen_t") + if(WIN32) + set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h;ws2tcpip.h") + elseif(HAVE_SYS_SOCKET_H) + set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h") + endif() + check_type_size("socklen_t" CURL_SIZEOF_CURL_SOCKLEN_T) + set(CMAKE_EXTRA_INCLUDE_FILES) + if(NOT HAVE_CURL_SIZEOF_CURL_SOCKLEN_T) + message(FATAL_ERROR + "Check for sizeof socklen_t failed, see CMakeFiles/CMakerror.log") + endif() +else() + set(CURL_HAVE_SOCKLEN_T 0) +endif() + +# TODO test which of these headers are required for the typedefs used in curlbuild.h +if(WIN32) + set(CURL_PULL_WS2TCPIP_H ${HAVE_WS2TCPIP_H}) +else() + set(CURL_PULL_SYS_TYPES_H ${HAVE_SYS_TYPES_H}) + set(CURL_PULL_SYS_SOCKET_H ${HAVE_SYS_SOCKET_H}) + set(CURL_PULL_SYS_POLL_H ${HAVE_SYS_POLL_H}) +endif() +set(CURL_PULL_STDINT_H ${HAVE_STDINT_H}) +set(CURL_PULL_INTTYPES_H ${HAVE_INTTYPES_H}) + +include(CMake/OtherTests.cmake) + +add_definitions(-DHAVE_CONFIG_H) + +# For windows, do not allow the compiler to use default target (Vista). +if(WIN32) + add_definitions(-D_WIN32_WINNT=0x0501) +endif(WIN32) + +if(MSVC) + add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) +endif(MSVC) + +# Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it). +function(TRANSFORM_MAKEFILE_INC INPUT_FILE OUTPUT_FILE) + file(READ ${INPUT_FILE} MAKEFILE_INC_TEXT) + string(REPLACE "$(top_srcdir)" "\${CURL_SOURCE_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) + string(REPLACE "$(top_builddir)" "\${CURL_BINARY_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) + + string(REGEX REPLACE "\\\\\n" "?!?" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) + string(REGEX REPLACE "([a-zA-Z_][a-zA-Z0-9_]*)[\t ]*=[\t ]*([^\n]*)" "SET(\\1 \\2)" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) + string(REPLACE "?!?" "\n" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) + + string(REGEX REPLACE "\\$\\(([a-zA-Z_][a-zA-Z0-9_]*)\\)" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) # Replace $() with ${} + string(REGEX REPLACE "@([a-zA-Z_][a-zA-Z0-9_]*)@" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) # Replace @@ with ${}, even if that may not be read by CMake scripts. + file(WRITE ${OUTPUT_FILE} ${MAKEFILE_INC_TEXT}) + +endfunction() + +add_subdirectory(lib) +if(BUILD_CURL_EXE) + add_subdirectory(src) +endif() - if(BUILD_CURL_TESTS) - add_subdirectory(tests) - endif() + +#----------------------------------------------------------------------------- +# CMake-specific curl code. +add_executable(LIBCURL curltest.c) +target_link_libraries(LIBCURL cmcurl) + +if(CMAKE_CURL_TEST_URL) + add_test(curl LIBCURL ${CMAKE_CURL_TEST_URL}) +endif() + +install(FILES COPYING DESTINATION ${CMAKE_DOC_DIR}/cmcurl) +#----------------------------------------------------------------------------- + +if(0) # This code not needed for building within CMake. ++include(CTest) ++if(BUILD_TESTING) ++ add_subdirectory(tests) ++endif() ++ +# TODO support GNUTLS, NSS, POLARSSL, AXTLS, CYASSL, WINSSL, DARWINSSL +if(USE_OPENSSL) + set(SSL_ENABLED 1) +endif() + +# Helper to populate a list (_items) with a label when conditions (the remaining +# args) are satisfied +function(_add_if label) + # TODO need to disable policy CMP0054 (CMake 3.1) to allow this indirection + if(${ARGN}) + set(_items ${_items} "${label}" PARENT_SCOPE) + endif() +endfunction() + +# Clear list and try to detect available features +set(_items) - _add_if("SSL" SSL_ENABLED) ++_add_if("WinSSL" SSL_ENABLED AND USE_WINDOWS_SSPI) ++_add_if("OpenSSL" SSL_ENABLED AND USE_OPENSSL) +_add_if("IPv6" ENABLE_IPV6) +_add_if("unix-sockets" USE_UNIX_SOCKETS) +_add_if("libz" HAVE_LIBZ) +_add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX) +_add_if("IDN" HAVE_LIBIDN) +# TODO SSP1 (WinSSL) check is missing +_add_if("SSPI" USE_WINDOWS_SSPI) +_add_if("GSS-API" HAVE_GSSAPI) +# TODO SSP1 missing for SPNEGO +_add_if("SPNEGO" NOT CURL_DISABLE_CRYPTO_AUTH AND + (HAVE_GSSAPI OR USE_WINDOWS_SSPI)) +_add_if("Kerberos" NOT CURL_DISABLE_CRYPTO_AUTH AND + (HAVE_GSSAPI OR USE_WINDOWS_SSPI)) +# NTLM support requires crypto function adaptions from various SSL libs +# TODO alternative SSL libs tests for SSP1, GNUTLS, NSS, DARWINSSL +if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR + USE_WINDOWS_SSPI OR GNUTLS_ENABLED OR NSS_ENABLED OR DARWINSSL_ENABLED)) + _add_if("NTLM" 1) + # TODO missing option (autoconf: --enable-ntlm-wb) + _add_if("NTLM_WB" NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED) +endif() +# TODO missing option (--enable-tls-srp), depends on GNUTLS_SRP/OPENSSL_SRP +_add_if("TLS-SRP" USE_TLS_SRP) +# TODO option --with-nghttp2 tests for nghttp2 lib and nghttp2/nghttp2.h header +_add_if("HTTP2" USE_NGHTTP2) +string(REPLACE ";" " " SUPPORT_FEATURES "${_items}") +message(STATUS "Enabled features: ${SUPPORT_FEATURES}") + +# Clear list and try to detect available protocols +set(_items) +_add_if("HTTP" NOT CURL_DISABLE_HTTP) +_add_if("HTTPS" NOT CURL_DISABLE_HTTP AND SSL_ENABLED) +_add_if("FTP" NOT CURL_DISABLE_FTP) +_add_if("FTPS" NOT CURL_DISABLE_FTP AND SSL_ENABLED) +_add_if("FILE" NOT CURL_DISABLE_FILE) +_add_if("TELNET" NOT CURL_DISABLE_TELNET) +_add_if("LDAP" NOT CURL_DISABLE_LDAP) +# CURL_DISABLE_LDAP implies CURL_DISABLE_LDAPS +# TODO check HAVE_LDAP_SSL (in autoconf this is enabled with --enable-ldaps) +_add_if("LDAPS" NOT CURL_DISABLE_LDAPS AND + ((USE_OPENLDAP AND SSL_ENABLED) OR + (NOT USE_OPENLDAP AND HAVE_LDAP_SSL))) +_add_if("DICT" NOT CURL_DISABLE_DICT) +_add_if("TFTP" NOT CURL_DISABLE_TFTP) +_add_if("GOPHER" NOT CURL_DISABLE_GOPHER) +_add_if("POP3" NOT CURL_DISABLE_POP3) +_add_if("POP3S" NOT CURL_DISABLE_POP3 AND SSL_ENABLED) +_add_if("IMAP" NOT CURL_DISABLE_IMAP) +_add_if("IMAPS" NOT CURL_DISABLE_IMAP AND SSL_ENABLED) +_add_if("SMTP" NOT CURL_DISABLE_SMTP) +_add_if("SMTPS" NOT CURL_DISABLE_SMTP AND SSL_ENABLED) +_add_if("SCP" USE_LIBSSH2) +_add_if("SFTP" USE_LIBSSH2) +_add_if("RTSP" NOT CURL_DISABLE_RTSP) +_add_if("RTMP" USE_LIBRTMP) +list(SORT _items) +string(REPLACE ";" " " SUPPORT_PROTOCOLS "${_items}") +message(STATUS "Enabled protocols: ${SUPPORT_PROTOCOLS}") + +# curl-config needs the following options to be set. +set(CC "${CMAKE_C_COMPILER}") +# TODO probably put a -D... options here? +set(CONFIGURE_OPTIONS "") +# TODO when to set "-DCURL_STATICLIB" for CPPFLAG_CURL_STATICLIB? +set(CPPFLAG_CURL_STATICLIB "") +# TODO need to set this (see CURL_CHECK_CA_BUNDLE in acinclude.m4) +set(CURL_CA_BUNDLE "") +set(CURLVERSION "${CURL_VERSION}") +set(ENABLE_SHARED "yes") +if(CURL_STATICLIB) + # Broken: LIBCURL_LIBS below; .a lib is not built + message(WARNING "Static linking is broken!") + set(ENABLE_STATIC "no") +else() + set(ENABLE_STATIC "no") +endif() +set(exec_prefix "\${prefix}") +set(includedir "\${prefix}/include") +set(LDFLAGS "${CMAKE_SHARED_LINKER_FLAGS}") +set(LIBCURL_LIBS "") +set(libdir "${CMAKE_INSTALL_PREFIX}/lib") +# TODO CURL_LIBS also contains absolute paths which don't work with static -l... +foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS}) + set(LIBCURL_LIBS "${LIBCURL_LIBS} -l${_lib}") +endforeach() +# "a" (Linux) or "lib" (Windows) +string(REPLACE "." "" libext "${CMAKE_STATIC_LIBRARY_SUFFIX}") +set(prefix "${CMAKE_INSTALL_PREFIX}") +# Set this to "yes" to append all libraries on which -lcurl is dependent +set(REQUIRE_LIB_DEPS "no") +# SUPPORT_FEATURES +# SUPPORT_PROTOCOLS +set(VERSIONNUM "${CURL_VERSION_NUM}") + +# Finally generate a "curl-config" matching this config +configure_file("${CURL_SOURCE_DIR}/curl-config.in" + "${CURL_BINARY_DIR}/curl-config" @ONLY) - install(FILES "${CMAKE_BINARY_DIR}/curl-config" ++install(FILES "${CURL_BINARY_DIR}/curl-config" + DESTINATION bin + PERMISSIONS + OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE) + +# Finally generate a pkg-config file matching this config +configure_file("${CURL_SOURCE_DIR}/libcurl.pc.in" + "${CURL_BINARY_DIR}/libcurl.pc" @ONLY) - install(FILES "${CMAKE_BINARY_DIR}/libcurl.pc" ++install(FILES "${CURL_BINARY_DIR}/libcurl.pc" + DESTINATION lib/pkgconfig) + +# This needs to be run very last so other parts of the scripts can take advantage of this. +if(NOT CURL_CONFIG_HAS_BEEN_RUN_BEFORE) + set(CURL_CONFIG_HAS_BEEN_RUN_BEFORE 1 CACHE INTERNAL "Flag to track whether this is the first time running CMake or if CMake has been configured before") +endif() + +# Installation. +# First, install generated curlbuild.h +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/curl/curlbuild.h" + DESTINATION include/curl ) +# Next, install other headers excluding curlbuild.h +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/curl" + DESTINATION include + FILES_MATCHING PATTERN "*.h" + PATTERN "curlbuild.h" EXCLUDE) + + +# Workaround for MSVS10 to avoid the Dialog Hell +# FIXME: This could be removed with future version of CMake. +if(MSVC_VERSION EQUAL 1600) + set(CURL_SLN_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/CURL.sln") + if(EXISTS "${CURL_SLN_FILENAME}") + file(APPEND "${CURL_SLN_FILENAME}" "\n# This should be regenerated!\n") + endif() +endif() +endif() diff --cc Utilities/cmcurl/include/curl/curl.h index 86ce1ff,0000000..dfaea5d mode 100644,000000..100644 --- a/Utilities/cmcurl/include/curl/curl.h +++ b/Utilities/cmcurl/include/curl/curl.h @@@ -1,2382 -1,0 +1,2447 @@@ +#ifndef __CURL_CURL_H +#define __CURL_CURL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. ++ * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. ++ * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * If you have libcurl problems, all docs and details are found here: - * http://curl.haxx.se/libcurl/ ++ * https://curl.haxx.se/libcurl/ + * + * curl-library mailing list subscription and unsubscription web interface: - * http://cool.haxx.se/mailman/listinfo/curl-library/ ++ * https://cool.haxx.se/mailman/listinfo/curl-library/ + */ + +#include "curlver.h" /* libcurl version defines */ +#include "cmcurl/include/curl/curlbuild.h" /* libcurl build definitions */ +#include "curlrules.h" /* libcurl rules enforcement */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && \ + !defined(WIN32) && !defined(__SYMBIAN32__) +#define WIN32 +#endif + +#include +#include + +#if defined(__FreeBSD__) && (__FreeBSD__ >= 2) +/* Needed for __FreeBSD_version symbol definition */ +#include +#endif + +/* The include stuff here below is mainly for time_t! */ +#include +#include + +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) - #if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || defined(__LWIP_OPT_H__)) ++#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ ++ defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) +/* The check above prevents the winsock2 inclusion if winsock.h already was + included, since they can't co-exist without problems */ +#include +#include +#endif +#endif + +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish + libc5-based Linux systems. Only include it on systems that are known to + require it! */ +#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ + defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ + defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) +#include +#endif + +#if !defined(WIN32) && !defined(_WIN32_WCE) +#include +#endif + +#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) +#include +#endif + +#if defined __BEOS__ || defined __HAIKU__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + ++#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) ++typedef struct Curl_easy CURL; ++typedef struct Curl_share CURLSH; ++#else +typedef void CURL; ++typedef void CURLSH; ++#endif + +/* + * libcurl external API function linkage decorations. + */ + +#ifdef CURL_STATICLIB +# define CURL_EXTERN +#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__) +# if defined(BUILDING_LIBCURL) +# define CURL_EXTERN __declspec(dllexport) +# else +# define CURL_EXTERN __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) +# define CURL_EXTERN CURL_EXTERN_SYMBOL +#else +# define CURL_EXTERN +#endif + +#ifndef curl_socket_typedef +/* socket typedef */ - #if defined(WIN32) && !defined(__LWIP_OPT_H__) ++#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) +typedef SOCKET curl_socket_t; +#define CURL_SOCKET_BAD INVALID_SOCKET +#else +typedef int curl_socket_t; +#define CURL_SOCKET_BAD -1 +#endif +#define curl_socket_typedef +#endif /* curl_socket_typedef */ + +struct curl_httppost { + struct curl_httppost *next; /* next entry in the list */ + char *name; /* pointer to allocated name */ + long namelength; /* length of name length */ + char *contents; /* pointer to allocated data contents */ - long contentslength; /* length of contents field */ ++ long contentslength; /* length of contents field, see also ++ CURL_HTTPPOST_LARGE */ + char *buffer; /* pointer to allocated buffer contents */ + long bufferlength; /* length of buffer field */ + char *contenttype; /* Content-Type */ + struct curl_slist* contentheader; /* list of extra headers for this form */ + struct curl_httppost *more; /* if one field name has more than one + file, this link should link to following + files */ + long flags; /* as defined below */ - #define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */ - #define HTTPPOST_READFILE (1<<1) /* specified content is a file name */ - #define HTTPPOST_PTRNAME (1<<2) /* name is only stored pointer - do not free in formfree */ - #define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer - do not free in formfree */ - #define HTTPPOST_BUFFER (1<<4) /* upload file from buffer */ - #define HTTPPOST_PTRBUFFER (1<<5) /* upload file from pointer contents */ - #define HTTPPOST_CALLBACK (1<<6) /* upload file contents by using the - regular read callback to get the data - and pass the given pointer as custom - pointer */ ++ ++/* specified content is a file name */ ++#define CURL_HTTPPOST_FILENAME (1<<0) ++/* specified content is a file name */ ++#define CURL_HTTPPOST_READFILE (1<<1) ++/* name is only stored pointer do not free in formfree */ ++#define CURL_HTTPPOST_PTRNAME (1<<2) ++/* contents is only stored pointer do not free in formfree */ ++#define CURL_HTTPPOST_PTRCONTENTS (1<<3) ++/* upload file from buffer */ ++#define CURL_HTTPPOST_BUFFER (1<<4) ++/* upload file from pointer contents */ ++#define CURL_HTTPPOST_PTRBUFFER (1<<5) ++/* upload file contents by using the regular read callback to get the data and ++ pass the given pointer as custom pointer */ ++#define CURL_HTTPPOST_CALLBACK (1<<6) ++/* use size in 'contentlen', added in 7.46.0 */ ++#define CURL_HTTPPOST_LARGE (1<<7) + + char *showfilename; /* The file name to show. If not set, the + actual file name will be used (if this + is a file part) */ + void *userp; /* custom pointer used for + HTTPPOST_CALLBACK posts */ ++ curl_off_t contentlen; /* alternative length of contents ++ field. Used if CURL_HTTPPOST_LARGE is ++ set. Added in 7.46.0 */ +}; + +/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered + deprecated but was the only choice up until 7.31.0 */ +typedef int (*curl_progress_callback)(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + +/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in + 7.32.0, it avoids floating point and provides more detailed information. */ +typedef int (*curl_xferinfo_callback)(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + +#ifndef CURL_MAX_WRITE_SIZE + /* Tests have proven that 20K is a very bad buffer size for uploads on + Windows, while 16K for some odd reason performed a lot better. + We do the ifndef check to allow this value to easier be changed at build + time for those who feel adventurous. The practical minimum is about + 400 bytes since libcurl uses a buffer of this size as a scratch area + (unrelated to network send operations). */ +#define CURL_MAX_WRITE_SIZE 16384 +#endif + +#ifndef CURL_MAX_HTTP_HEADER +/* The only reason to have a max limit for this is to avoid the risk of a bad + server feeding libcurl with a never-ending header that will cause reallocs + infinitely */ +#define CURL_MAX_HTTP_HEADER (100*1024) +#endif + +/* This is a magic return code for the write callback that, when returned, + will signal libcurl to pause receiving on the current transfer. */ +#define CURL_WRITEFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_write_callback)(char *buffer, + size_t size, + size_t nitems, + void *outstream); + + + +/* enumeration of file types */ +typedef enum { + CURLFILETYPE_FILE = 0, + CURLFILETYPE_DIRECTORY, + CURLFILETYPE_SYMLINK, + CURLFILETYPE_DEVICE_BLOCK, + CURLFILETYPE_DEVICE_CHAR, + CURLFILETYPE_NAMEDPIPE, + CURLFILETYPE_SOCKET, + CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ + + CURLFILETYPE_UNKNOWN /* should never occur */ +} curlfiletype; + +#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) +#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) +#define CURLFINFOFLAG_KNOWN_TIME (1<<2) +#define CURLFINFOFLAG_KNOWN_PERM (1<<3) +#define CURLFINFOFLAG_KNOWN_UID (1<<4) +#define CURLFINFOFLAG_KNOWN_GID (1<<5) +#define CURLFINFOFLAG_KNOWN_SIZE (1<<6) +#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) + +/* Content of this structure depends on information which is known and is + achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man + page for callbacks returning this structure -- some fields are mandatory, + some others are optional. The FLAG field has special meaning. */ +struct curl_fileinfo { + char *filename; + curlfiletype filetype; + time_t time; + unsigned int perm; + int uid; + int gid; + curl_off_t size; + long int hardlinks; + + struct { + /* If some of these fields is not NULL, it is a pointer to b_data. */ + char *time; + char *perm; + char *user; + char *group; + char *target; /* pointer to the target filename of a symlink */ + } strings; + + unsigned int flags; + + /* used internally */ + char * b_data; + size_t b_size; + size_t b_used; +}; + +/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ +#define CURL_CHUNK_BGN_FUNC_OK 0 +#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ +#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ + +/* if splitting of data transfer is enabled, this callback is called before + download of an individual chunk started. Note that parameter "remains" works + only for FTP wildcard downloading (for now), otherwise is not used */ +typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, + void *ptr, + int remains); + +/* return codes for CURLOPT_CHUNK_END_FUNCTION */ +#define CURL_CHUNK_END_FUNC_OK 0 +#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ + +/* If splitting of data transfer is enabled this callback is called after + download of an individual chunk finished. + Note! After this callback was set then it have to be called FOR ALL chunks. + Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. + This is the reason why we don't need "transfer_info" parameter in this + callback and we are not interested in "remains" parameter too. */ +typedef long (*curl_chunk_end_callback)(void *ptr); + +/* return codes for FNMATCHFUNCTION */ +#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ +#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */ +#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ + +/* callback type for wildcard downloading pattern matching. If the + string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ +typedef int (*curl_fnmatch_callback)(void *ptr, + const char *pattern, + const char *string); + +/* These are the return codes for the seek callbacks */ +#define CURL_SEEKFUNC_OK 0 +#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ +#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so + libcurl might try other means instead */ +typedef int (*curl_seek_callback)(void *instream, + curl_off_t offset, + int origin); /* 'whence' */ + +/* This is a return code for the read callback that, when returned, will + signal libcurl to immediately abort the current transfer. */ +#define CURL_READFUNC_ABORT 0x10000000 +/* This is a return code for the read callback that, when returned, will + signal libcurl to pause sending data on the current transfer. */ +#define CURL_READFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_read_callback)(char *buffer, + size_t size, + size_t nitems, + void *instream); + +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ + CURLSOCKTYPE_LAST /* never use */ +} curlsocktype; + +/* The return code from the sockopt_callback can signal information back + to libcurl: */ +#define CURL_SOCKOPT_OK 0 +#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return + CURLE_ABORTED_BY_CALLBACK */ +#define CURL_SOCKOPT_ALREADY_CONNECTED 2 + +typedef int (*curl_sockopt_callback)(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose); + +struct curl_sockaddr { + int family; + int socktype; + int protocol; + unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it + turned really ugly and painful on the systems that + lack this type */ + struct sockaddr addr; +}; + +typedef curl_socket_t +(*curl_opensocket_callback)(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address); + +typedef int +(*curl_closesocket_callback)(void *clientp, curl_socket_t item); + +typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ +} curlioerr; + +typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ +} curliocmd; + +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, + int cmd, + void *clientp); + ++#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS +/* + * The following typedef's are signatures of malloc, free, realloc, strdup and + * calloc respectively. Function pointers of these types can be passed to the + * curl_global_init_mem() function to set user defined memory management + * callback routines. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); + ++#define CURL_DID_MEMORY_FUNC_TYPEDEFS ++#endif ++ +/* the kind of data that is passed to information_callback*/ +typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} curl_infotype; + +typedef int (*curl_debug_callback) + (CURL *handle, /* the handle/transfer this concerns */ + curl_infotype type, /* what kind of data */ + char *data, /* points to the data */ + size_t size, /* size of the data pointed to */ + void *userptr); /* whatever the user please */ + +/* All possible error codes from all sorts of curl functions. Future versions + may return other values, stay prepared. + + Always add new return codes last. Never *EVER* remove any. The return + codes must remain the same! + */ + +typedef enum { + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ + CURLE_FAILED_INIT, /* 2 */ + CURLE_URL_MALFORMAT, /* 3 */ + CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for + 7.17.0, reused in April 2011 for 7.21.5] */ + CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ + CURLE_COULDNT_RESOLVE_HOST, /* 6 */ + CURLE_COULDNT_CONNECT, /* 7 */ + CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server + due to lack of access - when login fails + this is not returned. */ + CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for + 7.15.4, reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ + CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server + [was obsoleted in August 2007 for 7.17.0, + reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ + CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ + CURLE_FTP_CANT_GET_HOST, /* 15 */ + CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. + [was obsoleted in August 2007 for 7.17.0, + reused in July 2014 for 7.38.0] */ + CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ + CURLE_PARTIAL_FILE, /* 18 */ + CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ + CURLE_OBSOLETE20, /* 20 - NOT USED */ + CURLE_QUOTE_ERROR, /* 21 - quote command failure */ + CURLE_HTTP_RETURNED_ERROR, /* 22 */ + CURLE_WRITE_ERROR, /* 23 */ + CURLE_OBSOLETE24, /* 24 - NOT USED */ + CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */ + CURLE_READ_ERROR, /* 26 - couldn't open/read from file */ + CURLE_OUT_OF_MEMORY, /* 27 */ + /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error + instead of a memory allocation error if CURL_DOES_CONVERSIONS + is defined + */ + CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */ + CURLE_OBSOLETE29, /* 29 - NOT USED */ + CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ + CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ + CURLE_OBSOLETE32, /* 32 - NOT USED */ + CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ + CURLE_HTTP_POST_ERROR, /* 34 */ + CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ + CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ + CURLE_FILE_COULDNT_READ_FILE, /* 37 */ + CURLE_LDAP_CANNOT_BIND, /* 38 */ + CURLE_LDAP_SEARCH_FAILED, /* 39 */ + CURLE_OBSOLETE40, /* 40 - NOT USED */ + CURLE_FUNCTION_NOT_FOUND, /* 41 */ + CURLE_ABORTED_BY_CALLBACK, /* 42 */ + CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ + CURLE_OBSOLETE44, /* 44 - NOT USED */ + CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ + CURLE_OBSOLETE46, /* 46 - NOT USED */ - CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */ ++ CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */ + CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ - CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */ ++ CURLE_TELNET_OPTION_SYNTAX, /* 49 - Malformed telnet option */ + CURLE_OBSOLETE50, /* 50 - NOT USED */ + CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint + wasn't verified fine */ + CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ + CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ + CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as + default */ + CURLE_SEND_ERROR, /* 55 - failed sending network data */ + CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ + CURLE_OBSOLETE57, /* 57 - NOT IN USE */ + CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ + CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ + CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */ + CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ + CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ + CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ + CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ + CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind + that failed */ + CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ + CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not + accepted and we failed to login */ + CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ + CURLE_TFTP_PERM, /* 69 - permission problem on server */ + CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */ + CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ + CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ + CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */ + CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ + CURLE_CONV_FAILED, /* 75 - conversion failed */ + CURLE_CONV_REQD, /* 76 - caller must register conversion + callbacks using curl_easy_setopt options + CURLOPT_CONV_FROM_NETWORK_FUNCTION, + CURLOPT_CONV_TO_NETWORK_FUNCTION, and + CURLOPT_CONV_FROM_UTF8_FUNCTION */ + CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing + or wrong format */ + CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ + CURLE_SSH, /* 79 - error from the SSH layer, somewhat + generic so the error message will be of + interest when this has happened */ + + CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL + connection */ + CURLE_AGAIN, /* 81 - socket is not ready for send/recv, + wait till it's ready and try again (Added + in 7.18.2) */ + CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or + wrong format (Added in 7.19.0) */ + CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in + 7.19.0) */ + CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ + CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ + CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ + CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ + CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ + CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the + session will be queued */ + CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not + match */ + CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ ++ CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer ++ */ + CURL_LAST /* never use! */ +} CURLcode; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Previously obsolete error code re-used in 7.38.0 */ +#define CURLE_OBSOLETE16 CURLE_HTTP2 + +/* Previously obsolete error codes re-used in 7.24.0 */ +#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED +#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT + +/* compatibility with older names */ +#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING + +/* The following were added in 7.21.5, April 2011 */ +#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION + +/* The following were added in 7.17.1 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION + +/* The following were added in 7.17.0 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ +#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 +#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 +#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 +#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 +#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 +#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 +#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 +#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 +#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 +#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 +#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 +#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN + +#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED +#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE +#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR +#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL +#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS +#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR +#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED + +/* The following were added earlier */ + +#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT + +#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR +#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED +#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED + +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE +#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME + +/* This was the error code 50 in 7.7.3 and a few earlier versions, this + is no longer used by libcurl but is instead #defined here only to not + make programs break */ +#define CURLE_ALREADY_COMPLETE 99999 + +/* Provide defines for really old option names */ +#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ +#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ +#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA + +/* Since long deprecated options with no code in the lib that does anything + with them. */ +#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 +#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 + +#endif /*!CURL_NO_OLDIES*/ + +/* This prototype applies to all conversion callbacks */ +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); + +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ + void *ssl_ctx, /* actually an + OpenSSL SSL_CTX */ + void *userptr); + +typedef enum { + CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use + CONNECT HTTP/1.1 */ + CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT + HTTP/1.0 */ + CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already + in 7.10 */ + CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ + CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ + CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the + host name rather than the IP address. added + in 7.18.0 */ +} curl_proxytype; /* this enum was added in 7.10 */ + +/* + * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: + * + * CURLAUTH_NONE - No HTTP authentication + * CURLAUTH_BASIC - HTTP Basic authentication (default) + * CURLAUTH_DIGEST - HTTP Digest authentication + * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication + * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) + * CURLAUTH_NTLM - HTTP NTLM authentication + * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour + * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper + * CURLAUTH_ONLY - Use together with a single other type to force no + * authentication or just that single type + * CURLAUTH_ANY - All fine types set + * CURLAUTH_ANYSAFE - All fine types except Basic + */ + +#define CURLAUTH_NONE ((unsigned long)0) +#define CURLAUTH_BASIC (((unsigned long)1)<<0) +#define CURLAUTH_DIGEST (((unsigned long)1)<<1) +#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) +/* Deprecated since the advent of CURLAUTH_NEGOTIATE */ +#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE +#define CURLAUTH_NTLM (((unsigned long)1)<<3) +#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) +#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) +#define CURLAUTH_ONLY (((unsigned long)1)<<31) +#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) +#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) + +#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ +#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ +#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ +#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ +#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ +#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ +#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ +#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY + +#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ +#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ +#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ + +#define CURL_ERROR_SIZE 256 + +enum curl_khtype { + CURLKHTYPE_UNKNOWN, + CURLKHTYPE_RSA1, + CURLKHTYPE_RSA, + CURLKHTYPE_DSS +}; + +struct curl_khkey { + const char *key; /* points to a zero-terminated string encoded with base64 + if len is zero, otherwise to the "raw" data */ + size_t len; + enum curl_khtype keytype; +}; + +/* this is the set of return values expected from the curl_sshkeycallback + callback */ +enum curl_khstat { + CURLKHSTAT_FINE_ADD_TO_FILE, + CURLKHSTAT_FINE, + CURLKHSTAT_REJECT, /* reject the connection, return an error */ + CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so + this causes a CURLE_DEFER error but otherwise the + connection will be left intact etc */ + CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ +}; + +/* this is the set of status codes pass in to the callback */ +enum curl_khmatch { + CURLKHMATCH_OK, /* match */ + CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ + CURLKHMATCH_MISSING, /* no matching host/key found */ + CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */ +}; + +typedef int + (*curl_sshkeycallback) (CURL *easy, /* easy handle */ + const struct curl_khkey *knownkey, /* known */ + const struct curl_khkey *foundkey, /* found */ + enum curl_khmatch, /* libcurl's view on the keys */ + void *clientp); /* custom pointer passed from app */ + +/* parameter for the CURLOPT_USE_SSL option */ +typedef enum { + CURLUSESSL_NONE, /* do not attempt to use SSL */ + CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ + CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ + CURLUSESSL_ALL, /* SSL for all communication or fail */ + CURLUSESSL_LAST /* not an option, never use */ +} curl_usessl; + +/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ + +/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the + name of improving interoperability with older servers. Some SSL libraries + have introduced work-arounds for this flaw but those work-arounds sometimes + make the SSL communication fail. To regain functionality with those broken + servers, a user can this way allow the vulnerability back. */ +#define CURLSSLOPT_ALLOW_BEAST (1<<0) + +/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those + SSL backends where such behavior is present. */ +#define CURLSSLOPT_NO_REVOKE (1<<1) + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2009 */ + +#define CURLFTPSSL_NONE CURLUSESSL_NONE +#define CURLFTPSSL_TRY CURLUSESSL_TRY +#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL +#define CURLFTPSSL_ALL CURLUSESSL_ALL +#define CURLFTPSSL_LAST CURLUSESSL_LAST +#define curl_ftpssl curl_usessl +#endif /*!CURL_NO_OLDIES*/ + +/* parameter for the CURLOPT_FTP_SSL_CCC option */ +typedef enum { + CURLFTPSSL_CCC_NONE, /* do not send CCC */ + CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ + CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ + CURLFTPSSL_CCC_LAST /* not an option, never use */ +} curl_ftpccc; + +/* parameter for the CURLOPT_FTPSSLAUTH option */ +typedef enum { + CURLFTPAUTH_DEFAULT, /* let libcurl decide */ + CURLFTPAUTH_SSL, /* use "AUTH SSL" */ + CURLFTPAUTH_TLS, /* use "AUTH TLS" */ + CURLFTPAUTH_LAST /* not an option, never use */ +} curl_ftpauth; + +/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ +typedef enum { + CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ + CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD + again if MKD succeeded, for SFTP this does + similar magic */ + CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD + again even if MKD failed! */ + CURLFTP_CREATE_DIR_LAST /* not an option, never use */ +} curl_ftpcreatedir; + +/* parameter for the CURLOPT_FTP_FILEMETHOD option */ +typedef enum { + CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ + CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ + CURLFTPMETHOD_NOCWD, /* no CWD at all */ + CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ + CURLFTPMETHOD_LAST /* not an option, never use */ +} curl_ftpmethod; + +/* bitmask defines for CURLOPT_HEADEROPT */ +#define CURLHEADER_UNIFIED 0 +#define CURLHEADER_SEPARATE (1<<0) + +/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ +#define CURLPROTO_HTTP (1<<0) +#define CURLPROTO_HTTPS (1<<1) +#define CURLPROTO_FTP (1<<2) +#define CURLPROTO_FTPS (1<<3) +#define CURLPROTO_SCP (1<<4) +#define CURLPROTO_SFTP (1<<5) +#define CURLPROTO_TELNET (1<<6) +#define CURLPROTO_LDAP (1<<7) +#define CURLPROTO_LDAPS (1<<8) +#define CURLPROTO_DICT (1<<9) +#define CURLPROTO_FILE (1<<10) +#define CURLPROTO_TFTP (1<<11) +#define CURLPROTO_IMAP (1<<12) +#define CURLPROTO_IMAPS (1<<13) +#define CURLPROTO_POP3 (1<<14) +#define CURLPROTO_POP3S (1<<15) +#define CURLPROTO_SMTP (1<<16) +#define CURLPROTO_SMTPS (1<<17) +#define CURLPROTO_RTSP (1<<18) +#define CURLPROTO_RTMP (1<<19) +#define CURLPROTO_RTMPT (1<<20) +#define CURLPROTO_RTMPE (1<<21) +#define CURLPROTO_RTMPTE (1<<22) +#define CURLPROTO_RTMPS (1<<23) +#define CURLPROTO_RTMPTS (1<<24) +#define CURLPROTO_GOPHER (1<<25) +#define CURLPROTO_SMB (1<<26) +#define CURLPROTO_SMBS (1<<27) +#define CURLPROTO_ALL (~0) /* enable everything */ + +/* long may be 32 or 64 bits, but we should never depend on anything else + but 32 */ +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 ++#define CURLOPTTYPE_STRINGPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_OFF_T 30000 + ++/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the ++ string options from the header file */ ++ +/* name is uppercase CURLOPT_, + type is one of the defined CURLOPTTYPE_ + number is unique identifier */ +#ifdef CINIT +#undef CINIT +#endif + +#ifdef CURL_ISOCPP +#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT ++#define STRINGPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLOPT_/**/name = type + number +#endif + +/* + * This macro-mania below setups the CURLOPT_[what] enum, to be used with + * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] + * word. + */ + +typedef enum { + /* This is the FILE * or void * the regular output should be written to. */ + CINIT(WRITEDATA, OBJECTPOINT, 1), + + /* The full URL to get/put */ - CINIT(URL, OBJECTPOINT, 2), ++ CINIT(URL, STRINGPOINT, 2), + + /* Port number to connect to, if other than default. */ + CINIT(PORT, LONG, 3), + + /* Name of proxy to use. */ - CINIT(PROXY, OBJECTPOINT, 4), ++ CINIT(PROXY, STRINGPOINT, 4), + + /* "user:password;options" to use when fetching. */ - CINIT(USERPWD, OBJECTPOINT, 5), ++ CINIT(USERPWD, STRINGPOINT, 5), + + /* "user:password" to use with proxy. */ - CINIT(PROXYUSERPWD, OBJECTPOINT, 6), ++ CINIT(PROXYUSERPWD, STRINGPOINT, 6), + + /* Range to get, specified as an ASCII string. */ - CINIT(RANGE, OBJECTPOINT, 7), ++ CINIT(RANGE, STRINGPOINT, 7), + + /* not used */ + + /* Specified file stream to upload from (use as input): */ + CINIT(READDATA, OBJECTPOINT, 9), + + /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE + * bytes big. If this is not used, error messages go to stderr instead: */ + CINIT(ERRORBUFFER, OBJECTPOINT, 10), + + /* Function that will be called to store the output (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + + /* Function that will be called to read the input (instead of fread). The + * parameters will use fread() syntax, make sure to follow them. */ + CINIT(READFUNCTION, FUNCTIONPOINT, 12), + + /* Time-out the read operation after this amount of seconds */ + CINIT(TIMEOUT, LONG, 13), + + /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about + * how large the file being sent really is. That allows better error + * checking and better verifies that the upload was successful. -1 means + * unknown size. + * + * For large file support, there is also a _LARGE version of the key + * which takes an off_t type, allowing platforms with larger off_t + * sizes to handle larger files. See below for INFILESIZE_LARGE. + */ + CINIT(INFILESIZE, LONG, 14), + + /* POST static input fields. */ + CINIT(POSTFIELDS, OBJECTPOINT, 15), + + /* Set the referrer page (needed by some CGIs) */ - CINIT(REFERER, OBJECTPOINT, 16), ++ CINIT(REFERER, STRINGPOINT, 16), + + /* Set the FTP PORT string (interface name, named or numerical IP address) + Use i.e '-' to use default address. */ - CINIT(FTPPORT, OBJECTPOINT, 17), ++ CINIT(FTPPORT, STRINGPOINT, 17), + + /* Set the User-Agent string (examined by some CGIs) */ - CINIT(USERAGENT, OBJECTPOINT, 18), ++ CINIT(USERAGENT, STRINGPOINT, 18), + + /* If the download receives less than "low speed limit" bytes/second + * during "low speed time" seconds, the operations is aborted. + * You could i.e if you have a pretty high speed connection, abort if + * it is less than 2000 bytes/sec during 20 seconds. + */ + + /* Set the "low speed limit" */ + CINIT(LOW_SPEED_LIMIT, LONG, 19), + + /* Set the "low speed time" */ + CINIT(LOW_SPEED_TIME, LONG, 20), + + /* Set the continuation offset. + * + * Note there is also a _LARGE version of this key which uses + * off_t types, allowing for large file offsets on platforms which + * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. + */ + CINIT(RESUME_FROM, LONG, 21), + + /* Set cookie in request: */ - CINIT(COOKIE, OBJECTPOINT, 22), ++ CINIT(COOKIE, STRINGPOINT, 22), + + /* This points to a linked list of headers, struct curl_slist kind. This + list is also used for RTSP (in spite of its name) */ + CINIT(HTTPHEADER, OBJECTPOINT, 23), + + /* This points to a linked list of post entries, struct curl_httppost */ + CINIT(HTTPPOST, OBJECTPOINT, 24), + + /* name of the file keeping your private SSL-certificate */ - CINIT(SSLCERT, OBJECTPOINT, 25), ++ CINIT(SSLCERT, STRINGPOINT, 25), + + /* password for the SSL or SSH private key */ - CINIT(KEYPASSWD, OBJECTPOINT, 26), ++ CINIT(KEYPASSWD, STRINGPOINT, 26), + + /* send TYPE parameter? */ + CINIT(CRLF, LONG, 27), + + /* send linked-list of QUOTE commands */ + CINIT(QUOTE, OBJECTPOINT, 28), + + /* send FILE * or void * to store headers to, if you use a callback it + is simply passed to the callback unmodified */ + CINIT(HEADERDATA, OBJECTPOINT, 29), + + /* point to a file to read the initial cookies from, also enables + "cookie awareness" */ - CINIT(COOKIEFILE, OBJECTPOINT, 31), ++ CINIT(COOKIEFILE, STRINGPOINT, 31), + + /* What version to specifically try to use. + See CURL_SSLVERSION defines below. */ + CINIT(SSLVERSION, LONG, 32), + + /* What kind of HTTP time condition to use, see defines */ + CINIT(TIMECONDITION, LONG, 33), + + /* Time to use with the above condition. Specified in number of seconds + since 1 Jan 1970 */ + CINIT(TIMEVALUE, LONG, 34), + + /* 35 = OBSOLETE */ + + /* Custom request, for customizing the get command like + HTTP: DELETE, TRACE and others + FTP: to use a different list command + */ - CINIT(CUSTOMREQUEST, OBJECTPOINT, 36), ++ CINIT(CUSTOMREQUEST, STRINGPOINT, 36), + - /* HTTP request, for odd commands like DELETE, TRACE and others */ ++ /* FILE handle to use instead of stderr */ + CINIT(STDERR, OBJECTPOINT, 37), + + /* 38 is not used */ + + /* send linked-list of post-transfer QUOTE commands */ + CINIT(POSTQUOTE, OBJECTPOINT, 39), + + CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */ + + CINIT(VERBOSE, LONG, 41), /* talk a lot */ + CINIT(HEADER, LONG, 42), /* throw the header out too */ + CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ + CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ + CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */ + CINIT(UPLOAD, LONG, 46), /* this is an upload */ + CINIT(POST, LONG, 47), /* HTTP POST method */ + CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ + + CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */ + + /* Specify whether to read the user+password from the .netrc or the URL. + * This must be one of the CURL_NETRC_* enums below. */ + CINIT(NETRC, LONG, 51), + + CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + + CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ + CINIT(PUT, LONG, 54), /* HTTP PUT */ + + /* 55 = OBSOLETE */ + + /* DEPRECATED + * Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_progress_callback + * prototype defines. */ + CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), + + /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION + callbacks */ + CINIT(PROGRESSDATA, OBJECTPOINT, 57), +#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA + + /* We want the referrer field set automatically when following locations */ + CINIT(AUTOREFERER, LONG, 58), + + /* Port of the proxy, can be set in the proxy string as well with: + "[host]:[port]" */ + CINIT(PROXYPORT, LONG, 59), + + /* size of the POST input data, if strlen() is not good to use */ + CINIT(POSTFIELDSIZE, LONG, 60), + + /* tunnel non-http operations through a HTTP proxy */ + CINIT(HTTPPROXYTUNNEL, LONG, 61), + + /* Set the interface string to use as outgoing network interface */ - CINIT(INTERFACE, OBJECTPOINT, 62), ++ CINIT(INTERFACE, STRINGPOINT, 62), + + /* Set the krb4/5 security level, this also enables krb4/5 awareness. This + * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string + * is set but doesn't match one of these, 'private' will be used. */ - CINIT(KRBLEVEL, OBJECTPOINT, 63), ++ CINIT(KRBLEVEL, STRINGPOINT, 63), + + /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ + CINIT(SSL_VERIFYPEER, LONG, 64), + + /* The CApath or CAfile used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ - CINIT(CAINFO, OBJECTPOINT, 65), ++ CINIT(CAINFO, STRINGPOINT, 65), + + /* 66 = OBSOLETE */ + /* 67 = OBSOLETE */ + + /* Maximum number of http redirects to follow */ + CINIT(MAXREDIRS, LONG, 68), + + /* Pass a long set to 1 to get the date of the requested document (if + possible)! Pass a zero to shut it off. */ + CINIT(FILETIME, LONG, 69), + + /* This points to a linked list of telnet options */ + CINIT(TELNETOPTIONS, OBJECTPOINT, 70), + + /* Max amount of cached alive connections */ + CINIT(MAXCONNECTS, LONG, 71), + + CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */ + + /* 73 = OBSOLETE */ + + /* Set to explicitly use a new connection for the upcoming transfer. + Do not use this unless you're absolutely sure of this, as it makes the + operation slower and is less friendly for the network. */ + CINIT(FRESH_CONNECT, LONG, 74), + + /* Set to explicitly forbid the upcoming transfer's connection to be re-used + when done. Do not use this unless you're absolutely sure of this, as it + makes the operation slower and is less friendly for the network. */ + CINIT(FORBID_REUSE, LONG, 75), + + /* Set to a file name that contains random data for libcurl to use to + seed the random engine when doing SSL connects. */ - CINIT(RANDOM_FILE, OBJECTPOINT, 76), ++ CINIT(RANDOM_FILE, STRINGPOINT, 76), + + /* Set to the Entropy Gathering Daemon socket pathname */ - CINIT(EGDSOCKET, OBJECTPOINT, 77), ++ CINIT(EGDSOCKET, STRINGPOINT, 77), + + /* Time-out connect operations after this amount of seconds, if connects are + OK within this time, then fine... This only aborts the connect phase. */ + CINIT(CONNECTTIMEOUT, LONG, 78), + + /* Function that will be called to store headers (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), + + /* Set this to force the HTTP request to get back to GET. Only really usable + if POST, PUT or a custom request have been used first. + */ + CINIT(HTTPGET, LONG, 80), + + /* Set if we should verify the Common name from the peer certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches the + * provided hostname. */ + CINIT(SSL_VERIFYHOST, LONG, 81), + + /* Specify which file name to write all known cookies in after completed + operation. Set file name to "-" (dash) to make it go to stdout. */ - CINIT(COOKIEJAR, OBJECTPOINT, 82), ++ CINIT(COOKIEJAR, STRINGPOINT, 82), + + /* Specify which SSL ciphers to use */ - CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83), ++ CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83), + + /* Specify which HTTP version to use! This must be set to one of the + CURL_HTTP_VERSION* enums set below. */ + CINIT(HTTP_VERSION, LONG, 84), + + /* Specifically switch on or off the FTP engine's use of the EPSV command. By + default, that one will always be attempted before the more traditional + PASV command. */ + CINIT(FTP_USE_EPSV, LONG, 85), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ - CINIT(SSLCERTTYPE, OBJECTPOINT, 86), ++ CINIT(SSLCERTTYPE, STRINGPOINT, 86), + + /* name of the file keeping your private SSL-key */ - CINIT(SSLKEY, OBJECTPOINT, 87), ++ CINIT(SSLKEY, STRINGPOINT, 87), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ - CINIT(SSLKEYTYPE, OBJECTPOINT, 88), ++ CINIT(SSLKEYTYPE, STRINGPOINT, 88), + + /* crypto engine for the SSL-sub system */ - CINIT(SSLENGINE, OBJECTPOINT, 89), ++ CINIT(SSLENGINE, STRINGPOINT, 89), + + /* set the crypto engine for the SSL-sub system as default + the param has no meaning... + */ + CINIT(SSLENGINE_DEFAULT, LONG, 90), + + /* Non-zero value means to use the global dns cache */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ + + /* DNS cache timeout */ + CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + + /* send linked-list of pre-transfer QUOTE commands */ + CINIT(PREQUOTE, OBJECTPOINT, 93), + + /* set the debug function */ + CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), + + /* set the data for the debug function */ + CINIT(DEBUGDATA, OBJECTPOINT, 95), + + /* mark this as start of a cookie session */ + CINIT(COOKIESESSION, LONG, 96), + + /* The CApath directory used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ - CINIT(CAPATH, OBJECTPOINT, 97), ++ CINIT(CAPATH, STRINGPOINT, 97), + + /* Instruct libcurl to use a smaller receive buffer */ + CINIT(BUFFERSIZE, LONG, 98), + + /* Instruct libcurl to not use any signal/alarm handlers, even when using + timeouts. This option is useful for multi-threaded applications. + See libcurl-the-guide for more background information. */ + CINIT(NOSIGNAL, LONG, 99), + + /* Provide a CURLShare for mutexing non-ts data */ + CINIT(SHARE, OBJECTPOINT, 100), + + /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), + CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */ + CINIT(PROXYTYPE, LONG, 101), + + /* Set the Accept-Encoding string. Use this to tell a server you would like + the response to be compressed. Before 7.21.6, this was known as + CURLOPT_ENCODING */ - CINIT(ACCEPT_ENCODING, OBJECTPOINT, 102), ++ CINIT(ACCEPT_ENCODING, STRINGPOINT, 102), + + /* Set pointer to private data */ + CINIT(PRIVATE, OBJECTPOINT, 103), + + /* Set aliases for HTTP 200 in the HTTP Response header */ + CINIT(HTTP200ALIASES, OBJECTPOINT, 104), + + /* Continue to send authentication (user+password) when following locations, + even when hostname changed. This can potentially send off the name + and password to whatever host the server decides. */ + CINIT(UNRESTRICTED_AUTH, LONG, 105), + + /* Specifically switch on or off the FTP engine's use of the EPRT command ( + it also disables the LPRT attempt). By default, those ones will always be + attempted before the good old traditional PORT command. */ + CINIT(FTP_USE_EPRT, LONG, 106), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_USERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(HTTPAUTH, LONG, 107), + + /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx + in second argument. The function must be matching the + curl_ssl_ctx_callback proto. */ + CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), + + /* Set the userdata for the ssl context callback function's third + argument */ + CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), + + /* FTP Option that causes missing dirs to be created on the remote server. + In 7.19.4 we introduced the convenience enums for this option using the + CURLFTP_CREATE_DIR prefix. + */ + CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(PROXYAUTH, LONG, 111), + + /* FTP option that changes the timeout, in seconds, associated with + getting a response. This is different from transfer timeout time and + essentially places a demand on the FTP server to acknowledge commands + in a timely manner. */ + CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112), +#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT + + /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to + tell libcurl to resolve names to those IP versions only. This only has + affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ + CINIT(IPRESOLVE, LONG, 113), + + /* Set this option to limit the size of a file that will be downloaded from + an HTTP or FTP server. + + Note there is also _LARGE version which adds large file support for + platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ + CINIT(MAXFILESIZE, LONG, 114), + + /* See the comment for INFILESIZE above, but in short, specifies + * the size of the file being uploaded. -1 means unknown. + */ + CINIT(INFILESIZE_LARGE, OFF_T, 115), + + /* Sets the continuation offset. There is also a LONG version of this; + * look above for RESUME_FROM. + */ + CINIT(RESUME_FROM_LARGE, OFF_T, 116), + + /* Sets the maximum size of data that will be downloaded from + * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. + */ + CINIT(MAXFILESIZE_LARGE, OFF_T, 117), + + /* Set this option to the file name of your .netrc file you want libcurl + to parse (using the CURLOPT_NETRC option). If not set, libcurl will do + a poor attempt to find the user's home directory and check for a .netrc + file in there. */ - CINIT(NETRC_FILE, OBJECTPOINT, 118), ++ CINIT(NETRC_FILE, STRINGPOINT, 118), + + /* Enable SSL/TLS for FTP, pick one of: + CURLUSESSL_TRY - try using SSL, proceed anyway otherwise + CURLUSESSL_CONTROL - SSL for the control connection or fail + CURLUSESSL_ALL - SSL for all communication or fail + */ + CINIT(USE_SSL, LONG, 119), + + /* The _LARGE version of the standard POSTFIELDSIZE option */ + CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), + + /* Enable/disable the TCP Nagle algorithm */ + CINIT(TCP_NODELAY, LONG, 121), + + /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 123 OBSOLETE. Gone in 7.16.0 */ + /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 127 OBSOLETE. Gone in 7.16.0 */ + /* 128 OBSOLETE. Gone in 7.16.0 */ + + /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option + can be used to change libcurl's default action which is to first try + "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK + response has been received. + + Available parameters are: + CURLFTPAUTH_DEFAULT - let libcurl decide + CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS + CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL + */ + CINIT(FTPSSLAUTH, LONG, 129), + + CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), + CINIT(IOCTLDATA, OBJECTPOINT, 131), + + /* 132 OBSOLETE. Gone in 7.16.0 */ + /* 133 OBSOLETE. Gone in 7.16.0 */ + + /* zero terminated string for pass on to the FTP server when asked for + "account" info */ - CINIT(FTP_ACCOUNT, OBJECTPOINT, 134), ++ CINIT(FTP_ACCOUNT, STRINGPOINT, 134), + - /* feed cookies into cookie engine */ - CINIT(COOKIELIST, OBJECTPOINT, 135), ++ /* feed cookie into cookie engine */ ++ CINIT(COOKIELIST, STRINGPOINT, 135), + + /* ignore Content-Length */ + CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), + + /* Set to non-zero to skip the IP address received in a 227 PASV FTP server + response. Typically used for FTP-SSL purposes but is not restricted to + that. libcurl will then instead use the same IP address it used for the + control connection. */ + CINIT(FTP_SKIP_PASV_IP, LONG, 137), + + /* Select "file method" to use when doing FTP, see the curl_ftpmethod + above. */ + CINIT(FTP_FILEMETHOD, LONG, 138), + + /* Local port number to bind the socket to */ + CINIT(LOCALPORT, LONG, 139), + + /* Number of ports to try, including the first one set with LOCALPORT. + Thus, setting it to 1 will make no additional attempts but the first. + */ + CINIT(LOCALPORTRANGE, LONG, 140), + + /* no transfer, set up connection and let application use the socket by + extracting it with CURLINFO_LASTSOCKET */ + CINIT(CONNECT_ONLY, LONG, 141), + + /* Function that will be called to convert from the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), + + /* Function that will be called to convert to the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), + + /* Function that will be called to convert from UTF8 + (instead of using the iconv calls in libcurl) + Note that this is used only for SSL certificate processing */ + CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), + + /* if the connection proceeds too quickly then need to slow it down */ + /* limit-rate: maximum number of bytes per second to send or receive */ + CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), + CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), + + /* Pointer to command string to send if USER/PASS fails. */ - CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147), ++ CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147), + + /* callback function for setting socket options */ + CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), + CINIT(SOCKOPTDATA, OBJECTPOINT, 149), + + /* set to 0 to disable session ID re-use for this transfer, default is + enabled (== 1) */ + CINIT(SSL_SESSIONID_CACHE, LONG, 150), + + /* allowed SSH authentication methods */ + CINIT(SSH_AUTH_TYPES, LONG, 151), + + /* Used by scp/sftp to do public/private key authentication */ - CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152), - CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153), ++ CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152), ++ CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153), + + /* Send CCC (Clear Command Channel) after authentication */ + CINIT(FTP_SSL_CCC, LONG, 154), + + /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ + CINIT(TIMEOUT_MS, LONG, 155), + CINIT(CONNECTTIMEOUT_MS, LONG, 156), + + /* set to zero to disable the libcurl's decoding and thus pass the raw body + data to the application even when it is encoded/compressed */ + CINIT(HTTP_TRANSFER_DECODING, LONG, 157), + CINIT(HTTP_CONTENT_DECODING, LONG, 158), + + /* Permission used when creating new files and directories on the remote + server for protocols that support it, SFTP/SCP/FILE */ + CINIT(NEW_FILE_PERMS, LONG, 159), + CINIT(NEW_DIRECTORY_PERMS, LONG, 160), + + /* Set the behaviour of POST when redirecting. Values must be set to one + of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ + CINIT(POSTREDIR, LONG, 161), + + /* used by scp/sftp to verify the host's public key */ - CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162), ++ CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162), + + /* Callback function for opening socket (instead of socket(2)). Optionally, + callback is able change the address or refuse to connect returning + CURL_SOCKET_BAD. The callback should have type + curl_opensocket_callback */ + CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), + CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), + + /* POST volatile input fields. */ + CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165), + + /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ + CINIT(PROXY_TRANSFER_MODE, LONG, 166), + + /* Callback function for seeking in the input stream */ + CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167), + CINIT(SEEKDATA, OBJECTPOINT, 168), + + /* CRL file */ - CINIT(CRLFILE, OBJECTPOINT, 169), ++ CINIT(CRLFILE, STRINGPOINT, 169), + + /* Issuer certificate */ - CINIT(ISSUERCERT, OBJECTPOINT, 170), ++ CINIT(ISSUERCERT, STRINGPOINT, 170), + + /* (IPv6) Address scope */ + CINIT(ADDRESS_SCOPE, LONG, 171), + + /* Collect certificate chain info and allow it to get retrievable with + CURLINFO_CERTINFO after the transfer is complete. */ + CINIT(CERTINFO, LONG, 172), + + /* "name" and "pwd" to use when fetching. */ - CINIT(USERNAME, OBJECTPOINT, 173), - CINIT(PASSWORD, OBJECTPOINT, 174), ++ CINIT(USERNAME, STRINGPOINT, 173), ++ CINIT(PASSWORD, STRINGPOINT, 174), + + /* "name" and "pwd" to use with Proxy when fetching. */ - CINIT(PROXYUSERNAME, OBJECTPOINT, 175), - CINIT(PROXYPASSWORD, OBJECTPOINT, 176), ++ CINIT(PROXYUSERNAME, STRINGPOINT, 175), ++ CINIT(PROXYPASSWORD, STRINGPOINT, 176), + + /* Comma separated list of hostnames defining no-proxy zones. These should + match both hostnames directly, and hostnames within a domain. For + example, local.com will match local.com and www.local.com, but NOT + notlocal.com or www.notlocal.com. For compatibility with other + implementations of this, .local.com will be considered to be the same as + local.com. A single * is the only valid wildcard, and effectively + disables the use of proxy. */ - CINIT(NOPROXY, OBJECTPOINT, 177), ++ CINIT(NOPROXY, STRINGPOINT, 177), + + /* block size for TFTP transfers */ + CINIT(TFTP_BLKSIZE, LONG, 178), + + /* Socks Service */ - CINIT(SOCKS5_GSSAPI_SERVICE, OBJECTPOINT, 179), ++ CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */ + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), + + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ + CINIT(PROTOCOLS, LONG, 181), + + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. Defaults + to all protocols except FILE and SCP. */ + CINIT(REDIR_PROTOCOLS, LONG, 182), + + /* set the SSH knownhost file name to use */ - CINIT(SSH_KNOWNHOSTS, OBJECTPOINT, 183), ++ CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183), + + /* set the SSH host key callback, must point to a curl_sshkeycallback + function */ + CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184), + + /* set the SSH host key callback custom pointer */ + CINIT(SSH_KEYDATA, OBJECTPOINT, 185), + + /* set the SMTP mail originator */ - CINIT(MAIL_FROM, OBJECTPOINT, 186), ++ CINIT(MAIL_FROM, STRINGPOINT, 186), + - /* set the SMTP mail receiver(s) */ ++ /* set the list of SMTP mail receiver(s) */ + CINIT(MAIL_RCPT, OBJECTPOINT, 187), + + /* FTP: send PRET before PASV */ + CINIT(FTP_USE_PRET, LONG, 188), + + /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ + CINIT(RTSP_REQUEST, LONG, 189), + + /* The RTSP session identifier */ - CINIT(RTSP_SESSION_ID, OBJECTPOINT, 190), ++ CINIT(RTSP_SESSION_ID, STRINGPOINT, 190), + + /* The RTSP stream URI */ - CINIT(RTSP_STREAM_URI, OBJECTPOINT, 191), ++ CINIT(RTSP_STREAM_URI, STRINGPOINT, 191), + + /* The Transport: header to use in RTSP requests */ - CINIT(RTSP_TRANSPORT, OBJECTPOINT, 192), ++ CINIT(RTSP_TRANSPORT, STRINGPOINT, 192), + + /* Manually initialize the client RTSP CSeq for this handle */ + CINIT(RTSP_CLIENT_CSEQ, LONG, 193), + + /* Manually initialize the server RTSP CSeq for this handle */ + CINIT(RTSP_SERVER_CSEQ, LONG, 194), + + /* The stream to pass to INTERLEAVEFUNCTION. */ + CINIT(INTERLEAVEDATA, OBJECTPOINT, 195), + + /* Let the application define a custom write method for RTP data */ + CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196), + + /* Turn on wildcard matching */ + CINIT(WILDCARDMATCH, LONG, 197), + + /* Directory matching callback called before downloading of an + individual file (chunk) started */ + CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198), + + /* Directory matching callback called after the file (chunk) + was downloaded, or skipped */ + CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199), + + /* Change match (fnmatch-like) callback for wildcard matching */ + CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200), + + /* Let the application define custom chunk data pointer */ + CINIT(CHUNK_DATA, OBJECTPOINT, 201), + + /* FNMATCH_FUNCTION user pointer */ + CINIT(FNMATCH_DATA, OBJECTPOINT, 202), + + /* send linked-list of name:port:address sets */ + CINIT(RESOLVE, OBJECTPOINT, 203), + + /* Set a username for authenticated TLS */ - CINIT(TLSAUTH_USERNAME, OBJECTPOINT, 204), ++ CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204), + + /* Set a password for authenticated TLS */ - CINIT(TLSAUTH_PASSWORD, OBJECTPOINT, 205), ++ CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205), + + /* Set authentication type for authenticated TLS */ - CINIT(TLSAUTH_TYPE, OBJECTPOINT, 206), ++ CINIT(TLSAUTH_TYPE, STRINGPOINT, 206), + + /* Set to 1 to enable the "TE:" header in HTTP requests to ask for + compressed transfer-encoded responses. Set to 0 to disable the use of TE: + in outgoing requests. The current default is 0, but it might change in a + future libcurl release. + + libcurl will ask for the compressed methods it knows of, and if that + isn't any, it will not ask for transfer-encoding at all even if this + option is set to 1. + + */ + CINIT(TRANSFER_ENCODING, LONG, 207), + + /* Callback function for closing socket (instead of close(2)). The callback + should have type curl_closesocket_callback */ + CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), + CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), + + /* allow GSSAPI credential delegation */ + CINIT(GSSAPI_DELEGATION, LONG, 210), + + /* Set the name servers to use for DNS resolution */ - CINIT(DNS_SERVERS, OBJECTPOINT, 211), ++ CINIT(DNS_SERVERS, STRINGPOINT, 211), + + /* Time-out accept operations (currently for FTP only) after this amount + of miliseconds. */ + CINIT(ACCEPTTIMEOUT_MS, LONG, 212), + + /* Set TCP keepalive */ + CINIT(TCP_KEEPALIVE, LONG, 213), + + /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ + CINIT(TCP_KEEPIDLE, LONG, 214), + CINIT(TCP_KEEPINTVL, LONG, 215), + + /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ + CINIT(SSL_OPTIONS, LONG, 216), + + /* Set the SMTP auth originator */ - CINIT(MAIL_AUTH, OBJECTPOINT, 217), ++ CINIT(MAIL_AUTH, STRINGPOINT, 217), + + /* Enable/disable SASL initial response */ + CINIT(SASL_IR, LONG, 218), + + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_xferinfo_callback + * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ + CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), + + /* The XOAUTH2 bearer token */ - CINIT(XOAUTH2_BEARER, OBJECTPOINT, 220), ++ CINIT(XOAUTH2_BEARER, STRINGPOINT, 220), + + /* Set the interface string to use as outgoing network + * interface for DNS requests. + * Only supported by the c-ares DNS backend */ - CINIT(DNS_INTERFACE, OBJECTPOINT, 221), ++ CINIT(DNS_INTERFACE, STRINGPOINT, 221), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ - CINIT(DNS_LOCAL_IP4, OBJECTPOINT, 222), ++ CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ - CINIT(DNS_LOCAL_IP6, OBJECTPOINT, 223), ++ CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223), + + /* Set authentication options directly */ - CINIT(LOGIN_OPTIONS, OBJECTPOINT, 224), ++ CINIT(LOGIN_OPTIONS, STRINGPOINT, 224), + + /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_NPN, LONG, 225), + + /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_ALPN, LONG, 226), + + /* Time to wait for a response to a HTTP request containing an + * Expect: 100-continue header before sending the data anyway. */ + CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227), + + /* This points to a linked list of headers used for proxy requests only, + struct curl_slist kind */ + CINIT(PROXYHEADER, OBJECTPOINT, 228), + + /* Pass in a bitmask of "header options" */ + CINIT(HEADEROPT, LONG, 229), + + /* The public key in DER form used to validate the peer public key + this option is used only if SSL_VERIFYPEER is true */ - CINIT(PINNEDPUBLICKEY, OBJECTPOINT, 230), ++ CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230), + + /* Path to Unix domain socket */ - CINIT(UNIX_SOCKET_PATH, OBJECTPOINT, 231), ++ CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231), + + /* Set if we should verify the certificate status. */ + CINIT(SSL_VERIFYSTATUS, LONG, 232), + + /* Set if we should enable TLS false start. */ + CINIT(SSL_FALSESTART, LONG, 233), + + /* Do not squash dot-dot sequences */ + CINIT(PATH_AS_IS, LONG, 234), + + /* Proxy Service Name */ - CINIT(PROXY_SERVICE_NAME, OBJECTPOINT, 235), ++ CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235), + + /* Service Name */ - CINIT(SERVICE_NAME, OBJECTPOINT, 236), ++ CINIT(SERVICE_NAME, STRINGPOINT, 236), + + /* Wait/don't wait for pipe/mutex to clarify */ + CINIT(PIPEWAIT, LONG, 237), + ++ /* Set the protocol used when curl is given a URL without a protocol */ ++ CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238), ++ ++ /* Set stream weight, 1 - 256 (default is 16) */ ++ CINIT(STREAM_WEIGHT, LONG, 239), ++ ++ /* Set stream dependency on another CURL handle */ ++ CINIT(STREAM_DEPENDS, OBJECTPOINT, 240), ++ ++ /* Set E-xclusive stream dependency on another CURL handle */ ++ CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241), ++ ++ /* Do not send any tftp option requests to the server */ ++ CINIT(TFTP_NO_OPTIONS, LONG, 242), ++ ++ /* Linked-list of host:port:connect-to-host:connect-to-port, ++ overrides the URL's host:port (only for the network layer) */ ++ CINIT(CONNECT_TO, OBJECTPOINT, 243), ++ ++ /* Set TCP Fast Open */ ++ CINIT(TCP_FASTOPEN, LONG, 244), ++ + CURLOPT_LASTENTRY /* the last unused */ +} CURLoption; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2011 */ + +/* This was added in version 7.19.1 */ +#define CURLOPT_POST301 CURLOPT_POSTREDIR + +/* These are scheduled to disappear by 2009 */ + +/* The following were added in 7.17.0 */ +#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_FTPAPPEND CURLOPT_APPEND +#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY +#define CURLOPT_FTP_SSL CURLOPT_USE_SSL + +/* The following were added earlier */ + +#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL + +#else +/* This is set if CURL_NO_OLDIES is defined at compile-time */ +#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ +#endif + + + /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host + name resolves addresses using more than one IP protocol version, this + option might be handy to force libcurl to use a specific IP version. */ +#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP + versions that your system allows */ +#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */ +#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */ + + /* three convenient "aliases" that follow the name scheme better */ +#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER + + /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ +enum { + CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd + like the library to choose the best possible + for us! */ + CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ + CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ - CURL_HTTP_VERSION_2_0, /* please use HTTP 2.0 in the request */ ++ CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ ++ CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ ++ CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1 ++ Upgrade */ + + CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ +}; + +/* Convenience definition simple because the name of the version is HTTP/2 and + not 2.0. The 2_0 version of the enum name was set while the version was + still planned to be 2.0 and we stick to it for compatibility. */ +#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 + +/* + * Public API enums for RTSP requests + */ +enum { + CURL_RTSPREQ_NONE, /* first in list */ + CURL_RTSPREQ_OPTIONS, + CURL_RTSPREQ_DESCRIBE, + CURL_RTSPREQ_ANNOUNCE, + CURL_RTSPREQ_SETUP, + CURL_RTSPREQ_PLAY, + CURL_RTSPREQ_PAUSE, + CURL_RTSPREQ_TEARDOWN, + CURL_RTSPREQ_GET_PARAMETER, + CURL_RTSPREQ_SET_PARAMETER, + CURL_RTSPREQ_RECORD, + CURL_RTSPREQ_RECEIVE, + CURL_RTSPREQ_LAST /* last in list */ +}; + + /* These enums are for use with the CURLOPT_NETRC option. */ +enum CURL_NETRC_OPTION { + CURL_NETRC_IGNORED, /* The .netrc will never be read. + * This is the default. */ + CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred + * to one in the .netrc. */ + CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. + * Unless one is set programmatically, the .netrc + * will be queried. */ + CURL_NETRC_LAST +}; + +enum { + CURL_SSLVERSION_DEFAULT, + CURL_SSLVERSION_TLSv1, /* TLS 1.x */ + CURL_SSLVERSION_SSLv2, + CURL_SSLVERSION_SSLv3, + CURL_SSLVERSION_TLSv1_0, + CURL_SSLVERSION_TLSv1_1, + CURL_SSLVERSION_TLSv1_2, + + CURL_SSLVERSION_LAST /* never use, keep last */ +}; + +enum CURL_TLSAUTH { + CURL_TLSAUTH_NONE, + CURL_TLSAUTH_SRP, + CURL_TLSAUTH_LAST /* never use, keep last */ +}; + +/* symbols to use with CURLOPT_POSTREDIR. + CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 + can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 + | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ + +#define CURL_REDIR_GET_ALL 0 +#define CURL_REDIR_POST_301 1 +#define CURL_REDIR_POST_302 2 +#define CURL_REDIR_POST_303 4 +#define CURL_REDIR_POST_ALL \ + (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) + +typedef enum { + CURL_TIMECOND_NONE, + + CURL_TIMECOND_IFMODSINCE, + CURL_TIMECOND_IFUNMODSINCE, + CURL_TIMECOND_LASTMOD, + + CURL_TIMECOND_LAST +} curl_TimeCond; + + +/* curl_strequal() and curl_strnequal() are subject for removal in a future + libcurl, see lib/README.curlx for details */ +CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2); +CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n); + +/* name is uppercase CURLFORM_ */ +#ifdef CFINIT +#undef CFINIT +#endif + +#ifdef CURL_ISOCPP +#define CFINIT(name) CURLFORM_ ## name +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define CFINIT(name) CURLFORM_/**/name +#endif + +typedef enum { + CFINIT(NOTHING), /********* the first one is unused ************/ + + /* */ + CFINIT(COPYNAME), + CFINIT(PTRNAME), + CFINIT(NAMELENGTH), + CFINIT(COPYCONTENTS), + CFINIT(PTRCONTENTS), + CFINIT(CONTENTSLENGTH), + CFINIT(FILECONTENT), + CFINIT(ARRAY), + CFINIT(OBSOLETE), + CFINIT(FILE), + + CFINIT(BUFFER), + CFINIT(BUFFERPTR), + CFINIT(BUFFERLENGTH), + + CFINIT(CONTENTTYPE), + CFINIT(CONTENTHEADER), + CFINIT(FILENAME), + CFINIT(END), + CFINIT(OBSOLETE2), + + CFINIT(STREAM), ++ CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */ + + CURLFORM_LASTENTRY /* the last unused */ +} CURLformoption; + +#undef CFINIT /* done */ + +/* structure to be used as parameter for CURLFORM_ARRAY */ +struct curl_forms { + CURLformoption option; + const char *value; +}; + +/* use this for multipart formpost building */ +/* Returns code for curl_formadd() + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) + * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ +typedef enum { + CURL_FORMADD_OK, /* first, no error */ + + CURL_FORMADD_MEMORY, + CURL_FORMADD_OPTION_TWICE, + CURL_FORMADD_NULL, + CURL_FORMADD_UNKNOWN_OPTION, + CURL_FORMADD_INCOMPLETE, + CURL_FORMADD_ILLEGAL_ARRAY, + CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ + + CURL_FORMADD_LAST /* last */ +} CURLFORMcode; + +/* + * NAME curl_formadd() + * + * DESCRIPTION + * + * Pretty advanced function for building multi-part formposts. Each invoke + * adds one part that together construct a full post. Then use + * CURLOPT_HTTPPOST to send it off to libcurl. + */ +CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...); + +/* + * callback function for curl_formget() + * The void *arg pointer will be the one passed as second argument to + * curl_formget(). + * The character buffer passed to it must not be freed. + * Should return the buffer length passed to it as the argument "len" on + * success. + */ +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, + size_t len); + +/* + * NAME curl_formget() + * + * DESCRIPTION + * + * Serialize a curl_httppost struct built with curl_formadd(). + * Accepts a void pointer as second argument which will be passed to + * the curl_formget_callback function. + * Returns 0 on success. + */ +CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append); +/* + * NAME curl_formfree() + * + * DESCRIPTION + * + * Free a multipart formpost previously built with curl_formadd(). + */ +CURL_EXTERN void curl_formfree(struct curl_httppost *form); + +/* + * NAME curl_getenv() + * + * DESCRIPTION + * + * Returns a malloc()'ed string that MUST be curl_free()ed after usage is + * complete. DEPRECATED - see lib/README.curlx + */ +CURL_EXTERN char *curl_getenv(const char *variable); + +/* + * NAME curl_version() + * + * DESCRIPTION + * + * Returns a static ascii string of the libcurl version. + */ +CURL_EXTERN char *curl_version(void); + +/* + * NAME curl_easy_escape() + * + * DESCRIPTION + * + * Escapes URL strings (converts all letters consider illegal in URLs to their + * %XX versions). This function returns a new allocated string or NULL if an + * error occurred. + */ +CURL_EXTERN char *curl_easy_escape(CURL *handle, + const char *string, + int length); + +/* the previous version: */ +CURL_EXTERN char *curl_escape(const char *string, + int length); + + +/* + * NAME curl_easy_unescape() + * + * DESCRIPTION + * + * Unescapes URL encoding in strings (converts all %XX codes to their 8bit + * versions). This function returns a new allocated string or NULL if an error + * occurred. + * Conversion Note: On non-ASCII platforms the ASCII %XX codes are + * converted into the host encoding. + */ +CURL_EXTERN char *curl_easy_unescape(CURL *handle, + const char *string, + int length, + int *outlength); + +/* the previous version */ +CURL_EXTERN char *curl_unescape(const char *string, + int length); + +/* + * NAME curl_free() + * + * DESCRIPTION + * + * Provided for de-allocation in the same translation unit that did the + * allocation. Added in libcurl 7.10 + */ +CURL_EXTERN void curl_free(void *p); + +/* + * NAME curl_global_init() + * + * DESCRIPTION + * + * curl_global_init() should be invoked exactly once for each application that + * uses libcurl and before any call of other libcurl functions. + * + * This function is not thread-safe! + */ +CURL_EXTERN CURLcode curl_global_init(long flags); + +/* + * NAME curl_global_init_mem() + * + * DESCRIPTION + * + * curl_global_init() or curl_global_init_mem() should be invoked exactly once + * for each application that uses libcurl. This function can be used to + * initialize libcurl and set user defined memory management callback + * functions. Users can implement memory management routines to check for + * memory leaks, check for mis-use of the curl library etc. User registered + * callback routines with be invoked by this library instead of the system + * memory management routines like malloc, free etc. + */ +CURL_EXTERN CURLcode curl_global_init_mem(long flags, + curl_malloc_callback m, + curl_free_callback f, + curl_realloc_callback r, + curl_strdup_callback s, + curl_calloc_callback c); + +/* + * NAME curl_global_cleanup() + * + * DESCRIPTION + * + * curl_global_cleanup() should be invoked exactly once for each application + * that uses libcurl + */ +CURL_EXTERN void curl_global_cleanup(void); + +/* linked-list structure for the CURLOPT_QUOTE option (and other) */ +struct curl_slist { + char *data; + struct curl_slist *next; +}; + +/* + * NAME curl_slist_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, + const char *); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist. + */ +CURL_EXTERN void curl_slist_free_all(struct curl_slist *); + +/* + * NAME curl_getdate() + * + * DESCRIPTION + * + * Returns the time, in seconds since 1 Jan 1970 of the time string given in + * the first argument. The time argument in the second parameter is unused + * and should be set to NULL. + */ +CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); + +/* info about the certificate chain, only for OpenSSL builds. Asked + for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ +struct curl_certinfo { + int num_of_certs; /* number of certificates with information */ + struct curl_slist **certinfo; /* for each index in this array, there's a + linked list with textual information in the + format "name: value" */ +}; + +/* enum for the different supported SSL backends */ +typedef enum { + CURLSSLBACKEND_NONE = 0, + CURLSSLBACKEND_OPENSSL = 1, + CURLSSLBACKEND_GNUTLS = 2, + CURLSSLBACKEND_NSS = 3, + CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ + CURLSSLBACKEND_GSKIT = 5, + CURLSSLBACKEND_POLARSSL = 6, + CURLSSLBACKEND_CYASSL = 7, + CURLSSLBACKEND_SCHANNEL = 8, + CURLSSLBACKEND_DARWINSSL = 9, - CURLSSLBACKEND_AXTLS = 10 ++ CURLSSLBACKEND_AXTLS = 10, ++ CURLSSLBACKEND_MBEDTLS = 11 +} curl_sslbackend; + ++/* aliases for library clones and renames */ ++#define CURLSSLBACKEND_LIBRESSL 1 ++#define CURLSSLBACKEND_BORINGSSL 1 ++#define CURLSSLBACKEND_WOLFSSL 6 ++ +/* Information about the SSL library used and the respective internal SSL + handle, which can be used to obtain further information regarding the - connection. Asked for with CURLINFO_TLS_SESSION. */ ++ connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ +struct curl_tlssessioninfo { + curl_sslbackend backend; + void *internals; +}; + +#define CURLINFO_STRING 0x100000 +#define CURLINFO_LONG 0x200000 +#define CURLINFO_DOUBLE 0x300000 +#define CURLINFO_SLIST 0x400000 ++#define CURLINFO_SOCKET 0x500000 +#define CURLINFO_MASK 0x0fffff +#define CURLINFO_TYPEMASK 0xf00000 + +typedef enum { + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, + CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, + CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, + CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, + CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, + CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, + CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, + CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, + CURLINFO_CERTINFO = CURLINFO_SLIST + 34, + CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, + CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, + CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, + CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, + CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, + CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, + CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, + CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, + CURLINFO_TLS_SESSION = CURLINFO_SLIST + 43, ++ CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, ++ CURLINFO_TLS_SSL_PTR = CURLINFO_SLIST + 45, ++ CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, + /* Fill in new entries below here! */ + - CURLINFO_LASTONE = 43 ++ CURLINFO_LASTONE = 46 +} CURLINFO; + +/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as + CURLINFO_HTTP_CODE */ +#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE + +typedef enum { + CURLCLOSEPOLICY_NONE, /* first, never use this */ + + CURLCLOSEPOLICY_OLDEST, + CURLCLOSEPOLICY_LEAST_RECENTLY_USED, + CURLCLOSEPOLICY_LEAST_TRAFFIC, + CURLCLOSEPOLICY_SLOWEST, + CURLCLOSEPOLICY_CALLBACK, + + CURLCLOSEPOLICY_LAST /* last, never use this */ +} curl_closepolicy; + +#define CURL_GLOBAL_SSL (1<<0) +#define CURL_GLOBAL_WIN32 (1<<1) +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_NOTHING 0 +#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL +#define CURL_GLOBAL_ACK_EINTR (1<<2) + + +/***************************************************************************** + * Setup defines, protos etc for the sharing stuff. + */ + +/* Different data locks for a single share */ +typedef enum { + CURL_LOCK_DATA_NONE = 0, + /* CURL_LOCK_DATA_SHARE is used internally to say that + * the locking is just made to change the internal state of the share + * itself. + */ + CURL_LOCK_DATA_SHARE, + CURL_LOCK_DATA_COOKIE, + CURL_LOCK_DATA_DNS, + CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_DATA_CONNECT, + CURL_LOCK_DATA_LAST +} curl_lock_data; + +/* Different lock access types */ +typedef enum { + CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ + CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ + CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ + CURL_LOCK_ACCESS_LAST /* never use */ +} curl_lock_access; + +typedef void (*curl_lock_function)(CURL *handle, + curl_lock_data data, + curl_lock_access locktype, + void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, + curl_lock_data data, + void *userptr); + - typedef void CURLSH; + +typedef enum { + CURLSHE_OK, /* all is fine */ + CURLSHE_BAD_OPTION, /* 1 */ + CURLSHE_IN_USE, /* 2 */ + CURLSHE_INVALID, /* 3 */ + CURLSHE_NOMEM, /* 4 out of memory */ + CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ + CURLSHE_LAST /* never use */ +} CURLSHcode; + +typedef enum { + CURLSHOPT_NONE, /* don't use */ + CURLSHOPT_SHARE, /* specify a data type to share */ + CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ + CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ + CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ + CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock + callback functions */ + CURLSHOPT_LAST /* never use */ +} CURLSHoption; + +CURL_EXTERN CURLSH *curl_share_init(void); +CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); +CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); + +/**************************************************************************** + * Structures for querying information about the curl library at runtime. + */ + +typedef enum { + CURLVERSION_FIRST, + CURLVERSION_SECOND, + CURLVERSION_THIRD, + CURLVERSION_FOURTH, + CURLVERSION_LAST /* never actually use this */ +} CURLversion; + +/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by + basically all programs ever that want to get version information. It is + meant to be a built-in version number for what kind of struct the caller + expects. If the struct ever changes, we redefine the NOW to another enum + from above. */ +#define CURLVERSION_NOW CURLVERSION_FOURTH + +typedef struct { + CURLversion age; /* age of the returned struct */ + const char *version; /* LIBCURL_VERSION */ + unsigned int version_num; /* LIBCURL_VERSION_NUM */ + const char *host; /* OS/host/cpu/machine when configured */ + int features; /* bitmask, see defines below */ + const char *ssl_version; /* human readable string */ + long ssl_version_num; /* not used anymore, always 0 */ + const char *libz_version; /* human readable string */ + /* protocols is terminated by an entry with a NULL protoname */ + const char * const *protocols; + + /* The fields below this were added in CURLVERSION_SECOND */ + const char *ares; + int ares_num; + + /* This field was added in CURLVERSION_THIRD */ + const char *libidn; + + /* These field were added in CURLVERSION_FOURTH */ + + /* Same as '_libiconv_version' if built with HAVE_ICONV */ + int iconv_ver_num; + + const char *libssh_version; /* human readable string */ + +} curl_version_info_data; + +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported + (deprecated) */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported + (deprecated) */ +#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ +#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are + supported */ +#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ +#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ +#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ +#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ +#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper + is suported */ +#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ +#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ +#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ +#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ ++#define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used ++ for cookie domain verification */ + + /* + * NAME curl_version_info() + * + * DESCRIPTION + * + * This function returns a pointer to a static copy of the version info + * struct. See above. + */ +CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); + +/* + * NAME curl_easy_strerror() + * + * DESCRIPTION + * + * The curl_easy_strerror function may be used to turn a CURLcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_easy_strerror(CURLcode); + +/* + * NAME curl_share_strerror() + * + * DESCRIPTION + * + * The curl_share_strerror function may be used to turn a CURLSHcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_share_strerror(CURLSHcode); + +/* + * NAME curl_easy_pause() + * + * DESCRIPTION + * + * The curl_easy_pause function pauses or unpauses transfers. Select the new + * state by setting the bitmask, use the convenience defines below. + * + */ +CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); + +#define CURLPAUSE_RECV (1<<0) +#define CURLPAUSE_RECV_CONT (0) + +#define CURLPAUSE_SEND (1<<2) +#define CURLPAUSE_SEND_CONT (0) + +#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) +#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) + +#ifdef __cplusplus +} +#endif + +/* unfortunately, the easy.h and multi.h include files need options and info + stuff before they can be included! */ +#include "easy.h" /* nothing in curl is fun without the easy stuff */ +#include "multi.h" + +/* the typechecker doesn't work in C++ (yet) */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ + !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) +#include "typecheck-gcc.h" +#else +#if defined(__STDC__) && (__STDC__ >= 1) +#if 0 /* Triggers clang -Wdisabled-macro-expansion, skip for CMake. */ +/* This preprocessor magic that replaces a call with the exact same call is + only done to make sure application authors pass exactly three arguments + to these functions. */ +#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param) +#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg) +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) +#endif +#endif /* __STDC__ >= 1 */ +#endif /* gcc >= 4.3 && !__cplusplus */ + +#endif /* __CURL_CURL_H */ diff --cc Utilities/cmcurl/include/curl/curlbuild.h.cmake index 6608694,0000000..c8b4f52 mode 100644,000000..100644 --- a/Utilities/cmcurl/include/curl/curlbuild.h.cmake +++ b/Utilities/cmcurl/include/curl/curlbuild.h.cmake @@@ -1,218 -1,0 +1,218 @@@ +#ifndef __CURL_CURLBUILD_H +#define __CURL_CURLBUILD_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. ++ * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the libcurl development - * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/ ++ * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/ + * + * This header file shall only export symbols which are 'curl' or 'CURL' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file include/curl/curlbuild.h.in or + * at file include/curl/curlbuild.h, this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed include/curl/curlbuild.h file with one that + * is suitable and specific to the library being configured and built, which + * is generated from the include/curl/curlbuild.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CURL_SIZEOF_LONG +#error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T +#error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_SOCKLEN_T +#error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_OFF_T +#error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_T +#error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_TU +#error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined +#endif + +#ifdef CURL_FORMAT_OFF_T +#error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_OFF_T +#error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_T +#error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_TU +#error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file ws2tcpip.h must be included by the external interface. */ +#cmakedefine CURL_PULL_WS2TCPIP_H +#ifdef CURL_PULL_WS2TCPIP_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +#cmakedefine CURL_PULL_SYS_TYPES_H +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file stdint.h must be included by the external interface. */ +#cmakedefine CURL_PULL_STDINT_H +#ifdef CURL_PULL_STDINT_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file inttypes.h must be included by the external interface. */ +#cmakedefine CURL_PULL_INTTYPES_H +#ifdef CURL_PULL_INTTYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/socket.h must be included by the external interface. */ +#cmakedefine CURL_PULL_SYS_SOCKET_H +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/poll.h must be included by the external interface. */ +#cmakedefine CURL_PULL_SYS_POLL_H +#ifdef CURL_PULL_SYS_POLL_H +# include +#endif + +/* The size of `int', as computed by sizeof. */ + at CURL_SIZEOF_INT_CODE@ + +/* The size of `long', as computed by sizeof. */ + at CURL_SIZEOF_LONG_CODE@ + +/* The size of `long long', as computed by sizeof. */ + at CURL_SIZEOF_LONG_LONG_CODE@ + +/* The size of `ssize_t', as computed by sizeof. */ + at CURL_SIZEOF_SSIZE_T_CODE@ + +#define CURL_HAVE_SOCKLEN_T @CURL_HAVE_SOCKLEN_T@ +#if CURL_HAVE_SOCKLEN_T +/* Integral data type used for curl_socklen_t. */ +#define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t + +/* The size of `curl_socklen_t', as computed by sizeof. */ + at CURL_SIZEOF_CURL_SOCKLEN_T_CODE@ +#else +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T CURL_SIZEOF_INT +#endif + +/* Data type definition of curl_socklen_t. */ +typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; + +#if CURL_SIZEOF_LONG == 8 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +#elif CURL_SIZEOF_LONG_LONG == 8 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +#else +# define CURL_TYPEOF_CURL_OFF_T ssize_t +# define CURL_SIZEOF_CURL_OFF_T CURL_SIZEOF_SSIZE_T +/* TODO: need adjustment here. */ +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +#endif + +/* Data type definition of curl_off_t. */ +typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; + +#endif /* __CURL_CURLBUILD_H */ diff --cc Utilities/cmcurl/include/curl/curlver.h index a41fdef,0000000..09f612a mode 100644,000000..100644 --- a/Utilities/cmcurl/include/curl/curlver.h +++ b/Utilities/cmcurl/include/curl/curlver.h @@@ -1,77 -1,0 +1,77 @@@ +#ifndef __CURL_CURLVER_H +#define __CURL_CURLVER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. ++ * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. ++ * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* This header file contains nothing but libcurl version info, generated by + a script at release-time. This was made its own header file in 7.11.2 */ + +/* This is the global package copyright */ - #define LIBCURL_COPYRIGHT "1996 - 2015 Daniel Stenberg, ." ++#define LIBCURL_COPYRIGHT "1996 - 2016 Daniel Stenberg, ." + +/* This is the version number of the libcurl package from which this header + file origins: */ - #define LIBCURL_VERSION "7.44.0" ++#define LIBCURL_VERSION "7.50.1" + +/* The numeric version number is also available "in parts" by using these + defines: */ +#define LIBCURL_VERSION_MAJOR 7 - #define LIBCURL_VERSION_MINOR 44 - #define LIBCURL_VERSION_PATCH 0 ++#define LIBCURL_VERSION_MINOR 50 ++#define LIBCURL_VERSION_PATCH 1 + +/* This is the numeric version of the libcurl version number, meant for easier + parsing and comparions by programs. The LIBCURL_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + Where XX, YY and ZZ are the main version, release and patch numbers in + hexadecimal (using 8 bits each). All three numbers are always represented + using two digits. 1.2 would appear as "0x010200" while version 9.11.7 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. + + Note: This define is the full hex number and _does not_ use the + CURL_VERSION_BITS() macro since curl's own configure script greps for it + and needs it to contain the full number. +*/ - #define LIBCURL_VERSION_NUM 0x072C00 ++#define LIBCURL_VERSION_NUM 0x073201 + +/* + * This is the date and time when the full source package was created. The + * timestamp is not stored in git, as the timestamp is properly set in the + * tarballs by the maketgz script. + * + * The format of the date should follow this template: + * + * "Mon Feb 12 11:35:33 UTC 2007" + */ +#define LIBCURL_TIMESTAMP "DEV" + +#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) +#define CURL_AT_LEAST_VERSION(x,y,z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) + +#endif /* __CURL_CURLVER_H */ diff --cc Utilities/cmcurl/include/curl/multi.h index 0f1561d,0000000..f93e511 mode 100644,000000..100644 --- a/Utilities/cmcurl/include/curl/multi.h +++ b/Utilities/cmcurl/include/curl/multi.h @@@ -1,435 -1,0 +1,439 @@@ +#ifndef __CURL_MULTI_H +#define __CURL_MULTI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. ++ * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. ++ * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +/* + This is an "external" header file. Don't give away any internals here! + + GOALS + + o Enable a "pull" interface. The application that uses libcurl decides where + and when to ask libcurl to get/send data. + + o Enable multiple simultaneous transfers in the same thread without making it + complicated for the application. + + o Enable the application to select() on its own file descriptors and curl's + file descriptors simultaneous easily. + +*/ + +/* + * This header file should not really need to include "curl.h" since curl.h + * itself includes this file and we expect user applications to do #include + * without the need for especially including multi.h. + * + * For some reason we added this include here at one point, and rather than to + * break existing (wrongly written) libcurl applications, we leave it as-is + * but with this warning attached. + */ +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + ++#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) ++typedef struct Curl_multi CURLM; ++#else +typedef void CURLM; ++#endif + +typedef enum { + CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or + curl_multi_socket*() soon */ + CURLM_OK, + CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ + CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ + CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ + CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ + CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ + CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ + CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was + attempted to get added - again */ + CURLM_LAST +} CURLMcode; + +/* just to make code nicer when using curl_multi_socket() you can now check + for CURLM_CALL_MULTI_SOCKET too in the same style it works for + curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ +#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM + +/* bitmask bits for CURLMOPT_PIPELINING */ +#define CURLPIPE_NOTHING 0L +#define CURLPIPE_HTTP1 1L +#define CURLPIPE_MULTIPLEX 2L + +typedef enum { + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST /* last, not used */ +} CURLMSG; + +struct CURLMsg { + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; +}; +typedef struct CURLMsg CURLMsg; + +/* Based on poll(2) structure and values. + * We don't use pollfd and POLL* constants explicitly + * to cover platforms without poll(). */ +#define CURL_WAIT_POLLIN 0x0001 +#define CURL_WAIT_POLLPRI 0x0002 +#define CURL_WAIT_POLLOUT 0x0004 + +struct curl_waitfd { + curl_socket_t fd; + short events; + short revents; /* not supported yet */ +}; + +/* + * Name: curl_multi_init() + * + * Desc: inititalize multi-style curl usage + * + * Returns: a new CURLM handle to use in all 'curl_multi' functions. + */ +CURL_EXTERN CURLM *curl_multi_init(void); + +/* + * Name: curl_multi_add_handle() + * + * Desc: add a standard curl handle to the multi stack + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_remove_handle() + * + * Desc: removes a curl handle from the multi stack again + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_fdset() + * + * Desc: Ask curl for its fd_set sets. The app can use these to select() or + * poll() on. We want curl_multi_perform() called as soon as one of + * them are ready. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); + +/* + * Name: curl_multi_wait() + * + * Desc: Poll on all fds within a CURLM set as well as any + * additional fds passed to the function. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret); + + /* + * Name: curl_multi_perform() + * + * Desc: When the app thinks there's data available for curl it calls this + * function to read/write whatever there is right now. This returns + * as soon as the reads and writes are done. This function does not + * require that there actually is data available for reading or that + * data can be written, it can be called just in case. It returns + * the number of handles that still transfer data in the second + * argument's integer-pointer. + * + * Returns: CURLMcode type, general multi error code. *NOTE* that this only + * returns errors etc regarding the whole multi stack. There might + * still have occurred problems on invidual transfers even when this + * returns OK. + */ +CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, + int *running_handles); + + /* + * Name: curl_multi_cleanup() + * + * Desc: Cleans up and removes a whole multi stack. It does not free or + * touch any individual easy handles in any way. We need to define + * in what state those handles will be if this function is called + * in the middle of a transfer. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); + +/* + * Name: curl_multi_info_read() + * + * Desc: Ask the multi handle if there's any messages/informationals from + * the individual transfers. Messages include informationals such as + * error code from the transfer or just the fact that a transfer is + * completed. More details on these should be written down as well. + * + * Repeated calls to this function will return a new struct each + * time, until a special "end of msgs" struct is returned as a signal + * that there is no more to get at this point. + * + * The data the returned pointer points to will not survive calling + * curl_multi_cleanup(). + * + * The 'CURLMsg' struct is meant to be very simple and only contain + * very basic information. If more involved information is wanted, + * we will provide the particular "transfer handle" in that struct + * and that should/could/would be used in subsequent + * curl_easy_getinfo() calls (or similar). The point being that we + * must never expose complex structs to applications, as then we'll + * undoubtably get backwards compatibility problems in the future. + * + * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out + * of structs. It also writes the number of messages left in the + * queue (after this read) in the integer the second argument points + * to. + */ +CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, + int *msgs_in_queue); + +/* + * Name: curl_multi_strerror() + * + * Desc: The curl_multi_strerror function may be used to turn a CURLMcode + * value into the equivalent human readable error string. This is + * useful for printing meaningful error messages. + * + * Returns: A pointer to a zero-terminated error message. + */ +CURL_EXTERN const char *curl_multi_strerror(CURLMcode); + +/* + * Name: curl_multi_socket() and + * curl_multi_socket_all() + * + * Desc: An alternative version of curl_multi_perform() that allows the + * application to pass in one of the file descriptors that have been + * detected to have "action" on them and let libcurl perform. + * See man page for details. + */ +#define CURL_POLL_NONE 0 +#define CURL_POLL_IN 1 +#define CURL_POLL_OUT 2 +#define CURL_POLL_INOUT 3 +#define CURL_POLL_REMOVE 4 + +#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD + +#define CURL_CSELECT_IN 0x01 +#define CURL_CSELECT_OUT 0x02 +#define CURL_CSELECT_ERR 0x04 + +typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp); /* private socket + pointer */ +/* + * Name: curl_multi_timer_callback + * + * Desc: Called by libcurl whenever the library detects a change in the + * maximum number of milliseconds the app is allowed to wait before + * curl_multi_socket() or curl_multi_perform() must be called + * (to allow libcurl's timed events to take place). + * + * Returns: The callback should return zero. + */ +typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp); /* private callback + pointer */ + +CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, + curl_socket_t s, + int ev_bitmask, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, + int *running_handles); + +#ifndef CURL_ALLOW_OLD_MULTI_SOCKET +/* This macro below was added in 7.16.3 to push users who recompile to use + the new curl_multi_socket_action() instead of the old curl_multi_socket() +*/ +#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) +#endif + +/* + * Name: curl_multi_timeout() + * + * Desc: Returns the maximum number of milliseconds the app is allowed to + * wait before curl_multi_socket() or curl_multi_perform() must be + * called (to allow libcurl's timed events to take place). + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, + long *milliseconds); + +#undef CINIT /* re-using the same name as in curl.h */ + +#ifdef CURL_ISOCPP +#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLMOPT_/**/name = type + number +#endif + +typedef enum { + /* This is the socket callback function pointer */ + CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), + + /* This is the argument passed to the socket callback */ + CINIT(SOCKETDATA, OBJECTPOINT, 2), + + /* set to 1 to enable pipelining for this multi handle */ + CINIT(PIPELINING, LONG, 3), + + /* This is the timer callback function pointer */ + CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), + + /* This is the argument passed to the timer callback */ + CINIT(TIMERDATA, OBJECTPOINT, 5), + + /* maximum number of entries in the connection cache */ + CINIT(MAXCONNECTS, LONG, 6), + + /* maximum number of (pipelining) connections to one host */ + CINIT(MAX_HOST_CONNECTIONS, LONG, 7), + + /* maximum number of requests in a pipeline */ + CINIT(MAX_PIPELINE_LENGTH, LONG, 8), + + /* a connection with a content-length longer than this + will not be considered for pipelining */ + CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9), + + /* a connection with a chunk length longer than this + will not be considered for pipelining */ + CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10), + + /* a list of site names(+port) that are blacklisted from + pipelining */ + CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11), + + /* a list of server types that are blacklisted from + pipelining */ + CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12), + + /* maximum number of open connections in total */ + CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), + + /* This is the server push callback function pointer */ + CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14), + + /* This is the argument passed to the server push callback */ + CINIT(PUSHDATA, OBJECTPOINT, 15), + + CURLMOPT_LASTENTRY /* the last unused */ +} CURLMoption; + + +/* + * Name: curl_multi_setopt() + * + * Desc: Sets options for the multi handle. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, + CURLMoption option, ...); + + +/* + * Name: curl_multi_assign() + * + * Desc: This function sets an association in the multi handle between the + * given socket and a private pointer of the application. This is + * (only) useful for curl_multi_socket uses. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t sockfd, void *sockp); + + +/* + * Name: curl_push_callback + * + * Desc: This callback gets called when a new stream is being pushed by the + * server. It approves or denies the new stream. + * + * Returns: CURL_PUSH_OK or CURL_PUSH_DENY. + */ +#define CURL_PUSH_OK 0 +#define CURL_PUSH_DENY 1 + +struct curl_pushheaders; /* forward declaration only */ + +CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, + size_t num); +CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, + const char *name); + +typedef int (*curl_push_callback)(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *userp); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --cc Utilities/cmcurl/lib/curl_config.h.cmake index 06201ec,0000000..20f212b mode 100644,000000..100644 --- a/Utilities/cmcurl/lib/curl_config.h.cmake +++ b/Utilities/cmcurl/lib/curl_config.h.cmake @@@ -1,961 -1,0 +1,988 @@@ +/* lib/curl_config.h.in. Generated somehow by cmake. */ + +/* when building libcurl itself */ +#cmakedefine BUILDING_LIBCURL 1 + +/* to disable cookies support */ +#cmakedefine CURL_DISABLE_COOKIES 1 + +/* to disable cryptographic authentication */ +#cmakedefine CURL_DISABLE_CRYPTO_AUTH 1 + +/* to disable DICT */ +#cmakedefine CURL_DISABLE_DICT 1 + +/* to disable FILE */ +#cmakedefine CURL_DISABLE_FILE 1 + +/* to disable FTP */ +#cmakedefine CURL_DISABLE_FTP 1 + ++/* to disable GOPHER */ ++#cmakedefine CURL_DISABLE_GOPHER 1 ++ ++/* to disable IMAP */ ++#cmakedefine CURL_DISABLE_IMAP 1 ++ +/* to disable HTTP */ +#cmakedefine CURL_DISABLE_HTTP 1 + +/* to disable LDAP */ +#cmakedefine CURL_DISABLE_LDAP 1 + +/* to disable LDAPS */ +#cmakedefine CURL_DISABLE_LDAPS 1 + ++/* to disable POP3 */ ++#cmakedefine CURL_DISABLE_POP3 1 ++ +/* to disable proxies */ +#cmakedefine CURL_DISABLE_PROXY 1 + ++/* to disable RTSP */ ++#cmakedefine CURL_DISABLE_RTSP 1 ++ ++/* to disable RTMP */ ++#cmakedefine CURL_DISABLE_RTMP 1 ++ ++/* to disable SMB */ ++#cmakedefine CURL_DISABLE_SMB 1 ++ ++/* to disable SMTP */ ++#cmakedefine CURL_DISABLE_SMTP 1 ++ +/* to disable TELNET */ +#cmakedefine CURL_DISABLE_TELNET 1 + +/* to disable TFTP */ +#cmakedefine CURL_DISABLE_TFTP 1 + +/* to disable verbose strings */ +#cmakedefine CURL_DISABLE_VERBOSE_STRINGS 1 + +/* to make a symbol visible */ +#cmakedefine CURL_EXTERN_SYMBOL 1 +/* Ensure using CURL_EXTERN_SYMBOL is possible */ +#ifndef CURL_EXTERN_SYMBOL +#define CURL_EXTERN_SYMBOL +#endif + +/* Use Windows LDAP implementation */ +#cmakedefine USE_WIN32_LDAP 1 + +/* when not building a shared library */ +#cmakedefine CURL_STATICLIB 1 + +/* Set to explicitly specify we don't want to use thread-safe functions */ +#cmakedefine DISABLED_THREADSAFE 1 + +/* your Entropy Gathering Daemon socket pathname */ +#cmakedefine EGD_SOCKET ${EGD_SOCKET} + +/* Define if you want to enable IPv6 support */ +#cmakedefine ENABLE_IPV6 1 + +/* Define to the type qualifier of arg 1 for getnameinfo. */ +#cmakedefine GETNAMEINFO_QUAL_ARG1 ${GETNAMEINFO_QUAL_ARG1} + +/* Define to the type of arg 1 for getnameinfo. */ +#cmakedefine GETNAMEINFO_TYPE_ARG1 ${GETNAMEINFO_TYPE_ARG1} + +/* Define to the type of arg 2 for getnameinfo. */ +#cmakedefine GETNAMEINFO_TYPE_ARG2 ${GETNAMEINFO_TYPE_ARG2} + +/* Define to the type of args 4 and 6 for getnameinfo. */ +#cmakedefine GETNAMEINFO_TYPE_ARG46 ${GETNAMEINFO_TYPE_ARG46} + +/* Define to the type of arg 7 for getnameinfo. */ +#cmakedefine GETNAMEINFO_TYPE_ARG7 ${GETNAMEINFO_TYPE_ARG7} + +/* Specifies the number of arguments to getservbyport_r */ +#cmakedefine GETSERVBYPORT_R_ARGS ${GETSERVBYPORT_R_ARGS} + +/* Specifies the size of the buffer to pass to getservbyport_r */ +#cmakedefine GETSERVBYPORT_R_BUFSIZE ${GETSERVBYPORT_R_BUFSIZE} + +/* Define to 1 if you have the alarm function. */ +#cmakedefine HAVE_ALARM 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ALLOCA_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ARPA_TFTP_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ASSERT_H 1 + +/* Define to 1 if you have the `basename' function. */ +#cmakedefine HAVE_BASENAME 1 + +/* Define to 1 if bool is an available type. */ +#cmakedefine HAVE_BOOL_T 1 + +/* Define to 1 if you have the clock_gettime function and monotonic timer. */ +#cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC 1 + +/* Define to 1 if you have the `closesocket' function. */ +#cmakedefine HAVE_CLOSESOCKET 1 + +/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */ +#cmakedefine HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_CRYPTO_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_DES_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_DLFCN_H 1 + +/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */ +#cmakedefine HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ERRNO_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ERR_H 1 + +/* Define to 1 if you have the fcntl function. */ +#cmakedefine HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_FCNTL_H 1 + +/* Define to 1 if you have a working fcntl O_NONBLOCK function. */ +#cmakedefine HAVE_FCNTL_O_NONBLOCK 1 + +/* Define to 1 if you have the fdopen function. */ +#cmakedefine HAVE_FDOPEN 1 + +/* Define to 1 if you have the `fork' function. */ +#cmakedefine HAVE_FORK 1 + +/* Define to 1 if you have the freeaddrinfo function. */ +#cmakedefine HAVE_FREEADDRINFO 1 + +/* Define to 1 if you have the freeifaddrs function. */ +#cmakedefine HAVE_FREEIFADDRS 1 + +/* Define to 1 if you have the ftruncate function. */ +#cmakedefine HAVE_FTRUNCATE 1 + +/* Define to 1 if you have a working getaddrinfo function. */ +#cmakedefine HAVE_GETADDRINFO 1 + +/* Define to 1 if you have the `geteuid' function. */ +#cmakedefine HAVE_GETEUID 1 + +/* Define to 1 if you have the gethostbyaddr function. */ +#cmakedefine HAVE_GETHOSTBYADDR 1 + +/* Define to 1 if you have the gethostbyaddr_r function. */ +#cmakedefine HAVE_GETHOSTBYADDR_R 1 + +/* gethostbyaddr_r() takes 5 args */ +#cmakedefine HAVE_GETHOSTBYADDR_R_5 1 + +/* gethostbyaddr_r() takes 7 args */ +#cmakedefine HAVE_GETHOSTBYADDR_R_7 1 + +/* gethostbyaddr_r() takes 8 args */ +#cmakedefine HAVE_GETHOSTBYADDR_R_8 1 + +/* Define to 1 if you have the gethostbyname function. */ +#cmakedefine HAVE_GETHOSTBYNAME 1 + +/* Define to 1 if you have the gethostbyname_r function. */ +#cmakedefine HAVE_GETHOSTBYNAME_R 1 + +/* gethostbyname_r() takes 3 args */ +#cmakedefine HAVE_GETHOSTBYNAME_R_3 1 + +/* gethostbyname_r() takes 5 args */ +#cmakedefine HAVE_GETHOSTBYNAME_R_5 1 + +/* gethostbyname_r() takes 6 args */ +#cmakedefine HAVE_GETHOSTBYNAME_R_6 1 + +/* Define to 1 if you have the gethostname function. */ +#cmakedefine HAVE_GETHOSTNAME 1 + +/* Define to 1 if you have a working getifaddrs function. */ +#cmakedefine HAVE_GETIFADDRS 1 + +/* Define to 1 if you have the getnameinfo function. */ +#cmakedefine HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the `getpass_r' function. */ +#cmakedefine HAVE_GETPASS_R 1 + +/* Define to 1 if you have the `getppid' function. */ +#cmakedefine HAVE_GETPPID 1 + +/* Define to 1 if you have the `getprotobyname' function. */ +#cmakedefine HAVE_GETPROTOBYNAME 1 + +/* Define to 1 if you have the `getpwuid' function. */ +#cmakedefine HAVE_GETPWUID 1 + +/* Define to 1 if you have the `getrlimit' function. */ +#cmakedefine HAVE_GETRLIMIT 1 + +/* Define to 1 if you have the getservbyport_r function. */ +#cmakedefine HAVE_GETSERVBYPORT_R 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#cmakedefine HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have a working glibc-style strerror_r function. */ +#cmakedefine HAVE_GLIBC_STRERROR_R 1 + +/* Define to 1 if you have a working gmtime_r function. */ +#cmakedefine HAVE_GMTIME_R 1 + +/* if you have the gssapi libraries */ +#cmakedefine HAVE_GSSAPI 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_GSSAPI_GSSAPI_GENERIC_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_GSSAPI_GSSAPI_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_GSSAPI_GSSAPI_KRB5_H 1 + +/* if you have the GNU gssapi libraries */ +#cmakedefine HAVE_GSSGNU 1 + +/* if you have the Heimdal gssapi libraries */ +#cmakedefine HAVE_GSSHEIMDAL 1 + +/* if you have the MIT gssapi libraries */ +#cmakedefine HAVE_GSSMIT 1 + +/* Define to 1 if you have the `idna_strerror' function. */ +#cmakedefine HAVE_IDNA_STRERROR 1 + +/* Define to 1 if you have the `idn_free' function. */ +#cmakedefine HAVE_IDN_FREE 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_IDN_FREE_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_IFADDRS_H 1 + +/* Define to 1 if you have the `inet_addr' function. */ +#cmakedefine HAVE_INET_ADDR 1 + +/* Define to 1 if you have the inet_ntoa_r function. */ +#cmakedefine HAVE_INET_NTOA_R 1 + +/* inet_ntoa_r() takes 2 args */ +#cmakedefine HAVE_INET_NTOA_R_2 1 + +/* inet_ntoa_r() takes 3 args */ +#cmakedefine HAVE_INET_NTOA_R_3 1 + +/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ +#cmakedefine HAVE_INET_NTOP 1 + +/* Define to 1 if you have a IPv6 capable working inet_pton function. */ +#cmakedefine HAVE_INET_PTON 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the ioctl function. */ +#cmakedefine HAVE_IOCTL 1 + +/* Define to 1 if you have the ioctlsocket function. */ +#cmakedefine HAVE_IOCTLSOCKET 1 + +/* Define to 1 if you have the IoctlSocket camel case function. */ +#cmakedefine HAVE_IOCTLSOCKET_CAMEL 1 + +/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. + */ +#cmakedefine HAVE_IOCTLSOCKET_CAMEL_FIONBIO 1 + +/* Define to 1 if you have a working ioctlsocket FIONBIO function. */ +#cmakedefine HAVE_IOCTLSOCKET_FIONBIO 1 + +/* Define to 1 if you have a working ioctl FIONBIO function. */ +#cmakedefine HAVE_IOCTL_FIONBIO 1 + +/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */ +#cmakedefine HAVE_IOCTL_SIOCGIFADDR 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_IO_H 1 + +/* if you have the Kerberos4 libraries (including -ldes) */ +#cmakedefine HAVE_KRB4 1 + +/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */ +#cmakedefine HAVE_KRB_GET_OUR_IP_FOR_REALM 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_KRB_H 1 + +/* Define to 1 if you have the lber.h header file. */ +#cmakedefine HAVE_LBER_H 1 + +/* Define to 1 if you have the ldapssl.h header file. */ +#cmakedefine HAVE_LDAPSSL_H 1 + +/* Define to 1 if you have the ldap.h header file. */ +#cmakedefine HAVE_LDAP_H 1 + +/* Use LDAPS implementation */ +#cmakedefine HAVE_LDAP_SSL 1 + +/* Define to 1 if you have the ldap_ssl.h header file. */ +#cmakedefine HAVE_LDAP_SSL_H 1 + +/* Define to 1 if you have the `ldap_url_parse' function. */ +#cmakedefine HAVE_LDAP_URL_PARSE 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LIBGEN_H 1 + +/* Define to 1 if you have the `idn' library (-lidn). */ +#cmakedefine HAVE_LIBIDN 1 + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#cmakedefine HAVE_LIBRESOLV 1 + +/* Define to 1 if you have the `resolve' library (-lresolve). */ +#cmakedefine HAVE_LIBRESOLVE 1 + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#cmakedefine HAVE_LIBSOCKET 1 + +/* Define to 1 if you have the `ssh2' library (-lssh2). */ +#cmakedefine HAVE_LIBSSH2 1 + +/* Define to 1 if libssh2 provides `libssh2_version'. */ +#cmakedefine HAVE_LIBSSH2_VERSION 1 + +/* Define to 1 if libssh2 provides `libssh2_init'. */ +#cmakedefine HAVE_LIBSSH2_INIT 1 + +/* Define to 1 if libssh2 provides `libssh2_exit'. */ +#cmakedefine HAVE_LIBSSH2_EXIT 1 + +/* Define to 1 if libssh2 provides `libssh2_scp_send64'. */ +#cmakedefine HAVE_LIBSSH2_SCP_SEND64 1 + +/* Define to 1 if libssh2 provides `libssh2_session_handshake'. */ +#cmakedefine HAVE_LIBSSH2_SESSION_HANDSHAKE 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LIBSSH2_H 1 + +/* Define to 1 if you have the `ssl' library (-lssl). */ +#cmakedefine HAVE_LIBSSL 1 + +/* if zlib is available */ +#cmakedefine HAVE_LIBZ 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LIMITS_H 1 + +/* if your compiler supports LL */ +#cmakedefine HAVE_LL 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LOCALE_H 1 + +/* Define to 1 if you have a working localtime_r function. */ +#cmakedefine HAVE_LOCALTIME_R 1 + +/* Define to 1 if the compiler supports the 'long long' data type. */ +#cmakedefine HAVE_LONGLONG 1 + +/* Define to 1 if you have the malloc.h header file. */ +#cmakedefine HAVE_MALLOC_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MEMORY_H 1 + +/* Define to 1 if you have the MSG_NOSIGNAL flag. */ +#cmakedefine HAVE_MSG_NOSIGNAL 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NET_IF_H 1 + +/* Define to 1 if NI_WITHSCOPEID exists and works. */ +#cmakedefine HAVE_NI_WITHSCOPEID 1 + +/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE */ +#cmakedefine HAVE_OLD_GSSMIT 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_OPENSSL_CRYPTO_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_OPENSSL_ENGINE_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_OPENSSL_ERR_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_OPENSSL_PEM_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_OPENSSL_PKCS12_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_OPENSSL_RSA_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_OPENSSL_SSL_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_OPENSSL_X509_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_PEM_H 1 + +/* Define to 1 if you have the `perror' function. */ +#cmakedefine HAVE_PERROR 1 + +/* Define to 1 if you have the `pipe' function. */ +#cmakedefine HAVE_PIPE 1 + +/* Define to 1 if you have a working poll function. */ +#cmakedefine HAVE_POLL 1 + +/* If you have a fine poll */ +#cmakedefine HAVE_POLL_FINE 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_POLL_H 1 + +/* Define to 1 if you have a working POSIX-style strerror_r function. */ +#cmakedefine HAVE_POSIX_STRERROR_R 1 + +/* Define to 1 if you have the header file */ +#cmakedefine HAVE_PTHREAD_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_PWD_H 1 + +/* Define to 1 if you have the `RAND_egd' function. */ +#cmakedefine HAVE_RAND_EGD 1 + +/* Define to 1 if you have the `RAND_screen' function. */ +#cmakedefine HAVE_RAND_SCREEN 1 + +/* Define to 1 if you have the `RAND_status' function. */ +#cmakedefine HAVE_RAND_STATUS 1 + +/* Define to 1 if you have the recv function. */ +#cmakedefine HAVE_RECV 1 + +/* Define to 1 if you have the recvfrom function. */ +#cmakedefine HAVE_RECVFROM 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_RSA_H 1 + +/* Define to 1 if you have the select function. */ +#cmakedefine HAVE_SELECT 1 + +/* Define to 1 if you have the send function. */ +#cmakedefine HAVE_SEND 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SETJMP_H 1 + +/* Define to 1 if you have the `setlocale' function. */ +#cmakedefine HAVE_SETLOCALE 1 + +/* Define to 1 if you have the `setmode' function. */ +#cmakedefine HAVE_SETMODE 1 + +/* Define to 1 if you have the `setrlimit' function. */ +#cmakedefine HAVE_SETRLIMIT 1 + +/* Define to 1 if you have the setsockopt function. */ +#cmakedefine HAVE_SETSOCKOPT 1 + +/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ +#cmakedefine HAVE_SETSOCKOPT_SO_NONBLOCK 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SGTTY_H 1 + +/* Define to 1 if you have the sigaction function. */ +#cmakedefine HAVE_SIGACTION 1 + +/* Define to 1 if you have the siginterrupt function. */ +#cmakedefine HAVE_SIGINTERRUPT 1 + +/* Define to 1 if you have the signal function. */ +#cmakedefine HAVE_SIGNAL 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the sigsetjmp function or macro. */ +#cmakedefine HAVE_SIGSETJMP 1 + +/* Define to 1 if sig_atomic_t is an available typedef. */ +#cmakedefine HAVE_SIG_ATOMIC_T 1 + +/* Define to 1 if sig_atomic_t is already defined as volatile. */ +#cmakedefine HAVE_SIG_ATOMIC_T_VOLATILE 1 + +/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */ +#cmakedefine HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* Define to 1 if you have the `socket' function. */ +#cmakedefine HAVE_SOCKET 1 + +/* Define to 1 if you have the `SSL_get_shutdown' function. */ +#cmakedefine HAVE_SSL_GET_SHUTDOWN 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SSL_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDLIB_H 1 + +/* Define to 1 if you have the strcasecmp function. */ +#cmakedefine HAVE_STRCASECMP 1 + +/* Define to 1 if you have the strcasestr function. */ +#cmakedefine HAVE_STRCASESTR 1 + +/* Define to 1 if you have the strcmpi function. */ +#cmakedefine HAVE_STRCMPI 1 + +/* Define to 1 if you have the strdup function. */ +#cmakedefine HAVE_STRDUP 1 + +/* Define to 1 if you have the strerror_r function. */ +#cmakedefine HAVE_STRERROR_R 1 + +/* Define to 1 if you have the stricmp function. */ +#cmakedefine HAVE_STRICMP 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRING_H 1 + +/* Define to 1 if you have the strlcat function. */ +#cmakedefine HAVE_STRLCAT 1 + +/* Define to 1 if you have the `strlcpy' function. */ +#cmakedefine HAVE_STRLCPY 1 + +/* Define to 1 if you have the strncasecmp function. */ +#cmakedefine HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the strncmpi function. */ +#cmakedefine HAVE_STRNCMPI 1 + +/* Define to 1 if you have the strnicmp function. */ +#cmakedefine HAVE_STRNICMP 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STROPTS_H 1 + +/* Define to 1 if you have the strstr function. */ +#cmakedefine HAVE_STRSTR 1 + +/* Define to 1 if you have the strtok_r function. */ +#cmakedefine HAVE_STRTOK_R 1 + +/* Define to 1 if you have the strtoll function. */ +#cmakedefine HAVE_STRTOLL 1 + +/* if struct sockaddr_storage is defined */ +#cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if you have the timeval struct. */ +#cmakedefine HAVE_STRUCT_TIMEVAL 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_FILIO_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_POLL_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SOCKIO_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_UIO_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_UN_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_UTIME_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_TERMIOS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_TERMIO_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_TLD_H 1 + +/* Define to 1 if you have the `tld_strerror' function. */ +#cmakedefine HAVE_TLD_STRERROR 1 + +/* Define to 1 if you have the `uname' function. */ +#cmakedefine HAVE_UNAME 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `utime' function. */ +#cmakedefine HAVE_UTIME 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UTIME_H 1 + +/* Define to 1 if compiler supports C99 variadic macro style. */ +#cmakedefine HAVE_VARIADIC_MACROS_C99 1 + +/* Define to 1 if compiler supports old gcc variadic macro style. */ +#cmakedefine HAVE_VARIADIC_MACROS_GCC 1 + +/* Define to 1 if you have the winber.h header file. */ +#cmakedefine HAVE_WINBER_H 1 + +/* Define to 1 if you have the windows.h header file. */ +#cmakedefine HAVE_WINDOWS_H 1 + +/* Define to 1 if you have the winldap.h header file. */ +#cmakedefine HAVE_WINLDAP_H 1 + +/* Define to 1 if you have the winsock2.h header file. */ +#cmakedefine HAVE_WINSOCK2_H 1 + +/* Define to 1 if you have the winsock.h header file. */ +#cmakedefine HAVE_WINSOCK_H 1 + +/* Define this symbol if your OS supports changing the contents of argv */ +#cmakedefine HAVE_WRITABLE_ARGV 1 + +/* Define to 1 if you have the writev function. */ +#cmakedefine HAVE_WRITEV 1 + +/* Define to 1 if you have the ws2tcpip.h header file. */ +#cmakedefine HAVE_WS2TCPIP_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_X509_H 1 + +/* Define if you have the header file. */ +#cmakedefine HAVE_PROCESS_H 1 + +/* if you have the zlib.h header file */ +#cmakedefine HAVE_ZLIB_H 1 + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#cmakedefine LT_OBJDIR ${LT_OBJDIR} + +/* If you lack a fine basename() prototype */ +#cmakedefine NEED_BASENAME_PROTO 1 + +/* Define to 1 if you need the lber.h header file even with ldap.h */ +#cmakedefine NEED_LBER_H 1 + +/* Define to 1 if you need the malloc.h header file even with stdlib.h */ +#cmakedefine NEED_MALLOC_H 1 + +/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ +#cmakedefine NEED_REENTRANT 1 + +/* cpu-machine-OS */ +#cmakedefine OS ${OS} + +/* Name of package */ +#cmakedefine PACKAGE ${PACKAGE} + +/* Define to the address where bug reports for this package should be sent. */ +#cmakedefine PACKAGE_BUGREPORT ${PACKAGE_BUGREPORT} + +/* Define to the full name of this package. */ +#cmakedefine PACKAGE_NAME ${PACKAGE_NAME} + +/* Define to the full name and version of this package. */ +#cmakedefine PACKAGE_STRING ${PACKAGE_STRING} + +/* Define to the one symbol short name of this package. */ +#cmakedefine PACKAGE_TARNAME ${PACKAGE_TARNAME} + +/* Define to the version of this package. */ +#cmakedefine PACKAGE_VERSION ${PACKAGE_VERSION} + +/* a suitable file to read random data from */ +#cmakedefine RANDOM_FILE "${RANDOM_FILE}" + +/* Define to the type of arg 1 for recvfrom. */ +#cmakedefine RECVFROM_TYPE_ARG1 ${RECVFROM_TYPE_ARG1} + +/* Define to the type pointed by arg 2 for recvfrom. */ +#cmakedefine RECVFROM_TYPE_ARG2 ${RECVFROM_TYPE_ARG2} + +/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */ +#cmakedefine RECVFROM_TYPE_ARG2_IS_VOID 1 + +/* Define to the type of arg 3 for recvfrom. */ +#cmakedefine RECVFROM_TYPE_ARG3 ${RECVFROM_TYPE_ARG3} + +/* Define to the type of arg 4 for recvfrom. */ +#cmakedefine RECVFROM_TYPE_ARG4 ${RECVFROM_TYPE_ARG4} + +/* Define to the type pointed by arg 5 for recvfrom. */ +#cmakedefine RECVFROM_TYPE_ARG5 ${RECVFROM_TYPE_ARG5} + +/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */ +#cmakedefine RECVFROM_TYPE_ARG5_IS_VOID 1 + +/* Define to the type pointed by arg 6 for recvfrom. */ +#cmakedefine RECVFROM_TYPE_ARG6 ${RECVFROM_TYPE_ARG6} + +/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */ +#cmakedefine RECVFROM_TYPE_ARG6_IS_VOID 1 + +/* Define to the function return type for recvfrom. */ +#cmakedefine RECVFROM_TYPE_RETV ${RECVFROM_TYPE_RETV} + +/* Define to the type of arg 1 for recv. */ +#cmakedefine RECV_TYPE_ARG1 ${RECV_TYPE_ARG1} + +/* Define to the type of arg 2 for recv. */ +#cmakedefine RECV_TYPE_ARG2 ${RECV_TYPE_ARG2} + +/* Define to the type of arg 3 for recv. */ +#cmakedefine RECV_TYPE_ARG3 ${RECV_TYPE_ARG3} + +/* Define to the type of arg 4 for recv. */ +#cmakedefine RECV_TYPE_ARG4 ${RECV_TYPE_ARG4} + +/* Define to the function return type for recv. */ +#cmakedefine RECV_TYPE_RETV ${RECV_TYPE_RETV} + +/* Define as the return type of signal handlers (`int' or `void'). */ +#cmakedefine RETSIGTYPE ${RETSIGTYPE} + +/* Define to the type qualifier of arg 5 for select. */ +#cmakedefine SELECT_QUAL_ARG5 ${SELECT_QUAL_ARG5} + +/* Define to the type of arg 1 for select. */ +#cmakedefine SELECT_TYPE_ARG1 ${SELECT_TYPE_ARG1} + +/* Define to the type of args 2, 3 and 4 for select. */ +#cmakedefine SELECT_TYPE_ARG234 ${SELECT_TYPE_ARG234} + +/* Define to the type of arg 5 for select. */ +#cmakedefine SELECT_TYPE_ARG5 ${SELECT_TYPE_ARG5} + +/* Define to the function return type for select. */ +#cmakedefine SELECT_TYPE_RETV ${SELECT_TYPE_RETV} + +/* Define to the type qualifier of arg 2 for send. */ +#cmakedefine SEND_QUAL_ARG2 ${SEND_QUAL_ARG2} + +/* Define to the type of arg 1 for send. */ +#cmakedefine SEND_TYPE_ARG1 ${SEND_TYPE_ARG1} + +/* Define to the type of arg 2 for send. */ +#cmakedefine SEND_TYPE_ARG2 ${SEND_TYPE_ARG2} + +/* Define to the type of arg 3 for send. */ +#cmakedefine SEND_TYPE_ARG3 ${SEND_TYPE_ARG3} + +/* Define to the type of arg 4 for send. */ +#cmakedefine SEND_TYPE_ARG4 ${SEND_TYPE_ARG4} + +/* Define to the function return type for send. */ +#cmakedefine SEND_TYPE_RETV ${SEND_TYPE_RETV} + +/* The size of `int', as computed by sizeof. */ + at SIZEOF_INT_CODE@ + +/* The size of `short', as computed by sizeof. */ + at SIZEOF_SHORT_CODE@ + +/* The size of `long', as computed by sizeof. */ + at SIZEOF_LONG_CODE@ + +/* The size of `off_t', as computed by sizeof. */ + at SIZEOF_OFF_T_CODE@ + +/* The size of `size_t', as computed by sizeof. */ + at SIZEOF_SIZE_T_CODE@ + +/* The size of `ssize_t', as computed by sizeof. */ + at SIZEOF_SSIZE_T_CODE@ + +/* The size of `time_t', as computed by sizeof. */ + at SIZEOF_TIME_T_CODE@ + +/* Define to 1 if you have the ANSI C header files. */ +#cmakedefine STDC_HEADERS 1 + +/* Define to the type of arg 3 for strerror_r. */ +#cmakedefine STRERROR_R_TYPE_ARG3 ${STRERROR_R_TYPE_ARG3} + +/* Define to 1 if you can safely include both and . */ +#cmakedefine TIME_WITH_SYS_TIME 1 + +/* Define if you want to enable c-ares support */ +#cmakedefine USE_ARES 1 + +/* Define if you want to enable POSIX threaded DNS lookup */ +#cmakedefine USE_THREADS_POSIX 1 + +/* Define to disable non-blocking sockets. */ +#cmakedefine USE_BLOCKING_SOCKETS 1 + +/* if GnuTLS is enabled */ +#cmakedefine USE_GNUTLS 1 + +/* if PolarSSL is enabled */ +#cmakedefine USE_POLARSSL 1 + ++/* if mbedTLS is enabled */ ++#cmakedefine USE_MBEDTLS 1 ++ +/* if libSSH2 is in use */ +#cmakedefine USE_LIBSSH2 1 + +/* If you want to build curl with the built-in manual */ +#cmakedefine USE_MANUAL 1 + +/* if NSS is enabled */ +#cmakedefine USE_NSS 1 + +/* if you want to use OpenLDAP code instead of legacy ldap implementation */ +#cmakedefine USE_OPENLDAP 1 + +/* if OpenSSL is in use */ +#cmakedefine USE_OPENSSL 1 + +/* if Unix domain sockets are enabled */ +#cmakedefine USE_UNIX_SOCKETS + +/* to enable SSPI support */ +#cmakedefine USE_WINDOWS_SSPI 1 + ++/* to enable Windows SSL */ ++#cmakedefine USE_SCHANNEL 1 ++ +/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */ +#cmakedefine USE_YASSLEMUL 1 + +/* Version number of package */ +#cmakedefine VERSION ${VERSION} + +/* Define to avoid automatic inclusion of winsock.h */ +#cmakedefine WIN32_LEAN_AND_MEAN 1 + +/* Define to 1 if OS is AIX. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS} + +/* Define for large files, on AIX-style hosts. */ +#cmakedefine _LARGE_FILES ${_LARGE_FILES} + +/* define this if you need it to compile thread-safe code */ +#cmakedefine _THREAD_SAFE ${_THREAD_SAFE} + +/* Define to empty if `const' does not conform to ANSI C. */ +#cmakedefine const ${const} + +/* Type to use in place of in_addr_t when system does not provide it. */ +#cmakedefine in_addr_t ${in_addr_t} + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to `unsigned int' if does not define. */ +#cmakedefine size_t ${size_t} + +/* the signed version of size_t */ +#ifndef SIZEOF_SSIZE_T +# if SIZEOF_LONG == SIZEOF_SIZE_T + typedef long ssize_t; +# elif SIZEOF_LONG_LONG == SIZEOF_SIZE_T + typedef long long ssize_t; +# elif SIZEOF___INT64 == SIZEOF_SIZE_T + typedef __int64 ssize_t; +# else + typedef int ssize_t; +# endif +#endif diff --cc Utilities/cmcurl/lib/curl_setup.h index 19c1baf,0000000..2122220 mode 100644,000000..100644 --- a/Utilities/cmcurl/lib/curl_setup.h +++ b/Utilities/cmcurl/lib/curl_setup.h @@@ -1,745 -1,0 +1,764 @@@ +#ifndef HEADER_CURL_SETUP_H +#define HEADER_CURL_SETUP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. ++ * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. ++ * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) && \ + !defined(__SYMBIAN32__) +#define WIN32 +#endif + +/* + * Include configuration script results or hand-crafted + * configuration file for platforms which lack config tool. + */ + +#ifdef HAVE_CONFIG_H + +#include "curl_config.h" + +#else /* HAVE_CONFIG_H */ + +#ifdef _WIN32_WCE +# include "config-win32ce.h" +#else +# ifdef WIN32 +# include "config-win32.h" +# endif +#endif + +#if defined(macintosh) && defined(__MRC__) +# include "config-mac.h" +#endif + +#ifdef __riscos__ +# include "config-riscos.h" +#endif + +#ifdef __AMIGA__ +# include "config-amigaos.h" +#endif + +#ifdef __SYMBIAN32__ +# include "config-symbian.h" +#endif + +#ifdef __OS400__ +# include "config-os400.h" +#endif + +#ifdef TPF +# include "config-tpf.h" +#endif + +#ifdef __VXWORKS__ +# include "config-vxworks.h" +#endif + +#endif /* HAVE_CONFIG_H */ + +#if defined(_MSC_VER) +# pragma warning(push,1) +#endif + +/* ================================================================ */ +/* Definition of preprocessor macros/symbols which modify compiler */ +/* behavior or generated code characteristics must be done here, */ +/* as appropriate, before any system header file is included. It is */ +/* also possible to have them defined in the config file included */ +/* before this point. As a result of all this we frown inclusion of */ +/* system header files in our config files, avoid this at any cost. */ +/* ================================================================ */ + +/* + * AIX 4.3 and newer needs _THREAD_SAFE defined to build + * proper reentrant code. Others may also need it. + */ + +#ifdef NEED_THREAD_SAFE +# ifndef _THREAD_SAFE +# define _THREAD_SAFE +# endif +#endif + +/* + * Tru64 needs _REENTRANT set for a few function prototypes and + * things to appear in the system header files. Unixware needs it + * to build proper reentrant code. Others may also need it. + */ + +#ifdef NEED_REENTRANT +# ifndef _REENTRANT +# define _REENTRANT +# endif +#endif + +/* Solaris needs this to get a POSIX-conformant getpwuid_r */ +#if defined(sun) || defined(__sun) +# ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +# endif +#endif + +/* ================================================================ */ +/* If you need to include a system header file for your platform, */ +/* please, do it beyond the point further indicated in this file. */ +/* ================================================================ */ + +/* + * libcurl's external interface definitions are also used internally, + * and might also include required system header files to define them. + */ + +#include + +/* + * Compile time sanity checks must also be done when building the library. + */ + +#include + +/* + * Ensure that no one is using the old SIZEOF_CURL_OFF_T macro + */ + +#ifdef SIZEOF_CURL_OFF_T +# error "SIZEOF_CURL_OFF_T shall not be defined!" + Error Compilation_aborted_SIZEOF_CURL_OFF_T_shall_not_be_defined +#endif + +/* + * Disable other protocols when http is the only one desired. + */ + +#ifdef HTTP_ONLY +# ifndef CURL_DISABLE_TFTP +# define CURL_DISABLE_TFTP +# endif +# ifndef CURL_DISABLE_FTP +# define CURL_DISABLE_FTP +# endif +# ifndef CURL_DISABLE_LDAP +# define CURL_DISABLE_LDAP +# endif +# ifndef CURL_DISABLE_TELNET +# define CURL_DISABLE_TELNET +# endif +# ifndef CURL_DISABLE_DICT +# define CURL_DISABLE_DICT +# endif +# ifndef CURL_DISABLE_FILE +# define CURL_DISABLE_FILE +# endif +# ifndef CURL_DISABLE_RTSP +# define CURL_DISABLE_RTSP +# endif +# ifndef CURL_DISABLE_POP3 +# define CURL_DISABLE_POP3 +# endif +# ifndef CURL_DISABLE_IMAP +# define CURL_DISABLE_IMAP +# endif +# ifndef CURL_DISABLE_SMTP +# define CURL_DISABLE_SMTP +# endif - # ifndef CURL_DISABLE_RTSP - # define CURL_DISABLE_RTSP - # endif +# ifndef CURL_DISABLE_RTMP +# define CURL_DISABLE_RTMP +# endif +# ifndef CURL_DISABLE_GOPHER +# define CURL_DISABLE_GOPHER +# endif +# ifndef CURL_DISABLE_SMB +# define CURL_DISABLE_SMB +# endif +#endif + +/* + * When http is disabled rtsp is not supported. + */ + +#if defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_RTSP) +# define CURL_DISABLE_RTSP +#endif + +/* ================================================================ */ +/* No system header file shall be included in this file before this */ +/* point. The only allowed ones are those included from curlbuild.h */ +/* ================================================================ */ + +/* + * OS/400 setup file includes some system headers. + */ + +#ifdef __OS400__ +# include "setup-os400.h" +#endif + +/* + * VMS setup file includes some system headers. + */ + +#ifdef __VMS +# include "setup-vms.h" +#endif + +/* ++ * Use getaddrinfo to resolve the IPv4 address literal. If the current network ++ * interface doesn???t support IPv4, but supports IPv6, NAT64, and DNS64, ++ * performing this task will result in a synthesized IPv6 address. ++ */ ++#ifdef __APPLE__ ++#define USE_RESOLVE_ON_IPS 1 ++#endif ++ ++/* + * Include header files for windows builds before redefining anything. + * Use this preprocessor block only to include or exclude windows.h, + * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs + * to any other further and independent block. Under Cygwin things work + * just as under linux (e.g. ) and the winsock headers should + * never be included when __CYGWIN__ is defined. configure script takes + * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, + * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. + */ + +#ifdef HAVE_WINDOWS_H +# if defined(UNICODE) && !defined(_UNICODE) +# define _UNICODE +# endif +# if defined(_UNICODE) && !defined(UNICODE) +# define UNICODE +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# ifdef HAVE_WINSOCK2_H +# include +# ifdef HAVE_WS2TCPIP_H - # include ++# include +# endif +# else +# ifdef HAVE_WINSOCK_H +# include +# endif +# endif +# include +# ifdef UNICODE + typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str); +# endif +#endif + +/* + * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else + * define USE_WINSOCK to 1 if we have and use WINSOCK API, else + * undefine USE_WINSOCK. + */ + +#undef USE_WINSOCK + +#ifdef HAVE_WINSOCK2_H +# define USE_WINSOCK 2 +#else +# ifdef HAVE_WINSOCK_H +# define USE_WINSOCK 1 +# endif +#endif + +#ifdef USE_LWIPSOCK +# include +# include +# include +#endif + +#ifdef HAVE_EXTRA_STRICMP_H +# include +#endif + +#ifdef HAVE_EXTRA_STRDUP_H +# include +#endif + +#ifdef TPF +# include /* for bzero, strcasecmp, and strncasecmp */ +# include /* for strcpy and strlen */ +# include /* for rand and srand */ +# include /* for select and ioctl*/ +# include /* for in_addr_t definition */ +# include /* for tpf_process_signals */ + /* change which select is used for libcurl */ +# define select(a,b,c,d,e) tpf_select_libcurl(a,b,c,d,e) +#endif + +#ifdef __VXWORKS__ +# include /* for generic BSD socket functions */ +# include /* for basic I/O interface functions */ +#endif + +#ifdef __AMIGA__ +# ifndef __ixemul__ +# include +# include +# include +# include +# define select(a,b,c,d,e) WaitSelect(a,b,c,d,e,0) +# endif +#endif + +#include +#ifdef HAVE_ASSERT_H +#include +#endif + +#ifdef __TANDEM /* for nsr-tandem-nsk systems */ +#include +#endif + +#ifndef STDC_HEADERS /* no standard C headers! */ +#include +#endif + +#ifdef __POCC__ +# include +# include +# define sys_nerr EILSEQ +#endif + +/* + * Salford-C kludge section (mostly borrowed from wxWidgets). + */ +#ifdef __SALFORDC__ + #pragma suppress 353 /* Possible nested comments */ + #pragma suppress 593 /* Define not used */ + #pragma suppress 61 /* enum has no name */ + #pragma suppress 106 /* unnamed, unused parameter */ + #include +#endif + +/* Default Windows file API selection. */ +#ifdef _WIN32 +# if defined(_MSC_VER) && (_INTEGRAL_MAX_BITS >= 64) +# define USE_WIN32_LARGE_FILES +# elif defined(__MINGW32__) +# define USE_WIN32_LARGE_FILES +# else +# define USE_WIN32_SMALL_FILES +# endif +#endif + +/* + * Large file (>2Gb) support using WIN32 functions. + */ + +#ifdef USE_WIN32_LARGE_FILES +# include +# include +# include +# undef lseek +# define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence) +# undef fstat +# define fstat(fdes,stp) _fstati64(fdes, stp) +# undef stat +# define stat(fname,stp) _stati64(fname, stp) +# define struct_stat struct _stati64 +# define LSEEK_ERROR (__int64)-1 +#endif + +/* + * Small file (<2Gb) support using WIN32 functions. + */ + +#ifdef USE_WIN32_SMALL_FILES +# include +# include +# include +# ifndef _WIN32_WCE +# undef lseek +# define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence) +# define fstat(fdes,stp) _fstat(fdes, stp) +# define stat(fname,stp) _stat(fname, stp) +# define struct_stat struct _stat +# endif +# define LSEEK_ERROR (long)-1 +#endif + +#ifndef struct_stat +# define struct_stat struct stat +#endif + +#ifndef LSEEK_ERROR +# define LSEEK_ERROR (off_t)-1 +#endif + +/* + * Default sizeof(off_t) in case it hasn't been defined in config file. + */ + +#ifndef SIZEOF_OFF_T +# if defined(__VMS) && !defined(__VAX) +# if defined(_LARGEFILE) +# define SIZEOF_OFF_T 8 +# endif +# elif defined(__OS400__) && defined(__ILEC400__) +# if defined(_LARGE_FILES) +# define SIZEOF_OFF_T 8 +# endif +# elif defined(__MVS__) && defined(__IBMC__) +# if defined(_LP64) || defined(_LARGE_FILES) +# define SIZEOF_OFF_T 8 +# endif +# elif defined(__370__) && defined(__IBMC__) +# if defined(_LP64) || defined(_LARGE_FILES) +# define SIZEOF_OFF_T 8 +# endif +# endif +# ifndef SIZEOF_OFF_T +# define SIZEOF_OFF_T 4 +# endif +#endif + +/* + * Arg 2 type for gethostname in case it hasn't been defined in config file. + */ + +#ifndef GETHOSTNAME_TYPE_ARG2 +# ifdef USE_WINSOCK +# define GETHOSTNAME_TYPE_ARG2 int +# else +# define GETHOSTNAME_TYPE_ARG2 size_t +# endif +#endif + +/* Below we define some functions. They should + + 4. set the SIGALRM signal timeout + 5. set dir/file naming defines + */ + +#ifdef WIN32 + +# define DIR_CHAR "\\" +# define DOT_CHAR "_" + +#else /* WIN32 */ + +# ifdef MSDOS /* Watt-32 */ + +# include +# define select(n,r,w,x,t) select_s(n,r,w,x,t) +# define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z)) +# include +# ifdef word +# undef word +# endif +# ifdef byte +# undef byte +# endif + +# endif /* MSDOS */ + +# ifdef __minix + /* Minix 3 versions up to at least 3.1.3 are missing these prototypes */ + extern char * strtok_r(char *s, const char *delim, char **last); + extern struct tm * gmtime_r(const time_t * const timep, struct tm *tmp); +# endif + +# define DIR_CHAR "/" +# ifndef DOT_CHAR +# define DOT_CHAR "." +# endif + +# ifdef MSDOS +# undef DOT_CHAR +# define DOT_CHAR "_" +# endif + +# ifndef fileno /* sunos 4 have this as a macro! */ - int fileno( FILE *stream); ++ int fileno(FILE *stream); +# endif + +#endif /* WIN32 */ + +/* + * msvc 6.0 requires PSDK in order to have INET6_ADDRSTRLEN + * defined in ws2tcpip.h as well as to provide IPv6 support. ++ * Does not apply if lwIP is used. + */ + - #if defined(_MSC_VER) && !defined(__POCC__) ++#if defined(_MSC_VER) && !defined(__POCC__) && !defined(USE_LWIPSOCK) +# if !defined(HAVE_WS2TCPIP_H) || \ + ((_MSC_VER < 1300) && !defined(INET6_ADDRSTRLEN)) +# undef HAVE_GETADDRINFO_THREADSAFE +# undef HAVE_FREEADDRINFO +# undef HAVE_GETADDRINFO +# undef HAVE_GETNAMEINFO +# undef ENABLE_IPV6 +# endif +#endif + +/* ---------------------------------------------------------------- */ +/* resolver specialty compile-time defines */ +/* CURLRES_* defines to use in the host*.c sources */ +/* ---------------------------------------------------------------- */ + +/* + * lcc-win32 doesn't have _beginthreadex(), lacks threads support. + */ + +#if defined(__LCC__) && defined(WIN32) +# undef USE_THREADS_POSIX +# undef USE_THREADS_WIN32 +#endif + +/* + * MSVC threads support requires a multi-threaded runtime library. + * _beginthreadex() is not available in single-threaded ones. + */ + +#if defined(_MSC_VER) && !defined(__POCC__) && !defined(_MT) +# undef USE_THREADS_POSIX +# undef USE_THREADS_WIN32 +#endif + +/* + * Mutually exclusive CURLRES_* definitions. + */ + +#ifdef USE_ARES +# define CURLRES_ASYNCH +# define CURLRES_ARES +/* now undef the stock libc functions just to avoid them being used */ +# undef HAVE_GETADDRINFO ++# undef HAVE_FREEADDRINFO +# undef HAVE_GETHOSTBYNAME +#elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) +# define CURLRES_ASYNCH +# define CURLRES_THREADED +#else +# define CURLRES_SYNCH +#endif + +#ifdef ENABLE_IPV6 +# define CURLRES_IPV6 +#else +# define CURLRES_IPV4 +#endif + +/* ---------------------------------------------------------------- */ + +/* + * When using WINSOCK, TELNET protocol requires WINSOCK2 API. + */ + +#if defined(USE_WINSOCK) && (USE_WINSOCK != 2) +# define CURL_DISABLE_TELNET 1 +#endif + +/* + * msvc 6.0 does not have struct sockaddr_storage and + * does not define IPPROTO_ESP in winsock2.h. But both + * are available if PSDK is properly installed. + */ + +#if defined(_MSC_VER) && !defined(__POCC__) +# if !defined(HAVE_WINSOCK2_H) || ((_MSC_VER < 1300) && !defined(IPPROTO_ESP)) +# undef HAVE_STRUCT_SOCKADDR_STORAGE +# endif +#endif + +/* + * Intentionally fail to build when using msvc 6.0 without PSDK installed. + * The brave of heart can circumvent this, defining ALLOW_MSVC6_WITHOUT_PSDK + * in lib/config-win32.h although absolutely discouraged and unsupported. + */ + +#if defined(_MSC_VER) && !defined(__POCC__) +# if !defined(HAVE_WINDOWS_H) || ((_MSC_VER < 1300) && !defined(_FILETIME_)) +# if !defined(ALLOW_MSVC6_WITHOUT_PSDK) +# error MSVC 6.0 requires "February 2003 Platform SDK" a.k.a. \ + "Windows Server 2003 PSDK" +# else +# define CURL_DISABLE_LDAP 1 +# endif +# endif +#endif + +#ifdef NETWARE +int netware_init(void); +#ifndef __NOVELL_LIBC__ +#include +#include +#endif +#endif + +#if defined(HAVE_LIBIDN) && defined(HAVE_TLD_H) +/* The lib was present and the tld.h header (which is missing in libidn 0.3.X + but we only work with libidn 0.4.1 or later) */ +#define USE_LIBIDN +#endif + +#ifndef SIZEOF_TIME_T +/* assume default size of time_t to be 32 bit */ +#define SIZEOF_TIME_T 4 +#endif + +#define LIBIDN_REQUIRED_VERSION "0.4.1" + +#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \ - defined(USE_POLARSSL) || defined(USE_AXTLS) || \ ++ defined(USE_POLARSSL) || defined(USE_AXTLS) || defined(USE_MBEDTLS) || \ + defined(USE_CYASSL) || defined(USE_SCHANNEL) || \ + defined(USE_DARWINSSL) || defined(USE_GSKIT) +#define USE_SSL /* SSL support has been enabled */ +#endif + +/* Single point where USE_SPNEGO definition might be defined */ +#if !defined(CURL_DISABLE_CRYPTO_AUTH) && \ + (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) +#define USE_SPNEGO +#endif + +/* Single point where USE_KERBEROS5 definition might be defined */ +#if !defined(CURL_DISABLE_CRYPTO_AUTH) && \ + (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) +#define USE_KERBEROS5 +#endif + +/* Single point where USE_NTLM definition might be defined */ +#if !defined(CURL_DISABLE_NTLM) && !defined(CURL_DISABLE_CRYPTO_AUTH) +#if defined(USE_OPENSSL) || defined(USE_WINDOWS_SSPI) || \ + defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) || \ + defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) + - #ifdef HAVE_BORINGSSL /* BoringSSL is not NTLM capable */ - #undef USE_NTLM - #else +#define USE_NTLM +#endif +#endif - #endif + +/* non-configure builds may define CURL_WANTS_CA_BUNDLE_ENV */ +#if defined(CURL_WANTS_CA_BUNDLE_ENV) && !defined(CURL_CA_BUNDLE) +#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE") +#endif + +/* + * Provide a mechanism to silence picky compilers, such as gcc 4.6+. + * Parameters should of course normally not be unused, but for example when + * we have multiple implementations of the same interface it may happen. + */ + +#if defined(__GNUC__) && ((__GNUC__ >= 3) || \ + ((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 7))) +# define UNUSED_PARAM __attribute__((__unused__)) +# define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +# define UNUSED_PARAM /*NOTHING*/ +# define WARN_UNUSED_RESULT +#endif + +/* + * Include macros and defines that should only be processed once. + */ + +#ifndef HEADER_CURL_SETUP_ONCE_H +#include "curl_setup_once.h" +#endif + +/* + * Definition of our NOP statement Object-like macro + */ + +#ifndef Curl_nop_stmt +# define Curl_nop_stmt do { } WHILE_FALSE +#endif + +/* + * Ensure that Winsock and lwIP TCP/IP stacks are not mixed. + */ + - #if defined(__LWIP_OPT_H__) ++#if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H) +# if defined(SOCKET) || \ + defined(USE_WINSOCK) || \ + defined(HAVE_WINSOCK_H) || \ + defined(HAVE_WINSOCK2_H) || \ + defined(HAVE_WS2TCPIP_H) +# error "Winsock and lwIP TCP/IP stack definitions shall not coexist!" +# endif +#endif + +/* + * Portable symbolic names for Winsock shutdown() mode flags. + */ + +#ifdef USE_WINSOCK +# define SHUT_RD 0x00 +# define SHUT_WR 0x01 +# define SHUT_RDWR 0x02 +#endif + +/* Define S_ISREG if not defined by system headers, f.e. MSVC */ +#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif + +/* Define S_ISDIR if not defined by system headers, f.e. MSVC */ +#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif + +/* In Windows the default file mode is text but an application can override it. - Therefore we specify it explicitly. https://github.com/bagder/curl/pull/258 ++Therefore we specify it explicitly. https://github.com/curl/curl/pull/258 +*/ +#if defined(WIN32) || defined(MSDOS) +#define FOPEN_READTEXT "rt" +#define FOPEN_WRITETEXT "wt" +#elif defined(__CYGWIN__) +/* Cygwin has specific behavior we need to address when WIN32 is not defined. +https://cygwin.com/cygwin-ug-net/using-textbinary.html +For write we want our output to have line endings of LF and be compatible with +other Cygwin utilities. For read we want to handle input that may have line +endings either CRLF or LF so 't' is appropriate. +*/ +#define FOPEN_READTEXT "rt" +#define FOPEN_WRITETEXT "w" +#else +#define FOPEN_READTEXT "r" +#define FOPEN_WRITETEXT "w" +#endif + ++/* WinSock destroys recv() buffer when send() failed. ++ * Enabled automatically for Windows and for Cygwin as Cygwin sockets are ++ * wrappers for WinSock sockets. https://github.com/curl/curl/issues/657 ++ * Define DONT_USE_RECV_BEFORE_SEND_WORKAROUND to force disable workaround. ++ */ ++#if !defined(DONT_USE_RECV_BEFORE_SEND_WORKAROUND) ++# if defined(WIN32) || defined(__CYGWIN__) ++# define USE_RECV_BEFORE_SEND_WORKAROUND ++# endif ++#else /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */ ++# ifdef USE_RECV_BEFORE_SEND_WORKAROUND ++# undef USE_RECV_BEFORE_SEND_WORKAROUND ++# endif ++#endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */ ++ +#endif /* HEADER_CURL_SETUP_H */ diff --cc Utilities/cmcurl/lib/ftp.c index 29c840c,0000000..b0165bc mode 100644,000000..100644 --- a/Utilities/cmcurl/lib/ftp.c +++ b/Utilities/cmcurl/lib/ftp.c @@@ -1,4599 -1,0 +1,4616 @@@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. ++ * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. ++ * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_FTP + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_UTSNAME_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef __VMS +#include +#include +#endif + +#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) +#undef in_addr_t +#define in_addr_t unsigned long +#endif + +#include +#include "urldata.h" +#include "sendf.h" +#include "if2ip.h" +#include "hostip.h" +#include "progress.h" +#include "transfer.h" +#include "escape.h" +#include "http.h" /* for HTTP proxy tunnel stuff */ +#include "socks.h" +#include "ftp.h" +#include "fileinfo.h" +#include "ftplistparser.h" +#include "curl_sec.h" +#include "strtoofft.h" +#include "strequal.h" +#include "vtls/vtls.h" +#include "connect.h" +#include "strerror.h" +#include "inet_ntop.h" +#include "inet_pton.h" +#include "select.h" +#include "parsedate.h" /* for the week day and month names */ +#include "sockaddr.h" /* required for Curl_sockaddr_storage */ +#include "multiif.h" +#include "url.h" +#include "rawstr.h" +#include "speedcheck.h" +#include "warnless.h" +#include "http_proxy.h" +#include "non-ascii.h" ++/* The last 3 #include files should be in this order */ +#include "curl_printf.h" - +#include "curl_memory.h" - /* The last #include file should be: */ +#include "memdebug.h" + +#ifndef NI_MAXHOST +#define NI_MAXHOST 1025 +#endif +#ifndef INET_ADDRSTRLEN +#define INET_ADDRSTRLEN 16 +#endif + +#ifdef CURL_DISABLE_VERBOSE_STRINGS +#define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt +#endif + +/* Local API functions */ +#ifndef DEBUGBUILD +static void _state(struct connectdata *conn, + ftpstate newstate); +#define state(x,y) _state(x,y) +#else +static void _state(struct connectdata *conn, + ftpstate newstate, + int lineno); +#define state(x,y) _state(x,y,__LINE__) +#endif + +static CURLcode ftp_sendquote(struct connectdata *conn, + struct curl_slist *quote); +static CURLcode ftp_quit(struct connectdata *conn); +static CURLcode ftp_parse_url_path(struct connectdata *conn); +static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done); +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static void ftp_pasv_verbose(struct connectdata *conn, + Curl_addrinfo *ai, + char *newhost, /* ascii version */ + int port); +#endif +static CURLcode ftp_state_prepare_transfer(struct connectdata *conn); +static CURLcode ftp_state_mdtm(struct connectdata *conn); +static CURLcode ftp_state_quote(struct connectdata *conn, + bool init, ftpstate instate); +static CURLcode ftp_nb_type(struct connectdata *conn, + bool ascii, ftpstate newstate); +static int ftp_need_type(struct connectdata *conn, + bool ascii); +static CURLcode ftp_do(struct connectdata *conn, bool *done); +static CURLcode ftp_done(struct connectdata *conn, + CURLcode, bool premature); +static CURLcode ftp_connect(struct connectdata *conn, bool *done); +static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection); +static CURLcode ftp_do_more(struct connectdata *conn, int *completed); +static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done); +static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks); +static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks); +static CURLcode ftp_doing(struct connectdata *conn, + bool *dophase_done); +static CURLcode ftp_setup_connection(struct connectdata * conn); + +static CURLcode init_wc_data(struct connectdata *conn); +static CURLcode wc_statemach(struct connectdata *conn); + +static void wc_data_dtor(void *ptr); + +static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize); + +static CURLcode ftp_readresp(curl_socket_t sockfd, + struct pingpong *pp, + int *ftpcode, + size_t *size); +static CURLcode ftp_dophase_done(struct connectdata *conn, + bool connected); + +/* easy-to-use macro: */ - #define PPSENDF(x,y,z) if((result = Curl_pp_sendf(x,y,z))) \ - return result ++#define PPSENDF(x,y,z) result = Curl_pp_sendf(x,y,z); \ ++ if(result) \ ++ return result + + +/* + * FTP protocol handler. + */ + +const struct Curl_handler Curl_handler_ftp = { + "FTP", /* scheme */ + ftp_setup_connection, /* setup_connection */ + ftp_do, /* do_it */ + ftp_done, /* done */ + ftp_do_more, /* do_more */ + ftp_connect, /* connect_it */ + ftp_multi_statemach, /* connecting */ + ftp_doing, /* doing */ + ftp_getsock, /* proto_getsock */ + ftp_getsock, /* doing_getsock */ + ftp_domore_getsock, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ftp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ + PORT_FTP, /* defport */ + CURLPROTO_FTP, /* protocol */ + PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD + | PROTOPT_NOURLQUERY /* flags */ +}; + + +#ifdef USE_SSL +/* + * FTPS protocol handler. + */ + +const struct Curl_handler Curl_handler_ftps = { + "FTPS", /* scheme */ + ftp_setup_connection, /* setup_connection */ + ftp_do, /* do_it */ + ftp_done, /* done */ + ftp_do_more, /* do_more */ + ftp_connect, /* connect_it */ + ftp_multi_statemach, /* connecting */ + ftp_doing, /* doing */ + ftp_getsock, /* proto_getsock */ + ftp_getsock, /* doing_getsock */ + ftp_domore_getsock, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ftp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ + PORT_FTPS, /* defport */ + CURLPROTO_FTPS, /* protocol */ + PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION | + PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */ +}; +#endif + +#ifndef CURL_DISABLE_HTTP +/* + * HTTP-proxyed FTP protocol handler. + */ + +static const struct Curl_handler Curl_handler_ftp_proxy = { + "FTP", /* scheme */ + Curl_http_setup_conn, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + ZERO_NULL, /* do_more */ + ZERO_NULL, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ + PORT_FTP, /* defport */ + CURLPROTO_HTTP, /* protocol */ + PROTOPT_NONE /* flags */ +}; + + +#ifdef USE_SSL +/* + * HTTP-proxyed FTPS protocol handler. + */ + +static const struct Curl_handler Curl_handler_ftps_proxy = { + "FTPS", /* scheme */ + Curl_http_setup_conn, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + ZERO_NULL, /* do_more */ + ZERO_NULL, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ + PORT_FTPS, /* defport */ + CURLPROTO_HTTP, /* protocol */ + PROTOPT_NONE /* flags */ +}; +#endif +#endif + ++static void close_secondarysocket(struct connectdata *conn) ++{ ++ if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) { ++ Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); ++ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; ++ } ++ conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; ++ conn->tunnel_state[SECONDARYSOCKET] = TUNNEL_INIT; ++} + +/* + * NOTE: back in the old days, we added code in the FTP code that made NOBODY + * requests on files respond with headers passed to the client/stdout that + * looked like HTTP ones. + * + * This approach is not very elegant, it causes confusion and is error-prone. + * It is subject for removal at the next (or at least a future) soname bump. + * Until then you can test the effects of the removal by undefining the + * following define named CURL_FTP_HTTPSTYLE_HEAD. + */ +#define CURL_FTP_HTTPSTYLE_HEAD 1 + +static void freedirs(struct ftp_conn *ftpc) +{ + int i; + if(ftpc->dirs) { + for(i=0; i < ftpc->dirdepth; i++) { + free(ftpc->dirs[i]); + ftpc->dirs[i]=NULL; + } + free(ftpc->dirs); + ftpc->dirs = NULL; + ftpc->dirdepth = 0; + } + Curl_safefree(ftpc->file); + + /* no longer of any use */ + Curl_safefree(ftpc->newhost); +} + +/* Returns non-zero if the given string contains CR (\r) or LF (\n), + which are not allowed within RFC 959 . + Note: The input string is in the client's encoding which might + not be ASCII, so escape sequences \r & \n must be used instead + of hex values 0x0d & 0x0a. +*/ +static bool isBadFtpString(const char *string) +{ + return ((NULL != strchr(string, '\r')) || + (NULL != strchr(string, '\n'))) ? TRUE : FALSE; +} + +/*********************************************************************** + * + * AcceptServerConnect() + * + * After connection request is received from the server this function is + * called to accept the connection and close the listening socket + * + */ +static CURLcode AcceptServerConnect(struct connectdata *conn) +{ - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + curl_socket_t sock = conn->sock[SECONDARYSOCKET]; + curl_socket_t s = CURL_SOCKET_BAD; +#ifdef ENABLE_IPV6 + struct Curl_sockaddr_storage add; +#else + struct sockaddr_in add; +#endif + curl_socklen_t size = (curl_socklen_t) sizeof(add); + + if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) { + size = sizeof(add); + + s=accept(sock, (struct sockaddr *) &add, &size); + } + Curl_closesocket(conn, sock); /* close the first socket */ + + if(CURL_SOCKET_BAD == s) { + failf(data, "Error accept()ing server connect"); + return CURLE_FTP_PORT_FAILED; + } + infof(data, "Connection accepted from server\n"); ++ /* when this happens within the DO state it is important that we mark us as ++ not needing DO_MORE anymore */ ++ conn->bits.do_more = FALSE; + + conn->sock[SECONDARYSOCKET] = s; + (void)curlx_nonblock(s, TRUE); /* enable non-blocking */ + conn->sock_accepted[SECONDARYSOCKET] = TRUE; + + if(data->set.fsockopt) { + int error = 0; + + /* activate callback for setting socket options */ + error = data->set.fsockopt(data->set.sockopt_client, + s, + CURLSOCKTYPE_ACCEPT); + + if(error) { - Curl_closesocket(conn, s); /* close the socket and bail out */ - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; ++ close_secondarysocket(conn); + return CURLE_ABORTED_BY_CALLBACK; + } + } + + return CURLE_OK; + +} + +/* + * ftp_timeleft_accept() returns the amount of milliseconds left allowed for + * waiting server to connect. If the value is negative, the timeout time has + * already elapsed. + * + * The start time is stored in progress.t_acceptdata - as set with + * Curl_pgrsTime(..., TIMER_STARTACCEPT); + * + */ - static long ftp_timeleft_accept(struct SessionHandle *data) ++static long ftp_timeleft_accept(struct Curl_easy *data) +{ + long timeout_ms = DEFAULT_ACCEPT_TIMEOUT; + long other; + struct timeval now; + + if(data->set.accepttimeout > 0) + timeout_ms = data->set.accepttimeout; + + now = Curl_tvnow(); + + /* check if the generic timeout possibly is set shorter */ + other = Curl_timeleft(data, &now, FALSE); + if(other && (other < timeout_ms)) + /* note that this also works fine for when other happens to be negative + due to it already having elapsed */ + timeout_ms = other; + else { + /* subtract elapsed time */ + timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata); + if(!timeout_ms) + /* avoid returning 0 as that means no timeout! */ + return -1; + } + + return timeout_ms; +} + + +/*********************************************************************** + * + * ReceivedServerConnect() + * + * After allowing server to connect to us from data port, this function + * checks both data connection for connection establishment and ctrl + * connection for a negative response regarding a failure in connecting + * + */ +static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received) +{ - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET]; + curl_socket_t data_sock = conn->sock[SECONDARYSOCKET]; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + int result; + long timeout_ms; + ssize_t nread; + int ftpcode; + + *received = FALSE; + + timeout_ms = ftp_timeleft_accept(data); + infof(data, "Checking for server connect\n"); + if(timeout_ms < 0) { + /* if a timeout was already reached, bail out */ + failf(data, "Accept timeout occurred while waiting server connect"); + return CURLE_FTP_ACCEPT_TIMEOUT; + } + + /* First check whether there is a cached response from server */ + if(pp->cache_size && pp->cache && pp->cache[0] > '3') { + /* Data connection could not be established, let's return */ + infof(data, "There is negative response in cache while serv connect\n"); + Curl_GetFTPResponse(&nread, conn, &ftpcode); + return CURLE_FTP_ACCEPT_FAILED; + } + + result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0); + + /* see if the connection request is already here */ + switch (result) { + case -1: /* error */ + /* let's die here */ + failf(data, "Error while waiting for server connect"); + return CURLE_FTP_ACCEPT_FAILED; + case 0: /* Server connect is not received yet */ + break; /* loop */ + default: + + if(result & CURL_CSELECT_IN2) { + infof(data, "Ready to accept data connection from server\n"); + *received = TRUE; + } + else if(result & CURL_CSELECT_IN) { + infof(data, "Ctrl conn has data while waiting for data conn\n"); + Curl_GetFTPResponse(&nread, conn, &ftpcode); + + if(ftpcode/100 > 3) + return CURLE_FTP_ACCEPT_FAILED; + + return CURLE_FTP_WEIRD_SERVER_REPLY; + } + + break; + } /* switch() */ + + return CURLE_OK; +} + + +/*********************************************************************** + * + * InitiateTransfer() + * + * After connection from server is accepted this function is called to + * setup transfer parameters and initiate the data transfer. + * + */ +static CURLcode InitiateTransfer(struct connectdata *conn) +{ - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + struct FTP *ftp = data->req.protop; + CURLcode result = CURLE_OK; + + if(conn->ssl[SECONDARYSOCKET].use) { + /* since we only have a plaintext TCP connection here, we must now + * do the TLS stuff */ + infof(data, "Doing the SSL/TLS handshake on the data stream\n"); + result = Curl_ssl_connect(conn, SECONDARYSOCKET); + if(result) + return result; + } + + if(conn->proto.ftpc.state_saved == FTP_STOR) { + *(ftp->bytecountp)=0; + + /* When we know we're uploading a specified file, we can get the file + size prior to the actual upload. */ + + Curl_pgrsSetUploadSize(data, data->state.infilesize); + + /* set the SO_SNDBUF for the secondary socket for those who need it */ + Curl_sndbufset(conn->sock[SECONDARYSOCKET]); + + Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */ + SECONDARYSOCKET, ftp->bytecountp); + } + else { + /* FTP download: */ + Curl_setup_transfer(conn, SECONDARYSOCKET, + conn->proto.ftpc.retr_size_saved, FALSE, + ftp->bytecountp, -1, NULL); /* no upload here */ + } + + conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */ + state(conn, FTP_STOP); + + return CURLE_OK; +} + +/*********************************************************************** + * + * AllowServerConnect() + * + * When we've issue the PORT command, we have told the server to connect to + * us. This function checks whether data connection is established if so it is + * accepted. + * + */ +static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected) +{ - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + long timeout_ms; + CURLcode result = CURLE_OK; + + *connected = FALSE; + infof(data, "Preparing for accepting server on data port\n"); + + /* Save the time we start accepting server connect */ + Curl_pgrsTime(data, TIMER_STARTACCEPT); + + timeout_ms = ftp_timeleft_accept(data); + if(timeout_ms < 0) { + /* if a timeout was already reached, bail out */ + failf(data, "Accept timeout occurred while waiting server connect"); + return CURLE_FTP_ACCEPT_TIMEOUT; + } + + /* see if the connection request is already here */ + result = ReceivedServerConnect(conn, connected); + if(result) + return result; + + if(*connected) { + result = AcceptServerConnect(conn); + if(result) + return result; + + result = InitiateTransfer(conn); + if(result) + return result; + } + else { + /* Add timeout to multi handle and break out of the loop */ + if(!result && *connected == FALSE) { + if(data->set.accepttimeout > 0) + Curl_expire(data, data->set.accepttimeout); + else + Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT); + } + } + + return result; +} + +/* macro to check for a three-digit ftp status code at the start of the + given string */ +#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \ + ISDIGIT(line[2])) + +/* macro to check for the last line in an FTP server response */ +#define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3])) + +static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len, + int *code) +{ + (void)conn; + + if((len > 3) && LASTLINE(line)) { + *code = curlx_sltosi(strtol(line, NULL, 10)); + return TRUE; + } + + return FALSE; +} + +static CURLcode ftp_readresp(curl_socket_t sockfd, + struct pingpong *pp, + int *ftpcode, /* return the ftp-code if done */ + size_t *size) /* size of the response */ +{ + struct connectdata *conn = pp->conn; - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; +#ifdef HAVE_GSSAPI + char * const buf = data->state.buffer; +#endif + CURLcode result = CURLE_OK; + int code; + + result = Curl_pp_readresp(sockfd, pp, &code, size); + +#if defined(HAVE_GSSAPI) + /* handle the security-oriented responses 6xx ***/ + /* FIXME: some errorchecking perhaps... ***/ + switch(code) { + case 631: + code = Curl_sec_read_msg(conn, buf, PROT_SAFE); + break; + case 632: + code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE); + break; + case 633: + code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL); + break; + default: + /* normal ftp stuff we pass through! */ + break; + } +#endif + + /* store the latest code for later retrieval */ + data->info.httpcode=code; + + if(ftpcode) + *ftpcode = code; + + if(421 == code) { + /* 421 means "Service not available, closing control connection." and FTP + * servers use it to signal that idle session timeout has been exceeded. + * If we ignored the response, it could end up hanging in some cases. + * + * This response code can come at any point so having it treated + * generically is a good idea. + */ + infof(data, "We got a 421 - timeout!\n"); + state(conn, FTP_STOP); + return CURLE_OPERATION_TIMEDOUT; + } + + return result; +} + +/* --- parse FTP server responses --- */ + +/* + * Curl_GetFTPResponse() is a BLOCKING function to read the full response + * from a server after a command. + * + */ + +CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ + struct connectdata *conn, + int *ftpcode) /* return the ftp-code */ +{ + /* + * We cannot read just one byte per read() and then go back to select() as + * the OpenSSL read() doesn't grok that properly. + * + * Alas, read as much as possible, split up into lines, use the ending + * line in a response or continue reading. */ + + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + long timeout; /* timeout in milliseconds */ + long interval_ms; - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + CURLcode result = CURLE_OK; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + size_t nread; + int cache_skip=0; + int value_to_be_ignored=0; + + if(ftpcode) + *ftpcode = 0; /* 0 for errors */ + else + /* make the pointer point to something for the rest of this function */ + ftpcode = &value_to_be_ignored; + + *nreadp=0; + + while(!*ftpcode && !result) { + /* check and reset timeout value every lap */ + timeout = Curl_pp_state_timeout(pp); + - if(timeout <=0 ) { ++ if(timeout <=0) { + failf(data, "FTP response timeout"); + return CURLE_OPERATION_TIMEDOUT; /* already too little time */ + } + + interval_ms = 1000; /* use 1 second timeout intervals */ + if(timeout < interval_ms) + interval_ms = timeout; + + /* + * Since this function is blocking, we need to wait here for input on the + * connection and only then we call the response reading function. We do + * timeout at least every second to make the timeout check run. + * + * A caution here is that the ftp_readresp() function has a cache that may + * contain pieces of a response from the previous invoke and we need to + * make sure we don't just wait for input while there is unhandled data in + * that cache. But also, if the cache is there, we call ftp_readresp() and + * the cache wasn't good enough to continue we must not just busy-loop + * around this function. + * + */ + + if(pp->cache && (cache_skip < 2)) { + /* + * There's a cache left since before. We then skipping the wait for + * socket action, unless this is the same cache like the previous round + * as then the cache was deemed not enough to act on and we then need to + * wait for more data anyway. + */ + } + else { + switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, interval_ms)) { + case -1: /* select() error, stop reading */ + failf(data, "FTP response aborted due to select/poll error: %d", + SOCKERRNO); + return CURLE_RECV_ERROR; + + case 0: /* timeout */ + if(Curl_pgrsUpdate(conn)) + return CURLE_ABORTED_BY_CALLBACK; + continue; /* just continue in our loop for the timeout duration */ + + default: /* for clarity */ + break; + } + } + result = ftp_readresp(sockfd, pp, ftpcode, &nread); + if(result) + break; + + if(!nread && pp->cache) + /* bump cache skip counter as on repeated skips we must wait for more + data */ + cache_skip++; + else + /* when we got data or there is no cache left, we reset the cache skip + counter */ + cache_skip=0; + + *nreadp += nread; + + } /* while there's buffer left and loop is requested */ + + pp->pending_resp = FALSE; + + return result; +} + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ +static const char * const ftp_state_names[]={ + "STOP", + "WAIT220", + "AUTH", + "USER", + "PASS", + "ACCT", + "PBSZ", + "PROT", + "CCC", + "PWD", + "SYST", + "NAMEFMT", + "QUOTE", + "RETR_PREQUOTE", + "STOR_PREQUOTE", + "POSTQUOTE", + "CWD", + "MKD", + "MDTM", + "TYPE", + "LIST_TYPE", + "RETR_TYPE", + "STOR_TYPE", + "SIZE", + "RETR_SIZE", + "STOR_SIZE", + "REST", + "RETR_REST", + "PORT", + "PRET", + "PASV", + "LIST", + "RETR", + "STOR", + "QUIT" +}; +#endif + +/* This is the ONLY way to change FTP state! */ +static void _state(struct connectdata *conn, + ftpstate newstate +#ifdef DEBUGBUILD + , int lineno +#endif + ) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + +#if defined(DEBUGBUILD) + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) lineno; +#else + if(ftpc->state != newstate) + infof(conn->data, "FTP %p (line %d) state change from %s to %s\n", + (void *)ftpc, lineno, ftp_state_names[ftpc->state], + ftp_state_names[newstate]); +#endif +#endif + + ftpc->state = newstate; +} + +static CURLcode ftp_state_user(struct connectdata *conn) +{ + CURLcode result; + struct FTP *ftp = conn->data->req.protop; + /* send USER */ + PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:""); + + state(conn, FTP_USER); + conn->data->state.ftp_trying_alternative = FALSE; + + return CURLE_OK; +} + +static CURLcode ftp_state_pwd(struct connectdata *conn) +{ + CURLcode result; + + /* send PWD to discover our entry point */ + PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD"); + state(conn, FTP_PWD); + + return CURLE_OK; +} + +/* For the FTP "protocol connect" and "doing" phases only */ +static int ftp_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) +{ + return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks); +} + +/* For the FTP "DO_MORE" phase only */ +static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(!numsocks) + return GETSOCK_BLANK; + + /* When in DO_MORE state, we could be either waiting for us to connect to a + * remote site, or we could wait for that site to connect to us. Or just + * handle ordinary commands. + */ + + if(FTP_STOP == ftpc->state) { + int bits = GETSOCK_READSOCK(0); + + /* if stopped and still in this state, then we're also waiting for a + connect on the secondary connection */ + socks[0] = conn->sock[FIRSTSOCKET]; + + if(!conn->data->set.ftp_use_port) { + int s; + int i; + /* PORT is used to tell the server to connect to us, and during that we + don't do happy eyeballs, but we do if we connect to the server */ + for(s=1, i=0; i<2; i++) { + if(conn->tempsock[i] != CURL_SOCKET_BAD) { + socks[s] = conn->tempsock[i]; + bits |= GETSOCK_WRITESOCK(s++); + } + } + } + else { + socks[1] = conn->sock[SECONDARYSOCKET]; + bits |= GETSOCK_WRITESOCK(1); + } + + return bits; + } + else + return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks); +} + +/* This is called after the FTP_QUOTE state is passed. + + ftp_state_cwd() sends the range of CWD commands to the server to change to + the correct directory. It may also need to send MKD commands to create + missing ones, if that option is enabled. +*/ +static CURLcode ftp_state_cwd(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(ftpc->cwddone) + /* already done and fine */ + result = ftp_state_mdtm(conn); + else { + ftpc->count2 = 0; /* count2 counts failed CWDs */ + + /* count3 is set to allow a MKD to fail once. In the case when first CWD + fails and then MKD fails (due to another session raced it to create the + dir) this then allows for a second try to CWD to it */ + ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0; + + if(conn->bits.reuse && ftpc->entrypath) { + /* This is a re-used connection. Since we change directory to where the + transfer is taking place, we must first get back to the original dir + where we ended up after login: */ + ftpc->count1 = 0; /* we count this as the first path, then we add one + for all upcoming ones in the ftp->dirs[] array */ + PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath); + state(conn, FTP_CWD); + } + else { + if(ftpc->dirdepth) { + ftpc->count1 = 1; + /* issue the first CWD, the rest is sent when the CWD responses are + received... */ + PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]); + state(conn, FTP_CWD); + } + else { + /* No CWD necessary */ + result = ftp_state_mdtm(conn); + } + } + } + return result; +} + +typedef enum { + EPRT, + PORT, + DONE +} ftpport; + +static CURLcode ftp_state_use_port(struct connectdata *conn, + ftpport fcmd) /* start with this */ + +{ + CURLcode result = CURLE_OK; + struct ftp_conn *ftpc = &conn->proto.ftpc; - struct SessionHandle *data=conn->data; ++ struct Curl_easy *data=conn->data; + curl_socket_t portsock= CURL_SOCKET_BAD; + char myhost[256] = ""; + + struct Curl_sockaddr_storage ss; + Curl_addrinfo *res, *ai; + curl_socklen_t sslen; + char hbuf[NI_MAXHOST]; + struct sockaddr *sa=(struct sockaddr *)&ss; + struct sockaddr_in * const sa4 = (void *)sa; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 * const sa6 = (void *)sa; +#endif + char tmp[1024]; + static const char mode[][5] = { "EPRT", "PORT" }; + int rc; + int error; + char *host = NULL; + char *string_ftpport = data->set.str[STRING_FTPPORT]; + struct Curl_dns_entry *h=NULL; + unsigned short port_min = 0; + unsigned short port_max = 0; + unsigned short port; + bool possibly_non_local = TRUE; + + char *addr = NULL; + + /* Step 1, figure out what is requested, + * accepted format : + * (ipv4|ipv6|domain|interface)?(:port(-range)?)? + */ + + if(data->set.str[STRING_FTPPORT] && + (strlen(data->set.str[STRING_FTPPORT]) > 1)) { + +#ifdef ENABLE_IPV6 + size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ? + INET6_ADDRSTRLEN : strlen(string_ftpport); +#else + size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ? + INET_ADDRSTRLEN : strlen(string_ftpport); +#endif + char *ip_start = string_ftpport; + char *ip_end = NULL; + char *port_start = NULL; + char *port_sep = NULL; + + addr = calloc(addrlen+1, 1); + if(!addr) + return CURLE_OUT_OF_MEMORY; + +#ifdef ENABLE_IPV6 + if(*string_ftpport == '[') { + /* [ipv6]:port(-range) */ + ip_start = string_ftpport + 1; - if((ip_end = strchr(string_ftpport, ']')) != NULL ) ++ if((ip_end = strchr(string_ftpport, ']')) != NULL) + strncpy(addr, ip_start, ip_end - ip_start); + } + else +#endif + if(*string_ftpport == ':') { + /* :port */ + ip_end = string_ftpport; + } + else if((ip_end = strchr(string_ftpport, ':')) != NULL) { + /* either ipv6 or (ipv4|domain|interface):port(-range) */ +#ifdef ENABLE_IPV6 + if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) { + /* ipv6 */ + port_min = port_max = 0; + strcpy(addr, string_ftpport); + ip_end = NULL; /* this got no port ! */ + } + else +#endif + /* (ipv4|domain|interface):port(-range) */ - strncpy(addr, string_ftpport, ip_end - ip_start ); ++ strncpy(addr, string_ftpport, ip_end - ip_start); + } + else + /* ipv4|interface */ + strcpy(addr, string_ftpport); + + /* parse the port */ + if(ip_end != NULL) { + if((port_start = strchr(ip_end, ':')) != NULL) { + port_min = curlx_ultous(strtoul(port_start+1, NULL, 10)); + if((port_sep = strchr(port_start, '-')) != NULL) { + port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10)); + } + else + port_max = port_min; + } + } + + /* correct errors like: + * :1234-1230 - * :-4711 , in this case port_min is (unsigned)-1, ++ * :-4711, in this case port_min is (unsigned)-1, + * therefore port_min > port_max for all cases + * but port_max = (unsigned)-1 + */ - if(port_min > port_max ) ++ if(port_min > port_max) + port_min = port_max = 0; + + + if(*addr != '\0') { + /* attempt to get the address of the given interface name */ + switch(Curl_if2ip(conn->ip_addr->ai_family, + Curl_ipv6_scope(conn->ip_addr->ai_addr), + conn->scope_id, addr, hbuf, sizeof(hbuf))) { + case IF2IP_NOT_FOUND: + /* not an interface, use the given string as host name instead */ + host = addr; + break; + case IF2IP_AF_NOT_SUPPORTED: + return CURLE_FTP_PORT_FAILED; + case IF2IP_FOUND: + host = hbuf; /* use the hbuf for host name */ + } + } + else + /* there was only a port(-range) given, default the host */ + host = NULL; + } /* data->set.ftpport */ + + if(!host) { + /* not an interface and not a host name, get default by extracting + the IP from the control connection */ + + sslen = sizeof(ss); + if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { + failf(data, "getsockname() failed: %s", + Curl_strerror(conn, SOCKERRNO) ); + free(addr); + return CURLE_FTP_PORT_FAILED; + } + switch(sa->sa_family) { +#ifdef ENABLE_IPV6 + case AF_INET6: + Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf)); + break; +#endif + default: + Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf)); + break; + } + host = hbuf; /* use this host name */ + possibly_non_local = FALSE; /* we know it is local now */ + } + + /* resolv ip/host to ip */ + rc = Curl_resolv(conn, host, 0, &h); + if(rc == CURLRESOLV_PENDING) + (void)Curl_resolver_wait_resolv(conn, &h); + if(h) { + res = h->addr; + /* when we return from this function, we can forget about this entry + to we can unlock it now already */ + Curl_resolv_unlock(data, h); + } /* (h) */ + else + res = NULL; /* failure! */ + + if(res == NULL) { + failf(data, "failed to resolve the address provided to PORT: %s", host); + free(addr); + return CURLE_FTP_PORT_FAILED; + } + + free(addr); + host = NULL; + + /* step 2, create a socket for the requested address */ + + portsock = CURL_SOCKET_BAD; + error = 0; + for(ai = res; ai; ai = ai->ai_next) { + result = Curl_socket(conn, ai, NULL, &portsock); + if(result) { + error = SOCKERRNO; + continue; + } + break; + } + if(!ai) { + failf(data, "socket failure: %s", Curl_strerror(conn, error)); + return CURLE_FTP_PORT_FAILED; + } + + /* step 3, bind to a suitable local address */ + + memcpy(sa, ai->ai_addr, ai->ai_addrlen); + sslen = ai->ai_addrlen; + + for(port = port_min; port <= port_max;) { + if(sa->sa_family == AF_INET) + sa4->sin_port = htons(port); +#ifdef ENABLE_IPV6 + else + sa6->sin6_port = htons(port); +#endif + /* Try binding the given address. */ + if(bind(portsock, sa, sslen) ) { + /* It failed. */ + error = SOCKERRNO; + if(possibly_non_local && (error == EADDRNOTAVAIL)) { + /* The requested bind address is not local. Use the address used for + * the control connection instead and restart the port loop + */ + + infof(data, "bind(port=%hu) on non-local address failed: %s\n", port, + Curl_strerror(conn, error) ); + + sslen = sizeof(ss); + if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { + failf(data, "getsockname() failed: %s", + Curl_strerror(conn, SOCKERRNO) ); + Curl_closesocket(conn, portsock); + return CURLE_FTP_PORT_FAILED; + } + port = port_min; + possibly_non_local = FALSE; /* don't try this again */ + continue; + } + else if(error != EADDRINUSE && error != EACCES) { + failf(data, "bind(port=%hu) failed: %s", port, + Curl_strerror(conn, error) ); + Curl_closesocket(conn, portsock); + return CURLE_FTP_PORT_FAILED; + } + } + else + break; + + port++; + } + + /* maybe all ports were in use already*/ + if(port > port_max) { + failf(data, "bind() failed, we ran out of ports!"); + Curl_closesocket(conn, portsock); + return CURLE_FTP_PORT_FAILED; + } + + /* get the name again after the bind() so that we can extract the + port number it uses now */ + sslen = sizeof(ss); + if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) { + failf(data, "getsockname() failed: %s", + Curl_strerror(conn, SOCKERRNO) ); + Curl_closesocket(conn, portsock); + return CURLE_FTP_PORT_FAILED; + } + + /* step 4, listen on the socket */ + + if(listen(portsock, 1)) { + failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO)); + Curl_closesocket(conn, portsock); + return CURLE_FTP_PORT_FAILED; + } + + /* step 5, send the proper FTP command */ + + /* get a plain printable version of the numerical address to work with + below */ + Curl_printable_address(ai, myhost, sizeof(myhost)); + +#ifdef ENABLE_IPV6 + if(!conn->bits.ftp_use_eprt && conn->bits.ipv6) + /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the + request and enable EPRT again! */ + conn->bits.ftp_use_eprt = TRUE; +#endif + + for(; fcmd != DONE; fcmd++) { + + if(!conn->bits.ftp_use_eprt && (EPRT == fcmd)) + /* if disabled, goto next */ + continue; + + if((PORT == fcmd) && sa->sa_family != AF_INET) + /* PORT is IPv4 only */ + continue; + + switch(sa->sa_family) { + case AF_INET: + port = ntohs(sa4->sin_port); + break; +#ifdef ENABLE_IPV6 + case AF_INET6: + port = ntohs(sa6->sin6_port); + break; +#endif + default: + continue; /* might as well skip this */ + } + + if(EPRT == fcmd) { + /* + * Two fine examples from RFC2428; + * + * EPRT |1|132.235.1.2|6275| + * + * EPRT |2|1080::8:800:200C:417A|5282| + */ + + result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd], + sa->sa_family == AF_INET?1:2, + myhost, port); + if(result) { + failf(data, "Failure sending EPRT command: %s", + curl_easy_strerror(result)); + Curl_closesocket(conn, portsock); + /* don't retry using PORT */ + ftpc->count1 = PORT; + /* bail out */ + state(conn, FTP_STOP); + return result; + } + break; + } + else if(PORT == fcmd) { + char *source = myhost; + char *dest = tmp; + + /* translate x.x.x.x to x,x,x,x */ + while(source && *source) { + if(*source == '.') + *dest=','; + else + *dest = *source; + dest++; + source++; + } + *dest = 0; + snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff)); + + result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp); + if(result) { + failf(data, "Failure sending PORT command: %s", + curl_easy_strerror(result)); + Curl_closesocket(conn, portsock); + /* bail out */ + state(conn, FTP_STOP); + return result; + } + break; + } + } + + /* store which command was sent */ + ftpc->count1 = fcmd; + ++ close_secondarysocket(conn); ++ + /* we set the secondary socket variable to this for now, it is only so that + the cleanup function will close it in case we fail before the true + secondary stuff is made */ - if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) - Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); + conn->sock[SECONDARYSOCKET] = portsock; + + /* this tcpconnect assignment below is a hackish work-around to make the + multi interface with active FTP work - as it will not wait for a + (passive) connect in Curl_is_connected(). + + The *proper* fix is to make sure that the active connection from the + server is done in a non-blocking way. Currently, it is still BLOCKING. + */ + conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE; + + state(conn, FTP_PORT); + return result; +} + +static CURLcode ftp_state_use_pasv(struct connectdata *conn) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + CURLcode result = CURLE_OK; + /* + Here's the excecutive summary on what to do: + + PASV is RFC959, expect: + 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2) + + LPSV is RFC1639, expect: + 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2) + + EPSV is RFC2428, expect: + 229 Entering Extended Passive Mode (|||port|) + + */ + + static const char mode[][5] = { "EPSV", "PASV" }; + int modeoff; + +#ifdef PF_INET6 + if(!conn->bits.ftp_use_epsv && conn->bits.ipv6) + /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the + request and enable EPSV again! */ + conn->bits.ftp_use_epsv = TRUE; +#endif + + modeoff = conn->bits.ftp_use_epsv?0:1; + + PPSENDF(&ftpc->pp, "%s", mode[modeoff]); + + ftpc->count1 = modeoff; + state(conn, FTP_PASV); + infof(conn->data, "Connect data stream passively\n"); + + return result; +} + +/* + * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc. + * + * REST is the last command in the chain of commands when a "head"-like + * request is made. Thus, if an actual transfer is to be made this is where we + * take off for real. + */ +static CURLcode ftp_state_prepare_transfer(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = conn->data->req.protop; - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + + if(ftp->transfer != FTPTRANSFER_BODY) { + /* doesn't transfer any data */ + + /* still possibly do PRE QUOTE jobs */ + state(conn, FTP_RETR_PREQUOTE); + result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE); + } + else if(data->set.ftp_use_port) { + /* We have chosen to use the PORT (or similar) command */ + result = ftp_state_use_port(conn, EPRT); + } + else { + /* We have chosen (this is default) to use the PASV (or similar) command */ + if(data->set.ftp_use_pret) { + /* The user has requested that we send a PRET command + to prepare the server for the upcoming PASV */ + if(!conn->proto.ftpc.file) { + PPSENDF(&conn->proto.ftpc.pp, "PRET %s", + data->set.str[STRING_CUSTOMREQUEST]? + data->set.str[STRING_CUSTOMREQUEST]: + (data->set.ftp_list_only?"NLST":"LIST")); + } + else if(data->set.upload) { + PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file); + } + else { + PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file); + } + state(conn, FTP_PRET); + } + else { + result = ftp_state_use_pasv(conn); + } + } + return result; +} + +static CURLcode ftp_state_rest(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = conn->data->req.protop; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) { + /* if a "head"-like request is being made (on a file) */ + + /* Determine if server can respond to REST command and therefore + whether it supports range */ + PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0); + + state(conn, FTP_REST); + } + else + result = ftp_state_prepare_transfer(conn); + + return result; +} + +static CURLcode ftp_state_size(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = conn->data->req.protop; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) { + /* if a "head"-like request is being made (on a file) */ + + /* we know ftpc->file is a valid pointer to a file name */ + PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); + + state(conn, FTP_SIZE); + } + else + result = ftp_state_rest(conn); + + return result; +} + +static CURLcode ftp_state_list(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + + /* If this output is to be machine-parsed, the NLST command might be better + to use, since the LIST command output is not specified or standard in any + way. It has turned out that the NLST list output is not the same on all + servers either... */ + + /* + if FTPFILE_NOCWD was specified, we are currently in + the user's home directory, so we should add the path + as argument for the LIST / NLST / or custom command. + Whether the server will support this, is uncertain. + + The other ftp_filemethods will CWD into dir/dir/ first and + then just do LIST (in that case: nothing to do here) + */ + char *cmd, *lstArg, *slashPos; + + lstArg = NULL; + if((data->set.ftp_filemethod == FTPFILE_NOCWD) && + data->state.path && + data->state.path[0] && + strchr(data->state.path, '/')) { + + lstArg = strdup(data->state.path); + if(!lstArg) + return CURLE_OUT_OF_MEMORY; + + /* Check if path does not end with /, as then we cut off the file part */ + if(lstArg[strlen(lstArg) - 1] != '/') { + + /* chop off the file part if format is dir/dir/file */ + slashPos = strrchr(lstArg, '/'); + if(slashPos) + *(slashPos+1) = '\0'; + } + } + - cmd = aprintf( "%s%s%s", - data->set.str[STRING_CUSTOMREQUEST]? - data->set.str[STRING_CUSTOMREQUEST]: - (data->set.ftp_list_only?"NLST":"LIST"), - lstArg? " ": "", - lstArg? lstArg: "" ); ++ cmd = aprintf("%s%s%s", ++ data->set.str[STRING_CUSTOMREQUEST]? ++ data->set.str[STRING_CUSTOMREQUEST]: ++ (data->set.ftp_list_only?"NLST":"LIST"), ++ lstArg? " ": "", ++ lstArg? lstArg: ""); + + if(!cmd) { + free(lstArg); + return CURLE_OUT_OF_MEMORY; + } + + result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd); + + free(lstArg); + free(cmd); + + if(result) + return result; + + state(conn, FTP_LIST); + + return result; +} + +static CURLcode ftp_state_retr_prequote(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + /* We've sent the TYPE, now we must send the list of prequote strings */ + + result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE); + + return result; +} + +static CURLcode ftp_state_stor_prequote(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + /* We've sent the TYPE, now we must send the list of prequote strings */ + + result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE); + + return result; +} + +static CURLcode ftp_state_type(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = conn->data->req.protop; - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + /* If we have selected NOBODY and HEADER, it means that we only want file + information. Which in FTP can't be much more than the file size and + date. */ + if(data->set.opt_no_body && ftpc->file && + ftp_need_type(conn, data->set.prefer_ascii)) { + /* The SIZE command is _not_ RFC 959 specified, and therefor many servers + may not support it! It is however the only way we have to get a file's + size! */ + + ftp->transfer = FTPTRANSFER_INFO; + /* this means no actual transfer will be made */ + + /* Some servers return different sizes for different modes, and thus we + must set the proper type before we check the size */ + result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE); + if(result) + return result; + } + else + result = ftp_state_size(conn); + + return result; +} + +/* This is called after the CWD commands have been done in the beginning of + the DO phase */ +static CURLcode ftp_state_mdtm(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + /* Requested time of file or time-depended transfer? */ + if((data->set.get_filetime || data->set.timecondition) && ftpc->file) { + + /* we have requested to get the modified-time of the file, this is a white + spot as the MDTM is not mentioned in RFC959 */ + PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file); + + state(conn, FTP_MDTM); + } + else + result = ftp_state_type(conn); + + return result; +} + + +/* This is called after the TYPE and possible quote commands have been sent */ +static CURLcode ftp_state_ul_setup(struct connectdata *conn, + bool sizechecked) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = conn->data->req.protop; - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + struct ftp_conn *ftpc = &conn->proto.ftpc; + int seekerr = CURL_SEEKFUNC_OK; + + if((data->state.resume_from && !sizechecked) || + ((data->state.resume_from > 0) && sizechecked)) { + /* we're about to continue the uploading of a file */ + /* 1. get already existing file's size. We use the SIZE command for this + which may not exist in the server! The SIZE command is not in + RFC959. */ + + /* 2. This used to set REST. But since we can do append, we + don't another ftp command. We just skip the source file + offset and then we APPEND the rest on the file instead */ + + /* 3. pass file-size number of bytes in the source file */ + /* 4. lower the infilesize counter */ + /* => transfer as usual */ + - if(data->state.resume_from < 0 ) { ++ if(data->state.resume_from < 0) { + /* Got no given size to start from, figure it out */ + PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); + state(conn, FTP_STOR_SIZE); + return result; + } + + /* enable append */ + data->set.ftp_append = TRUE; + + /* Let's read off the proper amount of bytes from the input. */ + if(conn->seek_func) { + seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, + SEEK_SET); + } + + if(seekerr != CURL_SEEKFUNC_OK) { + if(seekerr != CURL_SEEKFUNC_CANTSEEK) { + failf(data, "Could not seek stream"); + return CURLE_FTP_COULDNT_USE_REST; + } + /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ + else { + curl_off_t passed=0; + do { + size_t readthisamountnow = + (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ? + BUFSIZE : curlx_sotouz(data->state.resume_from - passed); + + size_t actuallyread = - data->set.fread_func(data->state.buffer, 1, readthisamountnow, - data->set.in); ++ data->state.fread_func(data->state.buffer, 1, readthisamountnow, ++ data->state.in); + + passed += actuallyread; + if((actuallyread == 0) || (actuallyread > readthisamountnow)) { + /* this checks for greater-than only to make sure that the + CURL_READFUNC_ABORT return code still aborts */ + failf(data, "Failed to read data"); + return CURLE_FTP_COULDNT_USE_REST; + } + } while(passed < data->state.resume_from); + } + } + /* now, decrease the size of the read */ + if(data->state.infilesize>0) { + data->state.infilesize -= data->state.resume_from; + + if(data->state.infilesize <= 0) { + infof(data, "File already completely uploaded\n"); + + /* no data to transfer */ + Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + + /* Set ->transfer so that we won't get any error in + * ftp_done() because we didn't transfer anything! */ + ftp->transfer = FTPTRANSFER_NONE; + + state(conn, FTP_STOP); + return CURLE_OK; + } + } + /* we've passed, proceed as normal */ + } /* resume_from */ + + PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s", + ftpc->file); + + state(conn, FTP_STOR); + + return result; +} + +static CURLcode ftp_state_quote(struct connectdata *conn, + bool init, + ftpstate instate) +{ + CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + struct FTP *ftp = data->req.protop; + struct ftp_conn *ftpc = &conn->proto.ftpc; + bool quote=FALSE; + struct curl_slist *item; + + switch(instate) { + case FTP_QUOTE: + default: + item = data->set.quote; + break; + case FTP_RETR_PREQUOTE: + case FTP_STOR_PREQUOTE: + item = data->set.prequote; + break; + case FTP_POSTQUOTE: + item = data->set.postquote; + break; + } + + /* + * This state uses: + * 'count1' to iterate over the commands to send + * 'count2' to store wether to allow commands to fail + */ + + if(init) + ftpc->count1 = 0; + else + ftpc->count1++; + + if(item) { + int i = 0; + + /* Skip count1 items in the linked list */ + while((i< ftpc->count1) && item) { + item = item->next; + i++; + } + if(item) { + char *cmd = item->data; + if(cmd[0] == '*') { + cmd++; + ftpc->count2 = 1; /* the sent command is allowed to fail */ + } + else + ftpc->count2 = 0; /* failure means cancel operation */ + + PPSENDF(&ftpc->pp, "%s", cmd); + state(conn, instate); + quote = TRUE; + } + } + + if(!quote) { + /* No more quote to send, continue to ... */ + switch(instate) { + case FTP_QUOTE: + default: + result = ftp_state_cwd(conn); + break; + case FTP_RETR_PREQUOTE: + if(ftp->transfer != FTPTRANSFER_BODY) + state(conn, FTP_STOP); + else { + if(ftpc->known_filesize != -1) { + Curl_pgrsSetDownloadSize(data, ftpc->known_filesize); + result = ftp_state_retr(conn, ftpc->known_filesize); + } + else { - PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); - state(conn, FTP_RETR_SIZE); ++ if(data->set.ignorecl) { ++ /* This code is to support download of growing files. It prevents ++ the state machine from requesting the file size from the ++ server. With an unknown file size the download continues until ++ the server terminates it, otherwise the client stops if the ++ received byte count exceeds the reported file size. Set option ++ CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/ ++ PPSENDF(&ftpc->pp, "RETR %s", ftpc->file); ++ state(conn, FTP_RETR); ++ } ++ else { ++ PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); ++ state(conn, FTP_RETR_SIZE); ++ } + } + } + break; + case FTP_STOR_PREQUOTE: + result = ftp_state_ul_setup(conn, FALSE); + break; + case FTP_POSTQUOTE: + break; + } + } + + return result; +} + +/* called from ftp_state_pasv_resp to switch to PASV in case of EPSV + problems */ +static CURLcode ftp_epsv_disable(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + if(conn->bits.ipv6) { + /* We can't disable EPSV when doing IPv6, so this is instead a fail */ + failf(conn->data, "Failed EPSV attempt, exiting\n"); + return CURLE_FTP_WEIRD_SERVER_REPLY; + } + + infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n"); + /* disable it for next transfer */ + conn->bits.ftp_use_epsv = FALSE; + conn->data->state.errorbuf = FALSE; /* allow error message to get + rewritten */ + PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV"); + conn->proto.ftpc.count1++; + /* remain in/go to the FTP_PASV state */ + state(conn, FTP_PASV); + return result; +} + +/* + * Perform the necessary magic that needs to be done once the TCP connection + * to the proxy has completed. + */ +static CURLcode proxy_magic(struct connectdata *conn, + char *newhost, unsigned short newport, + bool *magicdone) +{ + CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + +#if defined(CURL_DISABLE_PROXY) + (void) newhost; + (void) newport; +#endif + + *magicdone = FALSE; + + switch(conn->proxytype) { + case CURLPROXY_SOCKS5: + case CURLPROXY_SOCKS5_HOSTNAME: + result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, + newport, SECONDARYSOCKET, conn); + *magicdone = TRUE; + break; + case CURLPROXY_SOCKS4: + result = Curl_SOCKS4(conn->proxyuser, newhost, newport, + SECONDARYSOCKET, conn, FALSE); + *magicdone = TRUE; + break; + case CURLPROXY_SOCKS4A: + result = Curl_SOCKS4(conn->proxyuser, newhost, newport, + SECONDARYSOCKET, conn, TRUE); + *magicdone = TRUE; + break; + case CURLPROXY_HTTP: + case CURLPROXY_HTTP_1_0: + /* do nothing here. handled later. */ + break; + default: + failf(data, "unknown proxytype option given"); + result = CURLE_COULDNT_CONNECT; + break; + } + + if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { + /* BLOCKING */ + /* We want "seamless" FTP operations through HTTP proxy tunnel */ + + /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the + * member conn->proto.http; we want FTP through HTTP and we have to + * change the member temporarily for connecting to the HTTP proxy. After + * Curl_proxyCONNECT we have to set back the member to the original + * struct FTP pointer + */ + struct HTTP http_proxy; + struct FTP *ftp_save = data->req.protop; + memset(&http_proxy, 0, sizeof(http_proxy)); + data->req.protop = &http_proxy; + + result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport, TRUE); + + data->req.protop = ftp_save; + + if(result) + return result; + + if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) { + /* the CONNECT procedure is not complete, the tunnel is not yet up */ + state(conn, FTP_STOP); /* this phase is completed */ + return result; + } + else + *magicdone = TRUE; + } + + return result; +} + +static char *control_address(struct connectdata *conn) +{ + /* Returns the control connection IP address. + If a proxy tunnel is used, returns the original host name instead, because + the effective control connection address is the proxy address, + not the ftp host. */ + if(conn->bits.tunnel_proxy || + conn->proxytype == CURLPROXY_SOCKS5 || + conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME || + conn->proxytype == CURLPROXY_SOCKS4 || + conn->proxytype == CURLPROXY_SOCKS4A) + return conn->host.name; + + return conn->ip_addr_str; +} + +static CURLcode ftp_state_pasv_resp(struct connectdata *conn, + int ftpcode) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + CURLcode result; - struct SessionHandle *data=conn->data; ++ struct Curl_easy *data=conn->data; + struct Curl_dns_entry *addr=NULL; + int rc; + unsigned short connectport; /* the local port connect() should use! */ + char *str=&data->state.buffer[4]; /* start on the first letter */ + + /* if we come here again, make sure the former name is cleared */ + Curl_safefree(ftpc->newhost); + + if((ftpc->count1 == 0) && + (ftpcode == 229)) { + /* positive EPSV response */ + char *ptr = strchr(str, '('); + if(ptr) { + unsigned int num; + char separator[4]; + ptr++; + if(5 == sscanf(ptr, "%c%c%c%u%c", + &separator[0], + &separator[1], + &separator[2], + &num, + &separator[3])) { + const char sep1 = separator[0]; + int i; + + /* The four separators should be identical, or else this is an oddly + formatted reply and we bail out immediately. */ + for(i=1; i<4; i++) { + if(separator[i] != sep1) { + ptr=NULL; /* set to NULL to signal error */ + break; + } + } + if(num > 0xffff) { + failf(data, "Illegal port number in EPSV reply"); + return CURLE_FTP_WEIRD_PASV_REPLY; + } + if(ptr) { + ftpc->newport = (unsigned short)(num & 0xffff); + ftpc->newhost = strdup(control_address(conn)); + if(!ftpc->newhost) + return CURLE_OUT_OF_MEMORY; + } + } + else + ptr=NULL; + } + if(!ptr) { + failf(data, "Weirdly formatted EPSV reply"); + return CURLE_FTP_WEIRD_PASV_REPLY; + } + } + else if((ftpc->count1 == 1) && + (ftpcode == 227)) { + /* positive PASV response */ + int ip[4]; + int port[2]; + + /* + * Scan for a sequence of six comma-separated numbers and use them as + * IP+port indicators. + * + * Found reply-strings include: + * "227 Entering Passive Mode (127,0,0,1,4,51)" + * "227 Data transfer will passively listen to 127,0,0,1,4,51" + * "227 Entering passive mode. 127,0,0,1,4,51" + */ + while(*str) { + if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d", + &ip[0], &ip[1], &ip[2], &ip[3], + &port[0], &port[1])) + break; + str++; + } + + if(!*str) { + failf(data, "Couldn't interpret the 227-response"); + return CURLE_FTP_WEIRD_227_FORMAT; + } + + /* we got OK from server */ + if(data->set.ftp_skip_ip) { + /* told to ignore the remotely given IP but instead use the host we used + for the control connection */ + infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n", + ip[0], ip[1], ip[2], ip[3], + conn->host.name); + ftpc->newhost = strdup(control_address(conn)); + } + else + ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + + if(!ftpc->newhost) + return CURLE_OUT_OF_MEMORY; + + ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff); + } + else if(ftpc->count1 == 0) { + /* EPSV failed, move on to PASV */ + return ftp_epsv_disable(conn); + } + else { + failf(data, "Bad PASV/EPSV response: %03d", ftpcode); + return CURLE_FTP_WEIRD_PASV_REPLY; + } + + if(conn->bits.proxy) { + /* + * This connection uses a proxy and we need to connect to the proxy again + * here. We don't want to rely on a former host lookup that might've + * expired now, instead we remake the lookup here and now! + */ + rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr); + if(rc == CURLRESOLV_PENDING) + /* BLOCKING, ignores the return code but 'addr' will be NULL in + case of failure */ + (void)Curl_resolver_wait_resolv(conn, &addr); + + connectport = + (unsigned short)conn->port; /* we connect to the proxy's port */ + + if(!addr) { + failf(data, "Can't resolve proxy host %s:%hu", + conn->proxy.name, connectport); + return CURLE_FTP_CANT_GET_HOST; + } + } + else { + /* normal, direct, ftp connection */ + rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr); + if(rc == CURLRESOLV_PENDING) + /* BLOCKING */ + (void)Curl_resolver_wait_resolv(conn, &addr); + + connectport = ftpc->newport; /* we connect to the remote port */ + + if(!addr) { + failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport); + return CURLE_FTP_CANT_GET_HOST; + } + } + + conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; + result = Curl_connecthost(conn, addr); + + if(result) { + Curl_resolv_unlock(data, addr); /* we're done using this address */ + if(ftpc->count1 == 0 && ftpcode == 229) + return ftp_epsv_disable(conn); + + return result; + } + + + /* + * When this is used from the multi interface, this might've returned with + * the 'connected' set to FALSE and thus we are now awaiting a non-blocking + * connect to connect. + */ + + if(data->set.verbose) + /* this just dumps information about this second connection */ + ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport); + + Curl_resolv_unlock(data, addr); /* we're done using this address */ + conn->bits.do_more = TRUE; + state(conn, FTP_STOP); /* this phase is completed */ + + return result; +} + +static CURLcode ftp_state_port_resp(struct connectdata *conn, + int ftpcode) +{ - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + struct ftp_conn *ftpc = &conn->proto.ftpc; + ftpport fcmd = (ftpport)ftpc->count1; + CURLcode result = CURLE_OK; + + /* The FTP spec tells a positive response should have code 200. + Be more permissive here to tolerate deviant servers. */ + if(ftpcode / 100 != 2) { + /* the command failed */ + + if(EPRT == fcmd) { + infof(data, "disabling EPRT usage\n"); + conn->bits.ftp_use_eprt = FALSE; + } + fcmd++; + + if(fcmd == DONE) { + failf(data, "Failed to do PORT"); + result = CURLE_FTP_PORT_FAILED; + } + else + /* try next */ + result = ftp_state_use_port(conn, fcmd); + } + else { + infof(data, "Connect data stream actively\n"); + state(conn, FTP_STOP); /* end of DO phase */ + result = ftp_dophase_done(conn, FALSE); + } + + return result; +} + +static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, + int ftpcode) +{ + CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; ++ struct Curl_easy *data=conn->data; + struct FTP *ftp = data->req.protop; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + switch(ftpcode) { + case 213: + { + /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the + last .sss part is optional and means fractions of a second */ + int year, month, day, hour, minute, second; + char *buf = data->state.buffer; + if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d", + &year, &month, &day, &hour, &minute, &second)) { + /* we have a time, reformat it */ + time_t secs=time(NULL); + /* using the good old yacc/bison yuck */ + snprintf(buf, sizeof(conn->data->state.buffer), + "%04d%02d%02d %02d:%02d:%02d GMT", + year, month, day, hour, minute, second); + /* now, convert this into a time() value: */ + data->info.filetime = (long)curl_getdate(buf, &secs); + } + +#ifdef CURL_FTP_HTTPSTYLE_HEAD + /* If we asked for a time of the file and we actually got one as well, + we "emulate" a HTTP-style header in our output. */ + + if(data->set.opt_no_body && + ftpc->file && + data->set.get_filetime && + (data->info.filetime>=0) ) { + time_t filetime = (time_t)data->info.filetime; + struct tm buffer; + const struct tm *tm = &buffer; + + result = Curl_gmtime(filetime, &buffer); + if(result) + return result; + + /* format: "Tue, 15 Nov 1994 12:45:26" */ + snprintf(buf, BUFSIZE-1, + "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", + Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); + result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); + if(result) + return result; + } /* end of a ridiculous amount of conditionals */ +#endif + } + break; + default: + infof(data, "unsupported MDTM reply format\n"); + break; + case 550: /* "No such file or directory" */ + failf(data, "Given file does not exist"); + result = CURLE_FTP_COULDNT_RETR_FILE; + break; + } + + if(data->set.timecondition) { + if((data->info.filetime > 0) && (data->set.timevalue > 0)) { + switch(data->set.timecondition) { + case CURL_TIMECOND_IFMODSINCE: + default: + if(data->info.filetime <= data->set.timevalue) { + infof(data, "The requested document is not new enough\n"); + ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */ + data->info.timecond = TRUE; + state(conn, FTP_STOP); + return CURLE_OK; + } + break; + case CURL_TIMECOND_IFUNMODSINCE: + if(data->info.filetime > data->set.timevalue) { + infof(data, "The requested document is not old enough\n"); + ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */ + data->info.timecond = TRUE; + state(conn, FTP_STOP); + return CURLE_OK; + } + break; + } /* switch */ + } + else { + infof(data, "Skipping time comparison\n"); + } + } + + if(!result) + result = ftp_state_type(conn); + + return result; +} + +static CURLcode ftp_state_type_resp(struct connectdata *conn, + int ftpcode, + ftpstate instate) +{ + CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; ++ struct Curl_easy *data=conn->data; + + if(ftpcode/100 != 2) { + /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a + successful 'TYPE I'. While that is not as RFC959 says, it is still a + positive response code and we allow that. */ + failf(data, "Couldn't set desired mode"); + return CURLE_FTP_COULDNT_SET_TYPE; + } + if(ftpcode != 200) + infof(data, "Got a %03d response code instead of the assumed 200\n", + ftpcode); + + if(instate == FTP_TYPE) + result = ftp_state_size(conn); + else if(instate == FTP_LIST_TYPE) + result = ftp_state_list(conn); + else if(instate == FTP_RETR_TYPE) + result = ftp_state_retr_prequote(conn); + else if(instate == FTP_STOR_TYPE) + result = ftp_state_stor_prequote(conn); + + return result; +} + +static CURLcode ftp_state_retr(struct connectdata *conn, + curl_off_t filesize) +{ + CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; ++ struct Curl_easy *data=conn->data; + struct FTP *ftp = data->req.protop; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(data->set.max_filesize && (filesize > data->set.max_filesize)) { + failf(data, "Maximum file size exceeded"); + return CURLE_FILESIZE_EXCEEDED; + } + ftp->downloadsize = filesize; + + if(data->state.resume_from) { + /* We always (attempt to) get the size of downloads, so it is done before + this even when not doing resumes. */ + if(filesize == -1) { + infof(data, "ftp server doesn't support SIZE\n"); + /* We couldn't get the size and therefore we can't know if there really + is a part of the file left to get, although the server will just + close the connection when we start the connection so it won't cause + us any harm, just not make us exit as nicely. */ + } + else { + /* We got a file size report, so we check that there actually is a + part of the file left to get, or else we go home. */ + if(data->state.resume_from< 0) { + /* We're supposed to download the last abs(from) bytes */ + if(filesize < -data->state.resume_from) { + failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T + ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", + data->state.resume_from, filesize); + return CURLE_BAD_DOWNLOAD_RESUME; + } + /* convert to size to download */ + ftp->downloadsize = -data->state.resume_from; + /* download from where? */ + data->state.resume_from = filesize - ftp->downloadsize; + } + else { + if(filesize < data->state.resume_from) { + failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T + ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", + data->state.resume_from, filesize); + return CURLE_BAD_DOWNLOAD_RESUME; + } + /* Now store the number of bytes we are expected to download */ + ftp->downloadsize = filesize-data->state.resume_from; + } + } + + if(ftp->downloadsize == 0) { + /* no data to transfer */ + Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + infof(data, "File already completely downloaded\n"); + + /* Set ->transfer so that we won't get any error in ftp_done() + * because we didn't transfer the any file */ + ftp->transfer = FTPTRANSFER_NONE; + state(conn, FTP_STOP); + return CURLE_OK; + } + + /* Set resume file transfer offset */ + infof(data, "Instructs server to resume from offset %" + CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from); + + PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T, + data->state.resume_from); + + state(conn, FTP_RETR_REST); + } + else { + /* no resume */ + PPSENDF(&ftpc->pp, "RETR %s", ftpc->file); + state(conn, FTP_RETR); + } + + return result; +} + +static CURLcode ftp_state_size_resp(struct connectdata *conn, + int ftpcode, + ftpstate instate) +{ + CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; ++ struct Curl_easy *data=conn->data; + curl_off_t filesize; + char *buf = data->state.buffer; + + /* get the size from the ascii string: */ + filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1; + + if(instate == FTP_SIZE) { +#ifdef CURL_FTP_HTTPSTYLE_HEAD + if(-1 != filesize) { + snprintf(buf, sizeof(data->state.buffer), + "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize); + result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); + if(result) + return result; + } +#endif + Curl_pgrsSetDownloadSize(data, filesize); + result = ftp_state_rest(conn); + } + else if(instate == FTP_RETR_SIZE) { + Curl_pgrsSetDownloadSize(data, filesize); + result = ftp_state_retr(conn, filesize); + } + else if(instate == FTP_STOR_SIZE) { + data->state.resume_from = filesize; + result = ftp_state_ul_setup(conn, TRUE); + } + + return result; +} + +static CURLcode ftp_state_rest_resp(struct connectdata *conn, + int ftpcode, + ftpstate instate) +{ + CURLcode result = CURLE_OK; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + switch(instate) { + case FTP_REST: + default: +#ifdef CURL_FTP_HTTPSTYLE_HEAD + if(ftpcode == 350) { + char buffer[24]= { "Accept-ranges: bytes\r\n" }; + result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0); + if(result) + return result; + } +#endif + result = ftp_state_prepare_transfer(conn); + break; + + case FTP_RETR_REST: + if(ftpcode != 350) { + failf(conn->data, "Couldn't use REST"); + result = CURLE_FTP_COULDNT_USE_REST; + } + else { + PPSENDF(&ftpc->pp, "RETR %s", ftpc->file); + state(conn, FTP_RETR); + } + break; + } + + return result; +} + +static CURLcode ftp_state_stor_resp(struct connectdata *conn, + int ftpcode, ftpstate instate) +{ + CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + + if(ftpcode>=400) { + failf(data, "Failed FTP upload: %0d", ftpcode); + state(conn, FTP_STOP); + /* oops, we never close the sockets! */ + return CURLE_UPLOAD_FAILED; + } + + conn->proto.ftpc.state_saved = instate; + + /* PORT means we are now awaiting the server to connect to us. */ + if(data->set.ftp_use_port) { + bool connected; + + state(conn, FTP_STOP); /* no longer in STOR state */ + + result = AllowServerConnect(conn, &connected); + if(result) + return result; + + if(!connected) { + struct ftp_conn *ftpc = &conn->proto.ftpc; + infof(data, "Data conn was not available immediately\n"); + ftpc->wait_data_conn = TRUE; + } + + return CURLE_OK; + } + else + return InitiateTransfer(conn); +} + +/* for LIST and RETR responses */ +static CURLcode ftp_state_get_resp(struct connectdata *conn, + int ftpcode, + ftpstate instate) +{ + CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + struct FTP *ftp = data->req.protop; + char *buf = data->state.buffer; + + if((ftpcode == 150) || (ftpcode == 125)) { + + /* + A; + 150 Opening BINARY mode data connection for /etc/passwd (2241 + bytes). (ok, the file is being transferred) + + B: + 150 Opening ASCII mode data connection for /bin/ls + + C: + 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes). + + D: + 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes) + + E: + 125 Data connection already open; Transfer starting. */ + + curl_off_t size=-1; /* default unknown size */ + + + /* + * It appears that there are FTP-servers that return size 0 for files when + * SIZE is used on the file while being in BINARY mode. To work around + * that (stupid) behavior, we attempt to parse the RETR response even if + * the SIZE returned size zero. + * + * Debugging help from Salvatore Sorrentino on February 26, 2003. + */ + + if((instate != FTP_LIST) && + !data->set.prefer_ascii && + (ftp->downloadsize < 1)) { + /* + * It seems directory listings either don't show the size or very + * often uses size 0 anyway. ASCII transfers may very well turn out + * that the transferred amount of data is not the same as this line + * tells, why using this number in those cases only confuses us. + * + * Example D above makes this parsing a little tricky */ + char *bytes; + bytes=strstr(buf, " bytes"); + if(bytes--) { + long in=(long)(bytes-buf); + /* this is a hint there is size information in there! ;-) */ + while(--in) { + /* scan for the left parenthesis and break there */ + if('(' == *bytes) + break; + /* skip only digits */ + if(!ISDIGIT(*bytes)) { + bytes=NULL; + break; + } + /* one more estep backwards */ + bytes--; + } + /* if we have nothing but digits: */ + if(bytes++) { + /* get the number! */ + size = curlx_strtoofft(bytes, NULL, 0); + } + } + } + else if(ftp->downloadsize > -1) + size = ftp->downloadsize; + + if(size > data->req.maxdownload && data->req.maxdownload > 0) + size = data->req.size = data->req.maxdownload; + else if((instate != FTP_LIST) && (data->set.prefer_ascii)) + size = -1; /* kludge for servers that understate ASCII mode file size */ + + infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n", + data->req.maxdownload); + + if(instate != FTP_LIST) + infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n", + size); + + /* FTP download: */ + conn->proto.ftpc.state_saved = instate; + conn->proto.ftpc.retr_size_saved = size; + + if(data->set.ftp_use_port) { + bool connected; + + result = AllowServerConnect(conn, &connected); + if(result) + return result; + + if(!connected) { + struct ftp_conn *ftpc = &conn->proto.ftpc; + infof(data, "Data conn was not available immediately\n"); + state(conn, FTP_STOP); + ftpc->wait_data_conn = TRUE; + } + } + else + return InitiateTransfer(conn); + } + else { + if((instate == FTP_LIST) && (ftpcode == 450)) { + /* simply no matching files in the dir listing */ + ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */ + state(conn, FTP_STOP); /* this phase is over */ + } + else { + failf(data, "RETR response: %03d", ftpcode); + return instate == FTP_RETR && ftpcode == 550? + CURLE_REMOTE_FILE_NOT_FOUND: + CURLE_FTP_COULDNT_RETR_FILE; + } + } + + return result; +} + +/* after USER, PASS and ACCT */ +static CURLcode ftp_state_loggedin(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + if(conn->ssl[FIRSTSOCKET].use) { + /* PBSZ = PROTECTION BUFFER SIZE. + + The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says: + + Specifically, the PROT command MUST be preceded by a PBSZ + command and a PBSZ command MUST be preceded by a successful + security data exchange (the TLS negotiation in this case) + + ... (and on page 8): + + Thus the PBSZ command must still be issued, but must have a + parameter of '0' to indicate that no buffering is taking place + and the data connection should not be encapsulated. + */ + PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0); + state(conn, FTP_PBSZ); + } + else { + result = ftp_state_pwd(conn); + } + return result; +} + +/* for USER and PASS responses */ +static CURLcode ftp_state_user_resp(struct connectdata *conn, + int ftpcode, + ftpstate instate) +{ + CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + struct FTP *ftp = data->req.protop; + struct ftp_conn *ftpc = &conn->proto.ftpc; + (void)instate; /* no use for this yet */ + + /* some need password anyway, and others just return 2xx ignored */ + if((ftpcode == 331) && (ftpc->state == FTP_USER)) { + /* 331 Password required for ... + (the server requires to send the user's password too) */ + PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:""); + state(conn, FTP_PASS); + } + else if(ftpcode/100 == 2) { + /* 230 User ... logged in. + (the user logged in with or without password) */ + result = ftp_state_loggedin(conn); + } + else if(ftpcode == 332) { + if(data->set.str[STRING_FTP_ACCOUNT]) { + PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]); + state(conn, FTP_ACCT); + } + else { + failf(data, "ACCT requested but none available"); + result = CURLE_LOGIN_DENIED; + } + } + else { + /* All other response codes, like: + + 530 User ... access denied + (the server denies to log the specified user) */ + + if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] && + !conn->data->state.ftp_trying_alternative) { + /* Ok, USER failed. Let's try the supplied command. */ + PPSENDF(&conn->proto.ftpc.pp, "%s", + conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); + conn->data->state.ftp_trying_alternative = TRUE; + state(conn, FTP_USER); + result = CURLE_OK; + } + else { + failf(data, "Access denied: %03d", ftpcode); + result = CURLE_LOGIN_DENIED; + } + } + return result; +} + +/* for ACCT response */ +static CURLcode ftp_state_acct_resp(struct connectdata *conn, + int ftpcode) +{ + CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + if(ftpcode != 230) { + failf(data, "ACCT rejected by server: %03d", ftpcode); + result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */ + } + else + result = ftp_state_loggedin(conn); + + return result; +} + + +static CURLcode ftp_statemach_act(struct connectdata *conn) +{ + CURLcode result; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct SessionHandle *data=conn->data; ++ struct Curl_easy *data=conn->data; + int ftpcode; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + static const char ftpauth[][4] = { "SSL", "TLS" }; + size_t nread = 0; + + if(pp->sendleft) + return Curl_pp_flushsend(pp); + + result = ftp_readresp(sock, pp, &ftpcode, &nread); + if(result) + return result; + + if(ftpcode) { + /* we have now received a full FTP server response */ + switch(ftpc->state) { + case FTP_WAIT220: + if(ftpcode == 230) + /* 230 User logged in - already! */ + return ftp_state_user_resp(conn, ftpcode, ftpc->state); + else if(ftpcode != 220) { + failf(data, "Got a %03d ftp-server response when 220 was expected", + ftpcode); + return CURLE_FTP_WEIRD_SERVER_REPLY; + } + + /* We have received a 220 response fine, now we proceed. */ +#ifdef HAVE_GSSAPI + if(data->set.krb) { + /* If not anonymous login, try a secure login. Note that this + procedure is still BLOCKING. */ + + Curl_sec_request_prot(conn, "private"); + /* We set private first as default, in case the line below fails to + set a valid level */ + Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); + + if(Curl_sec_login(conn)) + infof(data, "Logging in with password in cleartext!\n"); + else + infof(data, "Authentication successful\n"); + } +#endif + + if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { + /* We don't have a SSL/TLS connection yet, but FTPS is + requested. Try a FTPS connection now */ + + ftpc->count3=0; + switch(data->set.ftpsslauth) { + case CURLFTPAUTH_DEFAULT: + case CURLFTPAUTH_SSL: + ftpc->count2 = 1; /* add one to get next */ + ftpc->count1 = 0; + break; + case CURLFTPAUTH_TLS: + ftpc->count2 = -1; /* subtract one to get next */ + ftpc->count1 = 1; + break; + default: + failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d", + (int)data->set.ftpsslauth); + return CURLE_UNKNOWN_OPTION; /* we don't know what to do */ + } + PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]); + state(conn, FTP_AUTH); + } + else { + result = ftp_state_user(conn); + if(result) + return result; + } + + break; + + case FTP_AUTH: + /* we have gotten the response to a previous AUTH command */ + + /* RFC2228 (page 5) says: + * + * If the server is willing to accept the named security mechanism, + * and does not require any security data, it must respond with + * reply code 234/334. + */ + + if((ftpcode == 234) || (ftpcode == 334)) { + /* Curl_ssl_connect is BLOCKING */ + result = Curl_ssl_connect(conn, FIRSTSOCKET); + if(!result) { + conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */ + result = ftp_state_user(conn); + } + } + else if(ftpc->count3 < 1) { + ftpc->count3++; + ftpc->count1 += ftpc->count2; /* get next attempt */ + result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]); + /* remain in this same state */ + } + else { + if(data->set.use_ssl > CURLUSESSL_TRY) + /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */ + result = CURLE_USE_SSL_FAILED; + else + /* ignore the failure and continue */ + result = ftp_state_user(conn); + } + + if(result) + return result; + break; + + case FTP_USER: + case FTP_PASS: + result = ftp_state_user_resp(conn, ftpcode, ftpc->state); + break; + + case FTP_ACCT: + result = ftp_state_acct_resp(conn, ftpcode); + break; + + case FTP_PBSZ: + PPSENDF(&ftpc->pp, "PROT %c", + data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); + state(conn, FTP_PROT); + + break; + + case FTP_PROT: + if(ftpcode/100 == 2) + /* We have enabled SSL for the data connection! */ + conn->ssl[SECONDARYSOCKET].use = + (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE; + /* FTP servers typically responds with 500 if they decide to reject + our 'P' request */ + else if(data->set.use_ssl > CURLUSESSL_CONTROL) + /* we failed and bails out */ + return CURLE_USE_SSL_FAILED; + + if(data->set.ftp_ccc) { + /* CCC - Clear Command Channel + */ + PPSENDF(&ftpc->pp, "%s", "CCC"); + state(conn, FTP_CCC); + } + else { + result = ftp_state_pwd(conn); + if(result) + return result; + } + break; + + case FTP_CCC: + if(ftpcode < 500) { + /* First shut down the SSL layer (note: this call will block) */ + result = Curl_ssl_shutdown(conn, FIRSTSOCKET); + + if(result) { + failf(conn->data, "Failed to clear the command channel (CCC)"); + return result; + } + } + + /* Then continue as normal */ + result = ftp_state_pwd(conn); + if(result) + return result; + break; + + case FTP_PWD: + if(ftpcode == 257) { + char *ptr=&data->state.buffer[4]; /* start on the first letter */ + char *dir; + char *store; + + dir = malloc(nread + 1); + if(!dir) + return CURLE_OUT_OF_MEMORY; + + /* Reply format is like + 257[rubbish]"" and the + RFC959 says + + The directory name can contain any character; embedded + double-quotes should be escaped by double-quotes (the + "quote-doubling" convention). + */ + + /* scan for the first double-quote for non-standard responses */ + while(ptr < &data->state.buffer[sizeof(data->state.buffer)] + && *ptr != '\n' && *ptr != '\0' && *ptr != '"') + ptr++; + + if('\"' == *ptr) { + /* it started good */ + ptr++; + for(store = dir; *ptr;) { + if('\"' == *ptr) { + if('\"' == ptr[1]) { + /* "quote-doubling" */ + *store = ptr[1]; + ptr++; + } + else { + /* end of path */ + *store = '\0'; /* zero terminate */ + break; /* get out of this loop */ + } + } + else + *store = *ptr; + store++; + ptr++; + } + + /* If the path name does not look like an absolute path (i.e.: it + does not start with a '/'), we probably need some server-dependent + adjustments. For example, this is the case when connecting to + an OS400 FTP server: this server supports two name syntaxes, + the default one being incompatible with standard pathes. In + addition, this server switches automatically to the regular path + syntax when one is encountered in a command: this results in + having an entrypath in the wrong syntax when later used in CWD. + The method used here is to check the server OS: we do it only + if the path name looks strange to minimize overhead on other + systems. */ + + if(!ftpc->server_os && dir[0] != '/') { + + result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST"); + if(result) { + free(dir); + return result; + } + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'\n", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; + state(conn, FTP_SYST); + break; + } + + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'\n", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; + } + else { + /* couldn't get the path */ + free(dir); + infof(data, "Failed to figure out path\n"); + } + } + state(conn, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE\n")); + break; + + case FTP_SYST: + if(ftpcode == 215) { + char *ptr=&data->state.buffer[4]; /* start on the first letter */ + char *os; + char *store; + + os = malloc(nread + 1); + if(!os) + return CURLE_OUT_OF_MEMORY; + + /* Reply format is like + 215 + */ + while(*ptr == ' ') + ptr++; + for(store = os; *ptr && *ptr != ' ';) + *store++ = *ptr++; + *store = '\0'; /* zero terminate */ + + /* Check for special servers here. */ + + if(strequal(os, "OS/400")) { + /* Force OS400 name format 1. */ + result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1"); + if(result) { + free(os); + return result; + } + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; + state(conn, FTP_NAMEFMT); + break; + } + else { + /* Nothing special for the target server. */ + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; + } + } + else { + /* Cannot identify server OS. Continue anyway and cross fingers. */ + } + + state(conn, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE\n")); + break; + + case FTP_NAMEFMT: + if(ftpcode == 250) { + /* Name format change successful: reload initial path. */ + ftp_state_pwd(conn); + break; + } + + state(conn, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE\n")); + break; + + case FTP_QUOTE: + case FTP_POSTQUOTE: + case FTP_RETR_PREQUOTE: + case FTP_STOR_PREQUOTE: + if((ftpcode >= 400) && !ftpc->count2) { + /* failure response code, and not allowed to fail */ + failf(conn->data, "QUOT command failed with %03d", ftpcode); + return CURLE_QUOTE_ERROR; + } + result = ftp_state_quote(conn, FALSE, ftpc->state); + if(result) + return result; + + break; + + case FTP_CWD: + if(ftpcode/100 != 2) { + /* failure to CWD there */ + if(conn->data->set.ftp_create_missing_dirs && + ftpc->count1 && !ftpc->count2) { + /* try making it */ + ftpc->count2++; /* counter to prevent CWD-MKD loops */ + PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]); + state(conn, FTP_MKD); + } + else { + /* return failure */ + failf(data, "Server denied you to change to the given directory"); + ftpc->cwdfail = TRUE; /* don't remember this path as we failed + to enter it */ + return CURLE_REMOTE_ACCESS_DENIED; + } + } + else { + /* success */ + ftpc->count2=0; + if(++ftpc->count1 <= ftpc->dirdepth) { + /* send next CWD */ + PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]); + } + else { + result = ftp_state_mdtm(conn); + if(result) + return result; + } + } + break; + + case FTP_MKD: + if((ftpcode/100 != 2) && !ftpc->count3--) { + /* failure to MKD the dir */ + failf(data, "Failed to MKD dir: %03d", ftpcode); + return CURLE_REMOTE_ACCESS_DENIED; + } + state(conn, FTP_CWD); + /* send CWD */ + PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]); + break; + + case FTP_MDTM: + result = ftp_state_mdtm_resp(conn, ftpcode); + break; + + case FTP_TYPE: + case FTP_LIST_TYPE: + case FTP_RETR_TYPE: + case FTP_STOR_TYPE: + result = ftp_state_type_resp(conn, ftpcode, ftpc->state); + break; + + case FTP_SIZE: + case FTP_RETR_SIZE: + case FTP_STOR_SIZE: + result = ftp_state_size_resp(conn, ftpcode, ftpc->state); + break; + + case FTP_REST: + case FTP_RETR_REST: + result = ftp_state_rest_resp(conn, ftpcode, ftpc->state); + break; + + case FTP_PRET: + if(ftpcode != 200) { + /* there only is this one standard OK return code. */ + failf(data, "PRET command not accepted: %03d", ftpcode); + return CURLE_FTP_PRET_FAILED; + } + result = ftp_state_use_pasv(conn); + break; + + case FTP_PASV: + result = ftp_state_pasv_resp(conn, ftpcode); + break; + + case FTP_PORT: + result = ftp_state_port_resp(conn, ftpcode); + break; + + case FTP_LIST: + case FTP_RETR: + result = ftp_state_get_resp(conn, ftpcode, ftpc->state); + break; + + case FTP_STOR: + result = ftp_state_stor_resp(conn, ftpcode, ftpc->state); + break; + + case FTP_QUIT: + /* fallthrough, just stop! */ + default: + /* internal error */ + state(conn, FTP_STOP); + break; + } + } /* if(ftpcode) */ + + return result; +} + + +/* called repeatedly until done from multi.c */ +static CURLcode ftp_multi_statemach(struct connectdata *conn, + bool *done) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE); + + /* Check for the state outside of the Curl_socket_ready() return code checks + since at times we are in fact already in this state when this function + gets called. */ + *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE; + + return result; +} + +static CURLcode ftp_block_statemach(struct connectdata *conn) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + CURLcode result = CURLE_OK; + + while(ftpc->state != FTP_STOP) { + result = Curl_pp_statemach(pp, TRUE); + if(result) + break; + } + + return result; +} + +/* + * ftp_connect() should do everything that is to be considered a part of + * the connection phase. + * + * The variable 'done' points to will be TRUE if the protocol-layer connect + * phase is done when this function returns, or FALSE if not. + * + */ +static CURLcode ftp_connect(struct connectdata *conn, + bool *done) /* see description above */ +{ + CURLcode result; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + + *done = FALSE; /* default to not done yet */ + + /* We always support persistent connections on ftp */ + connkeep(conn, "FTP default"); + + pp->response_time = RESP_TIMEOUT; /* set default response time-out */ + pp->statemach_act = ftp_statemach_act; + pp->endofresp = ftp_endofresp; + pp->conn = conn; + + if(conn->handler->flags & PROTOPT_SSL) { + /* BLOCKING */ + result = Curl_ssl_connect(conn, FIRSTSOCKET); + if(result) + return result; + } + + Curl_pp_init(pp); /* init the generic pingpong data */ + + /* When we connect, we start in the state where we await the 220 + response */ + state(conn, FTP_WAIT220); + + result = ftp_multi_statemach(conn, done); + + return result; +} + +/*********************************************************************** + * + * ftp_done() + * + * The DONE function. This does what needs to be done after a single DO has + * performed. + * + * Input argument is already checked for validity. + */ +static CURLcode ftp_done(struct connectdata *conn, CURLcode status, - bool premature) ++ bool premature) +{ - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + struct FTP *ftp = data->req.protop; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + ssize_t nread; + int ftpcode; + CURLcode result = CURLE_OK; + bool was_ctl_valid = ftpc->ctl_valid; + char *path; + const char *path_to_use = data->state.path; + + if(!ftp) - /* When the easy handle is removed from the multi while libcurl is still - * trying to resolve the host name, it seems that the ftp struct is not - * yet initialized, but the removal action calls Curl_done() which calls - * this function. So we simply return success if no ftp pointer is set. - */ + return CURLE_OK; + + switch(status) { + case CURLE_BAD_DOWNLOAD_RESUME: + case CURLE_FTP_WEIRD_PASV_REPLY: + case CURLE_FTP_PORT_FAILED: + case CURLE_FTP_ACCEPT_FAILED: + case CURLE_FTP_ACCEPT_TIMEOUT: + case CURLE_FTP_COULDNT_SET_TYPE: + case CURLE_FTP_COULDNT_RETR_FILE: + case CURLE_PARTIAL_FILE: + case CURLE_UPLOAD_FAILED: + case CURLE_REMOTE_ACCESS_DENIED: + case CURLE_FILESIZE_EXCEEDED: + case CURLE_REMOTE_FILE_NOT_FOUND: + case CURLE_WRITE_ERROR: + /* the connection stays alive fine even though this happened */ + /* fall-through */ + case CURLE_OK: /* doesn't affect the control connection's status */ + if(!premature) { + ftpc->ctl_valid = was_ctl_valid; + break; + } + /* until we cope better with prematurely ended requests, let them + * fallback as if in complete failure */ + default: /* by default, an error means the control connection is + wedged and should not be used anymore */ + ftpc->ctl_valid = FALSE; + ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the + current path, as this connection is going */ + connclose(conn, "FTP ended with bad error code"); + result = status; /* use the already set error code */ + break; + } + + /* now store a copy of the directory we are in */ + free(ftpc->prevpath); + + if(data->set.wildcardmatch) { + if(data->set.chunk_end && ftpc->file) { + data->set.chunk_end(data->wildcard.customptr); + } + ftpc->known_filesize = -1; + } + + /* get the "raw" path */ + path = curl_easy_unescape(data, path_to_use, 0, NULL); + if(!path) { + /* out of memory, but we can limp along anyway (and should try to + * since we may already be in the out of memory cleanup path) */ + if(!result) + result = CURLE_OUT_OF_MEMORY; + ftpc->ctl_valid = FALSE; /* mark control connection as bad */ + connclose(conn, "FTP: out of memory!"); /* mark for connection closure */ + ftpc->prevpath = NULL; /* no path remembering */ + } + else { + size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */ + size_t dlen = strlen(path)-flen; + if(!ftpc->cwdfail) { + if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) { + ftpc->prevpath = path; + if(flen) + /* if 'path' is not the whole string */ + ftpc->prevpath[dlen]=0; /* terminate */ + } + else { + /* we never changed dir */ + ftpc->prevpath=strdup(""); + free(path); + } + if(ftpc->prevpath) + infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath); + } + else { + ftpc->prevpath = NULL; /* no path */ + free(path); + } + } + /* free the dir tree and file parts */ + freedirs(ftpc); + + /* shut down the socket to inform the server we're done */ + +#ifdef _WIN32_WCE + shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */ +#endif + + if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) { + if(!result && ftpc->dont_check && data->req.maxdownload > 0) { + /* partial download completed */ + result = Curl_pp_sendf(pp, "%s", "ABOR"); + if(result) { + failf(data, "Failure sending ABOR command: %s", + curl_easy_strerror(result)); + ftpc->ctl_valid = FALSE; /* mark control connection as bad */ + connclose(conn, "ABOR command failed"); /* connection closure */ + } + } + + if(conn->ssl[SECONDARYSOCKET].use) { + /* The secondary socket is using SSL so we must close down that part + first before we close the socket for real */ + Curl_ssl_close(conn, SECONDARYSOCKET); + + /* Note that we keep "use" set to TRUE since that (next) connection is + still requested to use SSL */ + } - if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) { - Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; - conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; - } ++ close_secondarysocket(conn); + } + + if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid && + pp->pending_resp && !premature) { + /* + * Let's see what the server says about the transfer we just performed, + * but lower the timeout as sometimes this connection has died while the + * data has been transferred. This happens when doing through NATs etc that + * abandon old silent connections. + */ + long old_time = pp->response_time; + + pp->response_time = 60*1000; /* give it only a minute for now */ + pp->response = Curl_tvnow(); /* timeout relative now */ + + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + + pp->response_time = old_time; /* set this back to previous value */ + + if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) { + failf(data, "control connection looks dead"); + ftpc->ctl_valid = FALSE; /* mark control connection as bad */ + connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */ + } + + if(result) + return result; + + if(ftpc->dont_check && data->req.maxdownload > 0) { + /* we have just sent ABOR and there is no reliable way to check if it was + * successful or not; we have to close the connection now */ + infof(data, "partial download completed, closing connection\n"); + connclose(conn, "Partial download with no ability to check"); + return result; + } + + if(!ftpc->dont_check) { + /* 226 Transfer complete, 250 Requested file action okay, completed. */ + if((ftpcode != 226) && (ftpcode != 250)) { + failf(data, "server did not report OK, got %d", ftpcode); + result = CURLE_PARTIAL_FILE; + } + } + } + + if(result || premature) + /* the response code from the transfer showed an error already so no + use checking further */ + ; + else if(data->set.upload) { + if((-1 != data->state.infilesize) && + (data->state.infilesize != *ftp->bytecountp) && + !data->set.crlf && + (ftp->transfer == FTPTRANSFER_BODY)) { + failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T + " out of %" CURL_FORMAT_CURL_OFF_T " bytes)", + *ftp->bytecountp, data->state.infilesize); + result = CURLE_PARTIAL_FILE; + } + } + else { + if((-1 != data->req.size) && + (data->req.size != *ftp->bytecountp) && +#ifdef CURL_DO_LINEEND_CONV + /* Most FTP servers don't adjust their file SIZE response for CRLFs, so + * we'll check to see if the discrepancy can be explained by the number + * of CRLFs we've changed to LFs. + */ + ((data->req.size + data->state.crlf_conversions) != + *ftp->bytecountp) && +#endif /* CURL_DO_LINEEND_CONV */ + (data->req.maxdownload != *ftp->bytecountp)) { + failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T + " bytes", *ftp->bytecountp); + result = CURLE_PARTIAL_FILE; + } + else if(!ftpc->dont_check && + !*ftp->bytecountp && + (data->req.size>0)) { + failf(data, "No data was received!"); + result = CURLE_FTP_COULDNT_RETR_FILE; + } + } + + /* clear these for next connection */ + ftp->transfer = FTPTRANSFER_BODY; + ftpc->dont_check = FALSE; + + /* Send any post-transfer QUOTE strings? */ + if(!status && !result && !premature && data->set.postquote) + result = ftp_sendquote(conn, data->set.postquote); + + return result; +} + +/*********************************************************************** + * + * ftp_sendquote() + * + * Where a 'quote' means a list of custom commands to send to the server. + * The quote list is passed as an argument. + * + * BLOCKING + */ + +static +CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote) +{ + struct curl_slist *item; + ssize_t nread; + int ftpcode; + CURLcode result; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + + item = quote; + while(item) { + if(item->data) { + char *cmd = item->data; + bool acceptfail = FALSE; + + /* if a command starts with an asterisk, which a legal FTP command never + can, the command will be allowed to fail without it causing any + aborts or cancels etc. It will cause libcurl to act as if the command + is successful, whatever the server reponds. */ + + if(cmd[0] == '*') { + cmd++; + acceptfail = TRUE; + } + + PPSENDF(&conn->proto.ftpc.pp, "%s", cmd); + + pp->response = Curl_tvnow(); /* timeout relative now */ + + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; + + if(!acceptfail && (ftpcode >= 400)) { + failf(conn->data, "QUOT string not accepted: %s", cmd); + return CURLE_QUOTE_ERROR; + } + } + + item = item->next; + } + + return CURLE_OK; +} + +/*********************************************************************** + * + * ftp_need_type() + * + * Returns TRUE if we in the current situation should send TYPE + */ +static int ftp_need_type(struct connectdata *conn, + bool ascii_wanted) +{ + return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I'); +} + +/*********************************************************************** + * + * ftp_nb_type() + * + * Set TYPE. We only deal with ASCII or BINARY so this function + * sets one of them. + * If the transfer type is not sent, simulate on OK response in newstate + */ +static CURLcode ftp_nb_type(struct connectdata *conn, + bool ascii, ftpstate newstate) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + CURLcode result; + char want = (char)(ascii?'A':'I'); + + if(ftpc->transfertype == want) { + state(conn, newstate); + return ftp_state_type_resp(conn, 200, newstate); + } + + PPSENDF(&ftpc->pp, "TYPE %c", want); + state(conn, newstate); + + /* keep track of our current transfer type */ + ftpc->transfertype = want; + return CURLE_OK; +} + +/*************************************************************************** + * + * ftp_pasv_verbose() + * + * This function only outputs some informationals about this second connection + * when we've issued a PASV command before and thus we have connected to a + * possibly new IP address. + * + */ +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static void +ftp_pasv_verbose(struct connectdata *conn, + Curl_addrinfo *ai, + char *newhost, /* ascii version */ + int port) +{ + char buf[256]; + Curl_printable_address(ai, buf, sizeof(buf)); + infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port); +} +#endif + +/* + Check if this is a range download, and if so, set the internal variables + properly. + */ + +static CURLcode ftp_range(struct connectdata *conn) +{ + curl_off_t from, to; + char *ptr; + char *ptr2; - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(data->state.use_range && data->state.range) { + from=curlx_strtoofft(data->state.range, &ptr, 0); + while(*ptr && (ISSPACE(*ptr) || (*ptr=='-'))) + ptr++; + to=curlx_strtoofft(ptr, &ptr2, 0); + if(ptr == ptr2) { + /* we didn't get any digit */ + to=-1; + } + if((-1 == to) && (from>=0)) { + /* X - */ + data->state.resume_from = from; + DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T + " to end of file\n", from)); + } + else if(from < 0) { + /* -Y */ + data->req.maxdownload = -from; + data->state.resume_from = from; + DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T + " bytes\n", -from)); + } + else { + /* X-Y */ + data->req.maxdownload = (to-from)+1; /* include last byte */ + data->state.resume_from = from; + DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T + " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n", + from, data->req.maxdownload)); + } + DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T + " to %" CURL_FORMAT_CURL_OFF_T ", totally %" + CURL_FORMAT_CURL_OFF_T " bytes\n", + from, to, data->req.maxdownload)); + ftpc->dont_check = TRUE; /* dont check for successful transfer */ + } + else + data->req.maxdownload = -1; + return CURLE_OK; +} + + +/* + * ftp_do_more() + * + * This function shall be called when the second FTP (data) connection is + * connected. + * + * 'complete' can return 0 for incomplete, 1 for done and -1 for go back + * (which basically is only for when PASV is being sent to retry a failed + * EPSV). + */ + +static CURLcode ftp_do_more(struct connectdata *conn, int *completep) +{ - struct SessionHandle *data=conn->data; ++ struct Curl_easy *data=conn->data; + struct ftp_conn *ftpc = &conn->proto.ftpc; + CURLcode result = CURLE_OK; + bool connected = FALSE; + bool complete = FALSE; + + /* the ftp struct is inited in ftp_connect() */ + struct FTP *ftp = data->req.protop; + + /* if the second connection isn't done yet, wait for it */ + if(!conn->bits.tcpconnect[SECONDARYSOCKET]) { + if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) { + /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port + aren't used so we blank their arguments. TODO: make this nicer */ + result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0, FALSE); + + return result; + } + + result = Curl_is_connected(conn, SECONDARYSOCKET, &connected); + + /* Ready to do more? */ + if(connected) { + DEBUGF(infof(data, "DO-MORE connected phase starts\n")); + if(conn->bits.proxy) { + infof(data, "Connection to proxy confirmed\n"); + result = proxy_magic(conn, ftpc->newhost, ftpc->newport, &connected); + } + } + else { + if(result && (ftpc->count1 == 0)) { + *completep = -1; /* go back to DOING please */ + /* this is a EPSV connect failing, try PASV instead */ + return ftp_epsv_disable(conn); + } + return result; + } + } + + if(ftpc->state) { + /* already in a state so skip the initial commands. + They are only done to kickstart the do_more state */ + result = ftp_multi_statemach(conn, &complete); + + *completep = (int)complete; + + /* if we got an error or if we don't wait for a data connection return + immediately */ + if(result || (ftpc->wait_data_conn != TRUE)) + return result; + + if(ftpc->wait_data_conn) + /* if we reach the end of the FTP state machine here, *complete will be + TRUE but so is ftpc->wait_data_conn, which says we need to wait for + the data connection and therefore we're not actually complete */ + *completep = 0; + } + + if(ftp->transfer <= FTPTRANSFER_INFO) { + /* a transfer is about to take place, or if not a file name was given + so we'll do a SIZE on it later and then we need the right TYPE first */ + + if(ftpc->wait_data_conn == TRUE) { + bool serv_conned; + + result = ReceivedServerConnect(conn, &serv_conned); + if(result) + return result; /* Failed to accept data connection */ + + if(serv_conned) { + /* It looks data connection is established */ + result = AcceptServerConnect(conn); + ftpc->wait_data_conn = FALSE; + if(!result) + result = InitiateTransfer(conn); + + if(result) + return result; + + *completep = 1; /* this state is now complete when the server has + connected back to us */ + } + } + else if(data->set.upload) { + result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE); + if(result) + return result; + + result = ftp_multi_statemach(conn, &complete); - *completep = (int)complete; ++ if(ftpc->wait_data_conn) ++ /* if we reach the end of the FTP state machine here, *complete will be ++ TRUE but so is ftpc->wait_data_conn, which says we need to wait for ++ the data connection and therefore we're not actually complete */ ++ *completep = 0; ++ else ++ *completep = (int)complete; + } + else { + /* download */ + ftp->downloadsize = -1; /* unknown as of yet */ + + result = ftp_range(conn); + if(result) + ; + else if(data->set.ftp_list_only || !ftpc->file) { + /* The specified path ends with a slash, and therefore we think this + is a directory that is requested, use LIST. But before that we + need to set ASCII transfer mode. */ + + /* But only if a body transfer was requested. */ + if(ftp->transfer == FTPTRANSFER_BODY) { + result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE); + if(result) + return result; + } + /* otherwise just fall through */ + } + else { + result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE); + if(result) + return result; + } + + result = ftp_multi_statemach(conn, &complete); + *completep = (int)complete; + } + return result; + } + + if(!result && (ftp->transfer != FTPTRANSFER_BODY)) + /* no data to transfer. FIX: it feels like a kludge to have this here + too! */ + Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + + if(!ftpc->wait_data_conn) { + /* no waiting for the data connection so this is now complete */ + *completep = 1; + DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result)); + } + + return result; +} + + + +/*********************************************************************** + * + * ftp_perform() + * + * This is the actual DO function for FTP. Get a file/directory according to + * the options previously setup. + */ + +static +CURLcode ftp_perform(struct connectdata *conn, + bool *connected, /* connect status after PASV / PORT */ + bool *dophase_done) +{ + /* this is FTP and no proxy */ + CURLcode result=CURLE_OK; + + DEBUGF(infof(conn->data, "DO phase starts\n")); + + if(conn->data->set.opt_no_body) { + /* requested no body means no transfer... */ + struct FTP *ftp = conn->data->req.protop; + ftp->transfer = FTPTRANSFER_INFO; + } + + *dophase_done = FALSE; /* not done yet */ + + /* start the first command in the DO phase */ + result = ftp_state_quote(conn, TRUE, FTP_QUOTE); + if(result) + return result; + + /* run the state-machine */ + result = ftp_multi_statemach(conn, dophase_done); + + *connected = conn->bits.tcpconnect[SECONDARYSOCKET]; + + infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected); + + if(*dophase_done) { + DEBUGF(infof(conn->data, "DO phase is complete1\n")); + } + + return result; +} + +static void wc_data_dtor(void *ptr) +{ + struct ftp_wc_tmpdata *tmp = ptr; + if(tmp) + Curl_ftp_parselist_data_free(&tmp->parser); + free(tmp); +} + +static CURLcode init_wc_data(struct connectdata *conn) +{ + char *last_slash; + char *path = conn->data->state.path; + struct WildcardData *wildcard = &(conn->data->wildcard); + CURLcode result = CURLE_OK; + struct ftp_wc_tmpdata *ftp_tmp; + + last_slash = strrchr(conn->data->state.path, '/'); + if(last_slash) { + last_slash++; + if(last_slash[0] == '\0') { + wildcard->state = CURLWC_CLEAN; + result = ftp_parse_url_path(conn); + return result; + } + else { + wildcard->pattern = strdup(last_slash); + if(!wildcard->pattern) + return CURLE_OUT_OF_MEMORY; + last_slash[0] = '\0'; /* cut file from path */ + } + } + else { /* there is only 'wildcard pattern' or nothing */ + if(path[0]) { + wildcard->pattern = strdup(path); + if(!wildcard->pattern) + return CURLE_OUT_OF_MEMORY; + path[0] = '\0'; + } + else { /* only list */ + wildcard->state = CURLWC_CLEAN; + result = ftp_parse_url_path(conn); + return result; + } + } + + /* program continues only if URL is not ending with slash, allocate needed + resources for wildcard transfer */ + + /* allocate ftp protocol specific temporary wildcard data */ + ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata)); + if(!ftp_tmp) { + Curl_safefree(wildcard->pattern); + return CURLE_OUT_OF_MEMORY; + } + + /* INITIALIZE parselist structure */ + ftp_tmp->parser = Curl_ftp_parselist_data_alloc(); + if(!ftp_tmp->parser) { + Curl_safefree(wildcard->pattern); + free(ftp_tmp); + return CURLE_OUT_OF_MEMORY; + } + + wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */ + wildcard->tmp_dtor = wc_data_dtor; + + /* wildcard does not support NOCWD option (assert it?) */ + if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD) + conn->data->set.ftp_filemethod = FTPFILE_MULTICWD; + + /* try to parse ftp url */ + result = ftp_parse_url_path(conn); + if(result) { + Curl_safefree(wildcard->pattern); + wildcard->tmp_dtor(wildcard->tmp); + wildcard->tmp_dtor = ZERO_NULL; + wildcard->tmp = NULL; + return result; + } + + wildcard->path = strdup(conn->data->state.path); + if(!wildcard->path) { + Curl_safefree(wildcard->pattern); + wildcard->tmp_dtor(wildcard->tmp); + wildcard->tmp_dtor = ZERO_NULL; + wildcard->tmp = NULL; + return CURLE_OUT_OF_MEMORY; + } + + /* backup old write_function */ + ftp_tmp->backup.write_function = conn->data->set.fwrite_func; + /* parsing write function */ + conn->data->set.fwrite_func = Curl_ftp_parselist; + /* backup old file descriptor */ + ftp_tmp->backup.file_descriptor = conn->data->set.out; + /* let the writefunc callback know what curl pointer is working with */ + conn->data->set.out = conn; + + infof(conn->data, "Wildcard - Parsing started\n"); + return CURLE_OK; +} + +/* This is called recursively */ +static CURLcode wc_statemach(struct connectdata *conn) +{ + struct WildcardData * const wildcard = &(conn->data->wildcard); + CURLcode result = CURLE_OK; + + switch (wildcard->state) { + case CURLWC_INIT: + result = init_wc_data(conn); + if(wildcard->state == CURLWC_CLEAN) + /* only listing! */ + break; + else + wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING; + break; + + case CURLWC_MATCHING: { + /* In this state is LIST response successfully parsed, so lets restore + previous WRITEFUNCTION callback and WRITEDATA pointer */ + struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp; + conn->data->set.fwrite_func = ftp_tmp->backup.write_function; + conn->data->set.out = ftp_tmp->backup.file_descriptor; + ftp_tmp->backup.write_function = ZERO_NULL; + ftp_tmp->backup.file_descriptor = NULL; + wildcard->state = CURLWC_DOWNLOADING; + + if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) { + /* error found in LIST parsing */ + wildcard->state = CURLWC_CLEAN; + return wc_statemach(conn); + } + else if(wildcard->filelist->size == 0) { + /* no corresponding file */ + wildcard->state = CURLWC_CLEAN; + return CURLE_REMOTE_FILE_NOT_FOUND; + } + return wc_statemach(conn); + } + + case CURLWC_DOWNLOADING: { + /* filelist has at least one file, lets get first one */ + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct curl_fileinfo *finfo = wildcard->filelist->head->ptr; + + char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); + if(!tmp_path) + return CURLE_OUT_OF_MEMORY; + + /* switch default "state.pathbuffer" and tmp_path, good to see + ftp_parse_url_path function to understand this trick */ + Curl_safefree(conn->data->state.pathbuffer); + conn->data->state.pathbuffer = tmp_path; + conn->data->state.path = tmp_path; + + infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename); + if(conn->data->set.chunk_bgn) { + long userresponse = conn->data->set.chunk_bgn( + finfo, wildcard->customptr, (int)wildcard->filelist->size); + switch(userresponse) { + case CURL_CHUNK_BGN_FUNC_SKIP: + infof(conn->data, "Wildcard - \"%s\" skipped by user\n", + finfo->filename); + wildcard->state = CURLWC_SKIP; + return wc_statemach(conn); + case CURL_CHUNK_BGN_FUNC_FAIL: + return CURLE_CHUNK_FAILED; + } + } + + if(finfo->filetype != CURLFILETYPE_FILE) { + wildcard->state = CURLWC_SKIP; + return wc_statemach(conn); + } + + if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE) + ftpc->known_filesize = finfo->size; + + result = ftp_parse_url_path(conn); + if(result) + return result; + + /* we don't need the Curl_fileinfo of first file anymore */ + Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL); + + if(wildcard->filelist->size == 0) { /* remains only one file to down. */ + wildcard->state = CURLWC_CLEAN; + /* after that will be ftp_do called once again and no transfer + will be done because of CURLWC_CLEAN state */ + return CURLE_OK; + } + } break; + + case CURLWC_SKIP: { + if(conn->data->set.chunk_end) + conn->data->set.chunk_end(conn->data->wildcard.customptr); + Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL); + wildcard->state = (wildcard->filelist->size == 0) ? + CURLWC_CLEAN : CURLWC_DOWNLOADING; + return wc_statemach(conn); + } + + case CURLWC_CLEAN: { + struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp; + result = CURLE_OK; + if(ftp_tmp) + result = Curl_ftp_parselist_geterror(ftp_tmp->parser); + + wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE; + } break; + + case CURLWC_DONE: + case CURLWC_ERROR: + break; + } + + return result; +} + +/*********************************************************************** + * + * ftp_do() + * + * This function is registered as 'curl_do' function. It decodes the path + * parts etc as a wrapper to the actual DO function (ftp_perform). + * + * The input argument is already checked for validity. + */ +static CURLcode ftp_do(struct connectdata *conn, bool *done) +{ + CURLcode result = CURLE_OK; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + *done = FALSE; /* default to false */ + ftpc->wait_data_conn = FALSE; /* default to no such wait */ + + if(conn->data->set.wildcardmatch) { + result = wc_statemach(conn); + if(conn->data->wildcard.state == CURLWC_SKIP || + conn->data->wildcard.state == CURLWC_DONE) { + /* do not call ftp_regular_transfer */ + return CURLE_OK; + } + if(result) /* error, loop or skipping the file */ + return result; + } + else { /* no wildcard FSM needed */ + result = ftp_parse_url_path(conn); + if(result) + return result; + } + + result = ftp_regular_transfer(conn, done); + + return result; +} + + +CURLcode Curl_ftpsendf(struct connectdata *conn, + const char *fmt, ...) +{ + ssize_t bytes_written; +#define SBUF_SIZE 1024 + char s[SBUF_SIZE]; + size_t write_len; + char *sptr=s; + CURLcode result = CURLE_OK; +#ifdef HAVE_GSSAPI + enum protection_level data_sec = conn->data_prot; +#endif + + va_list ap; + va_start(ap, fmt); + write_len = vsnprintf(s, SBUF_SIZE-3, fmt, ap); + va_end(ap); + + strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */ + write_len +=2; + + bytes_written=0; + + result = Curl_convert_to_network(conn->data, s, write_len); + /* Curl_convert_to_network calls failf if unsuccessful */ + if(result) + return result; + + for(;;) { +#ifdef HAVE_GSSAPI + conn->data_prot = PROT_CMD; +#endif + result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, + &bytes_written); +#ifdef HAVE_GSSAPI + DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); + conn->data_prot = data_sec; +#endif + + if(result) + break; + + if(conn->data->set.verbose) + Curl_debug(conn->data, CURLINFO_HEADER_OUT, + sptr, (size_t)bytes_written, conn); + + if(bytes_written != (ssize_t)write_len) { + write_len -= bytes_written; + sptr += bytes_written; + } + else + break; + } + + return result; +} + +/*********************************************************************** + * + * ftp_quit() + * + * This should be called before calling sclose() on an ftp control connection + * (not data connections). We should then wait for the response from the + * server before returning. The calling code should then try to close the + * connection. + * + */ +static CURLcode ftp_quit(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + if(conn->proto.ftpc.ctl_valid) { + result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT"); + if(result) { + failf(conn->data, "Failure sending QUIT command: %s", + curl_easy_strerror(result)); + conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */ + connclose(conn, "QUIT command failed"); /* mark for connection closure */ + state(conn, FTP_STOP); + return result; + } + + state(conn, FTP_QUIT); + + result = ftp_block_statemach(conn); + } + + return result; +} + +/*********************************************************************** + * + * ftp_disconnect() + * + * Disconnect from an FTP server. Cleanup protocol-specific per-connection + * resources. BLOCKING. + */ +static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection) +{ + struct ftp_conn *ftpc= &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + + /* We cannot send quit unconditionally. If this connection is stale or + bad in any way, sending quit and waiting around here will make the + disconnect wait in vain and cause more problems than we need to. + + ftp_quit() will check the state of ftp->ctl_valid. If it's ok it + will try to send the QUIT command, otherwise it will just return. + */ + if(dead_connection) + ftpc->ctl_valid = FALSE; + + /* The FTP session may or may not have been allocated/setup at this point! */ + (void)ftp_quit(conn); /* ignore errors on the QUIT */ + + if(ftpc->entrypath) { - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) { + data->state.most_recent_ftp_entrypath = NULL; + } + free(ftpc->entrypath); + ftpc->entrypath = NULL; + } + + freedirs(ftpc); + free(ftpc->prevpath); + ftpc->prevpath = NULL; + free(ftpc->server_os); + ftpc->server_os = NULL; + + Curl_pp_disconnect(pp); + +#ifdef HAVE_GSSAPI + Curl_sec_end(conn); +#endif + + return CURLE_OK; +} + +/*********************************************************************** + * + * ftp_parse_url_path() + * + * Parse the URL path into separate path components. + * + */ +static +CURLcode ftp_parse_url_path(struct connectdata *conn) +{ - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + /* the ftp struct is already inited in ftp_connect() */ + struct FTP *ftp = data->req.protop; + struct ftp_conn *ftpc = &conn->proto.ftpc; + const char *slash_pos; /* position of the first '/' char in curpos */ + const char *path_to_use = data->state.path; + const char *cur_pos; + const char *filename = NULL; + + cur_pos = path_to_use; /* current position in path. point at the begin + of next path component */ + + ftpc->ctl_valid = FALSE; + ftpc->cwdfail = FALSE; + + switch(data->set.ftp_filemethod) { + case FTPFILE_NOCWD: + /* fastest, but less standard-compliant */ + + /* + The best time to check whether the path is a file or directory is right + here. so: + + the first condition in the if() right here, is there just in case + someone decides to set path to NULL one day + */ - if(data->state.path && - data->state.path[0] && - (data->state.path[strlen(data->state.path) - 1] != '/') ) - filename = data->state.path; /* this is a full file path */ - /* ++ if(path_to_use[0] && ++ (path_to_use[strlen(path_to_use) - 1] != '/') ) ++ filename = path_to_use; /* this is a full file path */ ++ /* ++ else { + ftpc->file is not used anywhere other than for operations on a file. + In other words, never for directory operations. + So we can safely leave filename as NULL here and use it as a + argument in dir/file decisions. - */ ++ } ++ */ + break; + + case FTPFILE_SINGLECWD: + /* get the last slash */ + if(!path_to_use[0]) { + /* no dir, no file */ + ftpc->dirdepth = 0; + break; + } + slash_pos=strrchr(cur_pos, '/'); + if(slash_pos || !*cur_pos) { + size_t dirlen = slash_pos-cur_pos; + + ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0])); + if(!ftpc->dirs) + return CURLE_OUT_OF_MEMORY; + + if(!dirlen) + dirlen++; + + ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/", + slash_pos ? curlx_uztosi(dirlen) : 1, + NULL); + if(!ftpc->dirs[0]) { + freedirs(ftpc); + return CURLE_OUT_OF_MEMORY; + } + ftpc->dirdepth = 1; /* we consider it to be a single dir */ + filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */ + } + else + filename = cur_pos; /* this is a file name only */ + break; + + default: /* allow pretty much anything */ + case FTPFILE_MULTICWD: + ftpc->dirdepth = 0; + ftpc->diralloc = 5; /* default dir depth to allocate */ + ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0])); + if(!ftpc->dirs) + return CURLE_OUT_OF_MEMORY; + + /* we have a special case for listing the root dir only */ + if(strequal(path_to_use, "/")) { + cur_pos++; /* make it point to the zero byte */ + ftpc->dirs[0] = strdup("/"); + ftpc->dirdepth++; + } + else { + /* parse the URL path into separate path components */ + while((slash_pos = strchr(cur_pos, '/')) != NULL) { + /* 1 or 0 pointer offset to indicate absolute directory */ + ssize_t absolute_dir = ((cur_pos - data->state.path > 0) && + (ftpc->dirdepth == 0))?1:0; + + /* seek out the next path component */ + if(slash_pos-cur_pos) { + /* we skip empty path components, like "x//y" since the FTP command + CWD requires a parameter and a non-existent parameter a) doesn't + work on many servers and b) has no effect on the others. */ + int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir); + ftpc->dirs[ftpc->dirdepth] = + curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL); + if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */ + failf(data, "no memory"); + freedirs(ftpc); + return CURLE_OUT_OF_MEMORY; + } + if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) { + free(ftpc->dirs[ftpc->dirdepth]); + freedirs(ftpc); + return CURLE_URL_MALFORMAT; + } + } + else { + cur_pos = slash_pos + 1; /* jump to the rest of the string */ + if(!ftpc->dirdepth) { + /* path starts with a slash, add that as a directory */ + ftpc->dirs[ftpc->dirdepth] = strdup("/"); + if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */ + failf(data, "no memory"); + freedirs(ftpc); + return CURLE_OUT_OF_MEMORY; + } + } + continue; + } + + cur_pos = slash_pos + 1; /* jump to the rest of the string */ + if(++ftpc->dirdepth >= ftpc->diralloc) { + /* enlarge array */ + char **bigger; + ftpc->diralloc *= 2; /* double the size each time */ + bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0])); + if(!bigger) { + freedirs(ftpc); + return CURLE_OUT_OF_MEMORY; + } + ftpc->dirs = bigger; + } + } + } + filename = cur_pos; /* the rest is the file name */ + break; + } /* switch */ + + if(filename && *filename) { + ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL); + if(NULL == ftpc->file) { + freedirs(ftpc); + failf(data, "no memory"); + return CURLE_OUT_OF_MEMORY; + } + if(isBadFtpString(ftpc->file)) { + freedirs(ftpc); + return CURLE_URL_MALFORMAT; + } + } + else + ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL + pointer */ + + if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) { + /* We need a file name when uploading. Return error! */ + failf(data, "Uploading to a URL without a file name!"); + return CURLE_URL_MALFORMAT; + } + + ftpc->cwddone = FALSE; /* default to not done */ + + if(ftpc->prevpath) { + /* prevpath is "raw" so we convert the input path before we compare the + strings */ + int dlen; + char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen); + if(!path) { + freedirs(ftpc); + return CURLE_OUT_OF_MEMORY; + } + + dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0; + if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) && + strnequal(path, ftpc->prevpath, dlen)) { + infof(data, "Request has same path as previous transfer\n"); + ftpc->cwddone = TRUE; + } + free(path); + } + + return CURLE_OK; +} + +/* call this when the DO phase has completed */ +static CURLcode ftp_dophase_done(struct connectdata *conn, + bool connected) +{ + struct FTP *ftp = conn->data->req.protop; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(connected) { + int completed; + CURLcode result = ftp_do_more(conn, &completed); + + if(result) { - if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) { - /* close the second socket if it was created already */ - Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; - } ++ close_secondarysocket(conn); + return result; + } + } + + if(ftp->transfer != FTPTRANSFER_BODY) + /* no data to transfer */ + Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + else if(!connected) + /* since we didn't connect now, we want do_more to get called */ + conn->bits.do_more = TRUE; + + ftpc->ctl_valid = TRUE; /* seems good */ + + return CURLE_OK; +} + +/* called from multi.c while DOing */ +static CURLcode ftp_doing(struct connectdata *conn, + bool *dophase_done) +{ + CURLcode result = ftp_multi_statemach(conn, dophase_done); + + if(result) + DEBUGF(infof(conn->data, "DO phase failed\n")); + else if(*dophase_done) { + result = ftp_dophase_done(conn, FALSE /* not connected */); + + DEBUGF(infof(conn->data, "DO phase is complete2\n")); + } + return result; +} + +/*********************************************************************** + * + * ftp_regular_transfer() + * + * The input argument is already checked for validity. + * + * Performs all commands done before a regular transfer between a local and a + * remote host. + * + * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the + * ftp_done() function without finding any major problem. + */ +static +CURLcode ftp_regular_transfer(struct connectdata *conn, + bool *dophase_done) +{ + CURLcode result=CURLE_OK; + bool connected=FALSE; - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + struct ftp_conn *ftpc = &conn->proto.ftpc; + data->req.size = -1; /* make sure this is unknown at this point */ + + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + Curl_pgrsSetUploadSize(data, -1); + Curl_pgrsSetDownloadSize(data, -1); + + ftpc->ctl_valid = TRUE; /* starts good */ + + result = ftp_perform(conn, + &connected, /* have we connected after PASV/PORT */ + dophase_done); /* all commands in the DO-phase done? */ + + if(!result) { + + if(!*dophase_done) + /* the DO phase has not completed yet */ + return CURLE_OK; + + result = ftp_dophase_done(conn, connected); + + if(result) + return result; + } + else + freedirs(ftpc); + + return result; +} + +static CURLcode ftp_setup_connection(struct connectdata *conn) +{ - struct SessionHandle *data = conn->data; ++ struct Curl_easy *data = conn->data; + char *type; + char command; + struct FTP *ftp; + + if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { + /* Unless we have asked to tunnel ftp operations through the proxy, we + switch and use HTTP operations only */ +#ifndef CURL_DISABLE_HTTP + if(conn->handler == &Curl_handler_ftp) + conn->handler = &Curl_handler_ftp_proxy; + else { +#ifdef USE_SSL + conn->handler = &Curl_handler_ftps_proxy; +#else + failf(data, "FTPS not supported!"); + return CURLE_UNSUPPORTED_PROTOCOL; +#endif + } + /* set it up as a HTTP connection instead */ + return conn->handler->setup_connection(conn); +#else + failf(data, "FTP over http proxy requires HTTP support built-in!"); + return CURLE_UNSUPPORTED_PROTOCOL; +#endif + } + + conn->data->req.protop = ftp = malloc(sizeof(struct FTP)); + if(NULL == ftp) + return CURLE_OUT_OF_MEMORY; + + data->state.path++; /* don't include the initial slash */ + data->state.slash_removed = TRUE; /* we've skipped the slash */ + + /* FTP URLs support an extension like ";type=" that + * we'll try to get now! */ + type = strstr(data->state.path, ";type="); + + if(!type) + type = strstr(conn->host.rawalloc, ";type="); + + if(type) { + *type = 0; /* it was in the middle of the hostname */ + command = Curl_raw_toupper(type[6]); + conn->bits.type_set = TRUE; + + switch (command) { + case 'A': /* ASCII mode */ + data->set.prefer_ascii = TRUE; + break; + + case 'D': /* directory mode */ + data->set.ftp_list_only = TRUE; + break; + + case 'I': /* binary mode */ + default: + /* switch off ASCII */ + data->set.prefer_ascii = FALSE; + break; + } + } + + /* get some initial data into the ftp struct */ + ftp->bytecountp = &conn->data->req.bytecount; + ftp->transfer = FTPTRANSFER_BODY; + ftp->downloadsize = 0; + + /* No need to duplicate user+password, the connectdata struct won't change + during a session, but we re-init them here since on subsequent inits + since the conn struct may have changed or been replaced. + */ + ftp->user = conn->user; + ftp->passwd = conn->passwd; + if(isBadFtpString(ftp->user)) + return CURLE_URL_MALFORMAT; + if(isBadFtpString(ftp->passwd)) + return CURLE_URL_MALFORMAT; + + conn->proto.ftpc.known_filesize = -1; /* unknown size for now */ + + return CURLE_OK; +} + +#endif /* CURL_DISABLE_FTP */ diff --cc Utilities/cmcurl/lib/mprintf.c index 7412dc3,0000000..380c3d6 mode 100644,000000..100644 --- a/Utilities/cmcurl/lib/mprintf.c +++ b/Utilities/cmcurl/lib/mprintf.c @@@ -1,1138 -1,0 +1,1156 @@@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * - * Copyright (C) 1999 - 2014, Daniel Stenberg, , et al. ++ * Copyright (C) 1999 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. ++ * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * + * Purpose: + * A merge of Bjorn Reese's format() function and Daniel's dsprintf() + * 1.0. A full blooded printf() clone with full support for $ + * everywhere (parameters, widths and precisions) including variabled + * sized parameters (like doubles, long longs, long doubles and even + * void * in 64-bit architectures). + * + * Current restrictions: + * - Max 128 parameters + * - No 'long double' support. + * + * If you ever want truly portable and good *printf() clones, the project that + * took on from here is named 'Trio' and you find more details on the trio web - * page at http://daniel.haxx.se/trio/ ++ * page at https://daniel.haxx.se/projects/trio/ + */ + +#include "curl_setup.h" - - #if defined(DJGPP) && (DJGPP_MINOR < 4) - #undef _MPRINTF_REPLACE /* don't use x_was_used() here */ - #endif - +#include + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* + * If SIZEOF_SIZE_T has not been defined, default to the size of long. + */ + +#ifndef SIZEOF_SIZE_T +# define SIZEOF_SIZE_T CURL_SIZEOF_LONG +#endif + +#ifdef HAVE_LONGLONG +# define LONG_LONG_TYPE long long +# define HAVE_LONG_LONG_TYPE +#else +# if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) +# define LONG_LONG_TYPE __int64 +# define HAVE_LONG_LONG_TYPE +# else +# undef LONG_LONG_TYPE +# undef HAVE_LONG_LONG_TYPE +# endif +#endif + +/* + * Non-ANSI integer extensions + */ + +#if (defined(__BORLANDC__) && (__BORLANDC__ >= 0x520)) || \ + (defined(__WATCOMC__) && defined(__386__)) || \ + (defined(__POCC__) && defined(_MSC_VER)) || \ + (defined(_WIN32_WCE)) || \ + (defined(__MINGW32__)) || \ + (defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)) +# define MP_HAVE_INT_EXTENSIONS +#endif + +/* + * Max integer data types that mprintf.c is capable + */ + +#ifdef HAVE_LONG_LONG_TYPE +# define mp_intmax_t LONG_LONG_TYPE +# define mp_uintmax_t unsigned LONG_LONG_TYPE +#else +# define mp_intmax_t long +# define mp_uintmax_t unsigned long +#endif + +#define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */ +#define MAX_PARAMETERS 128 /* lame static limit */ + +#ifdef __AMIGA__ +# undef FORMAT_INT +#endif + +/* Lower-case digits. */ +static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + +/* Upper-case digits. */ +static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +#define OUTCHAR(x) \ + do{ \ + if(stream((unsigned char)(x), (FILE *)data) != -1) \ + done++; \ + else \ + return done; /* return immediately on failure */ \ + } WHILE_FALSE + +/* Data type to read from the arglist */ +typedef enum { + FORMAT_UNKNOWN = 0, + FORMAT_STRING, + FORMAT_PTR, + FORMAT_INT, + FORMAT_INTPTR, + FORMAT_LONG, + FORMAT_LONGLONG, + FORMAT_DOUBLE, + FORMAT_LONGDOUBLE, + FORMAT_WIDTH /* For internal use */ +} FormatType; + +/* conversion and display flags */ +enum { + FLAGS_NEW = 0, + FLAGS_SPACE = 1<<0, + FLAGS_SHOWSIGN = 1<<1, + FLAGS_LEFT = 1<<2, + FLAGS_ALT = 1<<3, + FLAGS_SHORT = 1<<4, + FLAGS_LONG = 1<<5, + FLAGS_LONGLONG = 1<<6, + FLAGS_LONGDOUBLE = 1<<7, + FLAGS_PAD_NIL = 1<<8, + FLAGS_UNSIGNED = 1<<9, + FLAGS_OCTAL = 1<<10, + FLAGS_HEX = 1<<11, + FLAGS_UPPER = 1<<12, + FLAGS_WIDTH = 1<<13, /* '*' or '*$' used */ + FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */ + FLAGS_PREC = 1<<15, /* precision was specified */ + FLAGS_PRECPARAM = 1<<16, /* precision PARAMETER was specified */ + FLAGS_CHAR = 1<<17, /* %c story */ + FLAGS_FLOATE = 1<<18, /* %e or %E */ + FLAGS_FLOATG = 1<<19 /* %g or %G */ +}; + +typedef struct { + FormatType type; + int flags; + long width; /* width OR width parameter number */ + long precision; /* precision OR precision parameter number */ + union { + char *str; + void *ptr; + union { + mp_intmax_t as_signed; + mp_uintmax_t as_unsigned; + } num; + double dnum; + } data; +} va_stack_t; + +struct nsprintf { + char *buffer; + size_t length; + size_t max; +}; + +struct asprintf { + char *buffer; /* allocated buffer */ + size_t len; /* length of string */ + size_t alloc; /* length of alloc */ + int fail; /* (!= 0) if an alloc has failed and thus + the output is not the complete data */ +}; + +static long dprintf_DollarString(char *input, char **end) +{ + int number=0; + while(ISDIGIT(*input)) { + number *= 10; + number += *input-'0'; + input++; + } + if(number && ('$'==*input++)) { + *end = input; + return number; + } + return 0; +} + +static bool dprintf_IsQualifierNoDollar(const char *fmt) +{ +#if defined(MP_HAVE_INT_EXTENSIONS) + if(!strncmp(fmt, "I32", 3) || !strncmp(fmt, "I64", 3)) { + return TRUE; + } +#endif + + switch(*fmt) { + case '-': case '+': case ' ': case '#': case '.': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 'h': case 'l': case 'L': case 'z': case 'q': + case '*': case 'O': +#if defined(MP_HAVE_INT_EXTENSIONS) + case 'I': +#endif + return TRUE; + + default: + return FALSE; + } +} + +/****************************************************************** + * + * Pass 1: + * Create an index with the type of each parameter entry and its + * value (may vary in size) + * + ******************************************************************/ + +static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, + va_list arglist) +{ + char *fmt = (char *)format; + int param_num = 0; + long this_param; + long width; + long precision; + int flags; + long max_param=0; + long i; + + while(*fmt) { + if(*fmt++ == '%') { + if(*fmt == '%') { + fmt++; + continue; /* while */ + } + + flags = FLAGS_NEW; + + /* Handle the positional case (N$) */ + + param_num++; + + this_param = dprintf_DollarString(fmt, &fmt); + if(0 == this_param) + /* we got no positional, get the next counter */ + this_param = param_num; + + if(this_param > max_param) + max_param = this_param; + + /* + * The parameter with number 'i' should be used. Next, we need + * to get SIZE and TYPE of the parameter. Add the information + * to our array. + */ + + width = 0; + precision = 0; + + /* Handle the flags */ + + while(dprintf_IsQualifierNoDollar(fmt)) { +#if defined(MP_HAVE_INT_EXTENSIONS) + if(!strncmp(fmt, "I32", 3)) { + flags |= FLAGS_LONG; + fmt += 3; + } + else if(!strncmp(fmt, "I64", 3)) { + flags |= FLAGS_LONGLONG; + fmt += 3; + } + else +#endif + + switch(*fmt++) { + case ' ': + flags |= FLAGS_SPACE; + break; + case '+': + flags |= FLAGS_SHOWSIGN; + break; + case '-': + flags |= FLAGS_LEFT; + flags &= ~FLAGS_PAD_NIL; + break; + case '#': + flags |= FLAGS_ALT; + break; + case '.': + flags |= FLAGS_PREC; + if('*' == *fmt) { + /* The precision is picked from a specified parameter */ + + flags |= FLAGS_PRECPARAM; + fmt++; + param_num++; + + i = dprintf_DollarString(fmt, &fmt); + if(i) + precision = i; + else + precision = param_num; + + if(precision > max_param) + max_param = precision; + } + else { + flags |= FLAGS_PREC; + precision = strtol(fmt, &fmt, 10); + } + break; + case 'h': + flags |= FLAGS_SHORT; + break; +#if defined(MP_HAVE_INT_EXTENSIONS) + case 'I': +#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG) + flags |= FLAGS_LONGLONG; +#else + flags |= FLAGS_LONG; +#endif + break; +#endif + case 'l': + if(flags & FLAGS_LONG) + flags |= FLAGS_LONGLONG; + else + flags |= FLAGS_LONG; + break; + case 'L': + flags |= FLAGS_LONGDOUBLE; + break; + case 'q': + flags |= FLAGS_LONGLONG; + break; + case 'z': + /* the code below generates a warning if -Wunreachable-code is + used */ +#if (SIZEOF_SIZE_T > CURL_SIZEOF_LONG) + flags |= FLAGS_LONGLONG; +#else + flags |= FLAGS_LONG; +#endif + break; + case 'O': +#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG) + flags |= FLAGS_LONGLONG; +#else + flags |= FLAGS_LONG; +#endif + break; + case '0': + if(!(flags & FLAGS_LEFT)) + flags |= FLAGS_PAD_NIL; + /* FALLTHROUGH */ + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + flags |= FLAGS_WIDTH; + width = strtol(fmt-1, &fmt, 10); + break; + case '*': /* Special case */ + flags |= FLAGS_WIDTHPARAM; + param_num++; + + i = dprintf_DollarString(fmt, &fmt); + if(i) + width = i; + else + width = param_num; + if(width > max_param) + max_param=width; + break; + default: + break; + } + } /* switch */ + + /* Handle the specifier */ + + i = this_param - 1; + + switch (*fmt) { + case 'S': + flags |= FLAGS_ALT; + /* FALLTHROUGH */ + case 's': + vto[i].type = FORMAT_STRING; + break; + case 'n': + vto[i].type = FORMAT_INTPTR; + break; + case 'p': + vto[i].type = FORMAT_PTR; + break; + case 'd': case 'i': + vto[i].type = FORMAT_INT; + break; + case 'u': + vto[i].type = FORMAT_INT; + flags |= FLAGS_UNSIGNED; + break; + case 'o': + vto[i].type = FORMAT_INT; + flags |= FLAGS_OCTAL; + break; + case 'x': + vto[i].type = FORMAT_INT; + flags |= FLAGS_HEX|FLAGS_UNSIGNED; + break; + case 'X': + vto[i].type = FORMAT_INT; + flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED; + break; + case 'c': + vto[i].type = FORMAT_INT; + flags |= FLAGS_CHAR; + break; + case 'f': + vto[i].type = FORMAT_DOUBLE; + break; + case 'e': + vto[i].type = FORMAT_DOUBLE; + flags |= FLAGS_FLOATE; + break; + case 'E': + vto[i].type = FORMAT_DOUBLE; + flags |= FLAGS_FLOATE|FLAGS_UPPER; + break; + case 'g': + vto[i].type = FORMAT_DOUBLE; + flags |= FLAGS_FLOATG; + break; + case 'G': + vto[i].type = FORMAT_DOUBLE; + flags |= FLAGS_FLOATG|FLAGS_UPPER; + break; + default: + vto[i].type = FORMAT_UNKNOWN; + break; + } /* switch */ + + vto[i].flags = flags; + vto[i].width = width; + vto[i].precision = precision; + + if(flags & FLAGS_WIDTHPARAM) { + /* we have the width specified from a parameter, so we make that + parameter's info setup properly */ - vto[i].width = width - 1; - i = width - 1; - vto[i].type = FORMAT_WIDTH; - vto[i].flags = FLAGS_NEW; - vto[i].precision = vto[i].width = 0; /* can't use width or precision - of width! */ ++ long k = width - 1; ++ vto[i].width = k; ++ vto[k].type = FORMAT_WIDTH; ++ vto[k].flags = FLAGS_NEW; ++ /* can't use width or precision of width! */ ++ vto[k].width = 0; ++ vto[k].precision = 0; + } + if(flags & FLAGS_PRECPARAM) { + /* we have the precision specified from a parameter, so we make that + parameter's info setup properly */ - vto[i].precision = precision - 1; - i = precision - 1; - vto[i].type = FORMAT_WIDTH; - vto[i].flags = FLAGS_NEW; - vto[i].precision = vto[i].width = 0; /* can't use width or precision - of width! */ ++ long k = precision - 1; ++ vto[i].precision = k; ++ vto[k].type = FORMAT_WIDTH; ++ vto[k].flags = FLAGS_NEW; ++ /* can't use width or precision of width! */ ++ vto[k].width = 0; ++ vto[k].precision = 0; + } + *endpos++ = fmt + 1; /* end of this sequence */ + } + } + + /* Read the arg list parameters into our data list */ + for(i=0; i$ sequence */ + param=dprintf_DollarString(f, &f); + + if(!param) + param = param_num; + else + --param; + + param_num++; /* increase this always to allow "%2$s %1$s %s" and then the + third %s will pick the 3rd argument */ + + p = &vto[param]; + + /* pick up the specified width */ - if(p->flags & FLAGS_WIDTHPARAM) ++ if(p->flags & FLAGS_WIDTHPARAM) { + width = (long)vto[p->width].data.num.as_signed; ++ param_num++; /* since the width is extracted from a parameter, we ++ must skip that to get to the next one properly */ ++ if(width < 0) { ++ /* "A negative field width is taken as a '-' flag followed by a ++ positive field width." */ ++ width = -width; ++ p->flags |= FLAGS_LEFT; ++ p->flags &= ~FLAGS_PAD_NIL; ++ } ++ } + else + width = p->width; + + /* pick up the specified precision */ + if(p->flags & FLAGS_PRECPARAM) { + prec = (long)vto[p->precision].data.num.as_signed; - param_num++; /* since the precision is extraced from a parameter, we ++ param_num++; /* since the precision is extracted from a parameter, we + must skip that to get to the next one properly */ ++ if(prec < 0) ++ /* "A negative precision is taken as if the precision were ++ omitted." */ ++ prec = -1; + } + else if(p->flags & FLAGS_PREC) + prec = p->precision; + else + prec = -1; + + is_alt = (p->flags & FLAGS_ALT) ? 1 : 0; + + switch (p->type) { + case FORMAT_INT: + num = p->data.num.as_unsigned; + if(p->flags & FLAGS_CHAR) { + /* Character. */ + if(!(p->flags & FLAGS_LEFT)) + while(--width > 0) + OUTCHAR(' '); + OUTCHAR((char) num); + if(p->flags & FLAGS_LEFT) + while(--width > 0) + OUTCHAR(' '); + break; + } + if(p->flags & FLAGS_OCTAL) { + /* Octal unsigned integer. */ + base = 8; + goto unsigned_number; + } + else if(p->flags & FLAGS_HEX) { + /* Hexadecimal unsigned integer. */ + + digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; + base = 16; + goto unsigned_number; + } + else if(p->flags & FLAGS_UNSIGNED) { + /* Decimal unsigned integer. */ + base = 10; + goto unsigned_number; + } + + /* Decimal integer. */ + base = 10; + + is_neg = (p->data.num.as_signed < (mp_intmax_t)0) ? 1 : 0; + if(is_neg) { + /* signed_num might fail to hold absolute negative minimum by 1 */ + signed_num = p->data.num.as_signed + (mp_intmax_t)1; + signed_num = -signed_num; + num = (mp_uintmax_t)signed_num; + num += (mp_uintmax_t)1; + } + + goto number; + + unsigned_number: + /* Unsigned number of base BASE. */ + is_neg = 0; + + number: + /* Number of base BASE. */ - { - char *workend = &work[sizeof(work) - 1]; - char *w; - - /* Supply a default precision if none was given. */ - if(prec == -1) - prec = 1; - - /* Put the number in WORK. */ - w = workend; - while(num > 0) { - *w-- = digits[num % base]; - num /= base; - } - width -= (long)(workend - w); - prec -= (long)(workend - w); + - if(is_alt && base == 8 && prec <= 0) { - *w-- = '0'; - --width; - } ++ /* Supply a default precision if none was given. */ ++ if(prec == -1) ++ prec = 1; + - if(prec > 0) { - width -= prec; - while(prec-- > 0) - *w-- = '0'; - } ++ /* Put the number in WORK. */ ++ w = workend; ++ while(num > 0) { ++ *w-- = digits[num % base]; ++ num /= base; ++ } ++ width -= (long)(workend - w); ++ prec -= (long)(workend - w); ++ ++ if(is_alt && base == 8 && prec <= 0) { ++ *w-- = '0'; ++ --width; ++ } + - if(is_alt && base == 16) - width -= 2; ++ if(prec > 0) { ++ width -= prec; ++ while(prec-- > 0) ++ *w-- = '0'; ++ } + - if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE)) - --width; ++ if(is_alt && base == 16) ++ width -= 2; + - if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL)) - while(width-- > 0) - OUTCHAR(' '); ++ if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE)) ++ --width; + - if(is_neg) - OUTCHAR('-'); - else if(p->flags & FLAGS_SHOWSIGN) - OUTCHAR('+'); - else if(p->flags & FLAGS_SPACE) ++ if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL)) ++ while(width-- > 0) + OUTCHAR(' '); + - if(is_alt && base == 16) { - OUTCHAR('0'); - if(p->flags & FLAGS_UPPER) - OUTCHAR('X'); - else - OUTCHAR('x'); - } - - if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL)) - while(width-- > 0) - OUTCHAR('0'); ++ if(is_neg) ++ OUTCHAR('-'); ++ else if(p->flags & FLAGS_SHOWSIGN) ++ OUTCHAR('+'); ++ else if(p->flags & FLAGS_SPACE) ++ OUTCHAR(' '); ++ ++ if(is_alt && base == 16) { ++ OUTCHAR('0'); ++ if(p->flags & FLAGS_UPPER) ++ OUTCHAR('X'); ++ else ++ OUTCHAR('x'); ++ } + - /* Write the number. */ - while(++w <= workend) { - OUTCHAR(*w); - } ++ if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL)) ++ while(width-- > 0) ++ OUTCHAR('0'); + - if(p->flags & FLAGS_LEFT) - while(width-- > 0) - OUTCHAR(' '); ++ /* Write the number. */ ++ while(++w <= workend) { ++ OUTCHAR(*w); + } ++ ++ if(p->flags & FLAGS_LEFT) ++ while(width-- > 0) ++ OUTCHAR(' '); + break; + + case FORMAT_STRING: + /* String. */ + { + static const char null[] = "(nil)"; + const char *str; + size_t len; + + str = (char *) p->data.str; + if(str == NULL) { + /* Write null[] if there's space. */ + if(prec == -1 || prec >= (long) sizeof(null) - 1) { + str = null; + len = sizeof(null) - 1; + /* Disable quotes around (nil) */ + p->flags &= (~FLAGS_ALT); + } + else { + str = ""; + len = 0; + } + } + else if(prec != -1) + len = (size_t)prec; + else + len = strlen(str); + - width -= (long)len; ++ width -= (len > LONG_MAX) ? LONG_MAX : (long)len; + + if(p->flags & FLAGS_ALT) + OUTCHAR('"'); + + if(!(p->flags&FLAGS_LEFT)) + while(width-- > 0) + OUTCHAR(' '); + + while((len-- > 0) && *str) + OUTCHAR(*str++); + if(p->flags&FLAGS_LEFT) + while(width-- > 0) + OUTCHAR(' '); + + if(p->flags & FLAGS_ALT) + OUTCHAR('"'); + } + break; + + case FORMAT_PTR: + /* Generic pointer. */ + { + void *ptr; + ptr = (void *) p->data.ptr; + if(ptr != NULL) { + /* If the pointer is not NULL, write it as a %#x spec. */ + base = 16; + digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; + is_alt = 1; + num = (size_t) ptr; + is_neg = 0; + goto number; + } + else { + /* Write "(nil)" for a nil pointer. */ + static const char strnil[] = "(nil)"; + const char *point; + + width -= (long)(sizeof(strnil) - 1); + if(p->flags & FLAGS_LEFT) + while(width-- > 0) + OUTCHAR(' '); + for(point = strnil; *point != '\0'; ++point) + OUTCHAR(*point); + if(! (p->flags & FLAGS_LEFT)) + while(width-- > 0) + OUTCHAR(' '); + } + } + break; + + case FORMAT_DOUBLE: + { + char formatbuf[32]="%"; + char *fptr = &formatbuf[1]; + size_t left = sizeof(formatbuf)-strlen(formatbuf); + int len; + + width = -1; + if(p->flags & FLAGS_WIDTH) + width = p->width; + else if(p->flags & FLAGS_WIDTHPARAM) + width = (long)vto[p->width].data.num.as_signed; + + prec = -1; + if(p->flags & FLAGS_PREC) + prec = p->precision; + else if(p->flags & FLAGS_PRECPARAM) + prec = (long)vto[p->precision].data.num.as_signed; + + if(p->flags & FLAGS_LEFT) + *fptr++ = '-'; + if(p->flags & FLAGS_SHOWSIGN) + *fptr++ = '+'; + if(p->flags & FLAGS_SPACE) + *fptr++ = ' '; + if(p->flags & FLAGS_ALT) + *fptr++ = '#'; + + *fptr = 0; + + if(width >= 0) { + /* RECURSIVE USAGE */ + len = curl_msnprintf(fptr, left, "%ld", width); + fptr += len; + left -= len; + } + if(prec >= 0) { + /* RECURSIVE USAGE */ + len = curl_msnprintf(fptr, left, ".%ld", prec); + fptr += len; + } + if(p->flags & FLAGS_LONG) + *fptr++ = 'l'; + + if(p->flags & FLAGS_FLOATE) + *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'E':'e'); + else if(p->flags & FLAGS_FLOATG) + *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'G' : 'g'); + else + *fptr++ = 'f'; + + *fptr = 0; /* and a final zero termination */ + + /* NOTE NOTE NOTE!! Not all sprintf implementations return number of + output characters */ + (sprintf)(work, formatbuf, p->data.dnum); + + for(fptr=work; *fptr; fptr++) + OUTCHAR(*fptr); + } + break; + + case FORMAT_INTPTR: + /* Answer the count of characters written. */ +#ifdef HAVE_LONG_LONG_TYPE + if(p->flags & FLAGS_LONGLONG) + *(LONG_LONG_TYPE *) p->data.ptr = (LONG_LONG_TYPE)done; + else +#endif + if(p->flags & FLAGS_LONG) + *(long *) p->data.ptr = (long)done; + else if(!(p->flags & FLAGS_SHORT)) + *(int *) p->data.ptr = (int)done; + else + *(short *) p->data.ptr = (short)done; + break; + + default: + break; + } + f = *end++; /* goto end of %-code */ + + } + return done; +} + +/* fputc() look-alike */ +static int addbyter(int output, FILE *data) +{ + struct nsprintf *infop=(struct nsprintf *)data; + unsigned char outc = (unsigned char)output; + + if(infop->length < infop->max) { + /* only do this if we haven't reached max length yet */ + infop->buffer[0] = outc; /* store */ + infop->buffer++; /* increase pointer */ + infop->length++; /* we are now one byte larger */ + return outc; /* fputc() returns like this on success */ + } + return -1; +} + +int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, + va_list ap_save) +{ + int retcode; + struct nsprintf info; + + info.buffer = buffer; + info.length = 0; + info.max = maxlength; + + retcode = dprintf_formatf(&info, addbyter, format, ap_save); + if(info.max) { + /* we terminate this with a zero byte */ + if(info.max == info.length) + /* we're at maximum, scrap the last letter */ + info.buffer[-1] = 0; + else + info.buffer[0] = 0; + } + return retcode; +} + +int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...) +{ + int retcode; + va_list ap_save; /* argument pointer */ + va_start(ap_save, format); + retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save); + va_end(ap_save); + return retcode; +} + +/* fputc() look-alike */ +static int alloc_addbyter(int output, FILE *data) +{ + struct asprintf *infop=(struct asprintf *)data; + unsigned char outc = (unsigned char)output; + + if(!infop->buffer) { + infop->buffer = malloc(32); + if(!infop->buffer) { + infop->fail = 1; + return -1; /* fail */ + } + infop->alloc = 32; + infop->len =0; + } + else if(infop->len+1 >= infop->alloc) { + char *newptr; + + newptr = realloc(infop->buffer, infop->alloc*2); + + if(!newptr) { + infop->fail = 1; + return -1; /* fail */ + } + infop->buffer = newptr; + infop->alloc *= 2; + } + + infop->buffer[ infop->len ] = outc; + + infop->len++; + + return outc; /* fputc() returns like this on success */ +} + +char *curl_maprintf(const char *format, ...) +{ + va_list ap_save; /* argument pointer */ + int retcode; + struct asprintf info; + + info.buffer = NULL; + info.len = 0; + info.alloc = 0; + info.fail = 0; + + va_start(ap_save, format); + retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); + va_end(ap_save); + if((-1 == retcode) || info.fail) { + if(info.alloc) + free(info.buffer); + return NULL; + } + if(info.alloc) { + info.buffer[info.len] = 0; /* we terminate this with a zero byte */ + return info.buffer; + } + else + return strdup(""); +} + +char *curl_mvaprintf(const char *format, va_list ap_save) +{ + int retcode; + struct asprintf info; + + info.buffer = NULL; + info.len = 0; + info.alloc = 0; + info.fail = 0; + + retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); + if((-1 == retcode) || info.fail) { + if(info.alloc) + free(info.buffer); + return NULL; + } + + if(info.alloc) { + info.buffer[info.len] = 0; /* we terminate this with a zero byte */ + return info.buffer; + } + else + return strdup(""); +} + +static int storebuffer(int output, FILE *data) +{ + char **buffer = (char **)data; + unsigned char outc = (unsigned char)output; + **buffer = outc; + (*buffer)++; + return outc; /* act like fputc() ! */ +} + +int curl_msprintf(char *buffer, const char *format, ...) +{ + va_list ap_save; /* argument pointer */ + int retcode; + va_start(ap_save, format); + retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); + va_end(ap_save); + *buffer=0; /* we terminate this with a zero byte */ + return retcode; +} + +int curl_mprintf(const char *format, ...) +{ + int retcode; + va_list ap_save; /* argument pointer */ + va_start(ap_save, format); + + retcode = dprintf_formatf(stdout, fputc, format, ap_save); + va_end(ap_save); + return retcode; +} + +int curl_mfprintf(FILE *whereto, const char *format, ...) +{ + int retcode; + va_list ap_save; /* argument pointer */ + va_start(ap_save, format); + retcode = dprintf_formatf(whereto, fputc, format, ap_save); + va_end(ap_save); + return retcode; +} + +int curl_mvsprintf(char *buffer, const char *format, va_list ap_save) +{ + int retcode; + retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); + *buffer=0; /* we terminate this with a zero byte */ + return retcode; +} + +int curl_mvprintf(const char *format, va_list ap_save) +{ + return dprintf_formatf(stdout, fputc, format, ap_save); +} + +int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save) +{ + return dprintf_formatf(whereto, fputc, format, ap_save); +} diff --cc Utilities/cmcurl/lib/select.c index 6eff070,0000000..2002349 mode 100644,000000..100644 --- a/Utilities/cmcurl/lib/select.c +++ b/Utilities/cmcurl/lib/select.c @@@ -1,578 -1,0 +1,578 @@@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. ++ * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE) +#error "We can't compile without select() or poll() support." +#endif + +#if defined(__BEOS__) +/* BeOS has FD_SET defined in socket.h */ +#include +#endif + +#ifdef MSDOS +#include /* delay() */ +#endif + +#ifdef __VXWORKS__ +#include /* bzero() in FD_SET */ +#endif + +#include + +#include "urldata.h" +#include "connect.h" +#include "select.h" +#include "warnless.h" + +/* Convenience local macros */ + +#define elapsed_ms (int)curlx_tvdiff(curlx_tvnow(), initial_tv) + +int Curl_ack_eintr = 0; +#define error_not_EINTR (Curl_ack_eintr || error != EINTR) + +/* + * Internal function used for waiting a specific amount of ms + * in Curl_socket_ready() and Curl_poll() when no file descriptor + * is provided to wait on, just being used to delay execution. + * WinSock select() and poll() timeout mechanisms need a valid + * socket descriptor in a not null file descriptor set to work. + * Waiting indefinitely with this function is not allowed, a + * zero or negative timeout value will return immediately. + * Timeout resolution, accuracy, as well as maximum supported + * value is system dependent, neither factor is a citical issue + * for the intended use of this function in the library. + * + * Return values: + * -1 = system call error, invalid timeout value, or interrupted + * 0 = specified timeout has elapsed + */ +int Curl_wait_ms(int timeout_ms) +{ +#if !defined(MSDOS) && !defined(USE_WINSOCK) +#ifndef HAVE_POLL_FINE + struct timeval pending_tv; +#endif + struct timeval initial_tv; + int pending_ms; + int error; +#endif + int r = 0; + + if(!timeout_ms) + return 0; + if(timeout_ms < 0) { + SET_SOCKERRNO(EINVAL); + return -1; + } +#if defined(MSDOS) + delay(timeout_ms); +#elif defined(USE_WINSOCK) + Sleep(timeout_ms); +#else + pending_ms = timeout_ms; + initial_tv = curlx_tvnow(); + do { +#if defined(HAVE_POLL_FINE) + r = poll(NULL, 0, pending_ms); +#else + pending_tv.tv_sec = pending_ms / 1000; + pending_tv.tv_usec = (pending_ms % 1000) * 1000; + r = select(0, NULL, NULL, NULL, &pending_tv); +#endif /* HAVE_POLL_FINE */ + if(r != -1) + break; + error = SOCKERRNO; + if(error && error_not_EINTR) + break; + pending_ms = timeout_ms - elapsed_ms; + if(pending_ms <= 0) { + r = 0; /* Simulate a "call timed out" case */ + break; + } + } while(r == -1); +#endif /* USE_WINSOCK */ + if(r) + r = -1; + return r; +} + +/* + * Wait for read or write events on a set of file descriptors. It uses poll() + * when a fine poll() is available, in order to avoid limits with FD_SETSIZE, + * otherwise select() is used. An error is returned if select() is being used + * and a file descriptor is too large for FD_SETSIZE. + * + * A negative timeout value makes this function wait indefinitely, + * unles no valid file descriptor is given, when this happens the + * negative timeout is ignored and the function times out immediately. + * + * Return values: + * -1 = system call error or fd >= FD_SETSIZE + * 0 = timeout + * [bitmask] = action as described below + * + * CURL_CSELECT_IN - first socket is readable + * CURL_CSELECT_IN2 - second socket is readable + * CURL_CSELECT_OUT - write socket is writable + * CURL_CSELECT_ERR - an error condition occurred + */ +int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ + curl_socket_t readfd1, + curl_socket_t writefd, /* socket to write to */ + long timeout_ms) /* milliseconds to wait */ +{ +#ifdef HAVE_POLL_FINE + struct pollfd pfd[3]; + int num; +#else + struct timeval pending_tv; + struct timeval *ptimeout; + fd_set fds_read; + fd_set fds_write; + fd_set fds_err; + curl_socket_t maxfd; +#endif + struct timeval initial_tv = {0, 0}; + int pending_ms = 0; + int error; + int r; + int ret; + + if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) && + (writefd == CURL_SOCKET_BAD)) { + /* no sockets, just wait */ + r = Curl_wait_ms((int)timeout_ms); + return r; + } + + /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed + time in this function does not need to be measured. This happens + when function is called with a zero timeout or a negative timeout + value indicating a blocking call should be performed. */ + + if(timeout_ms > 0) { + pending_ms = (int)timeout_ms; + initial_tv = curlx_tvnow(); + } + +#ifdef HAVE_POLL_FINE + + num = 0; + if(readfd0 != CURL_SOCKET_BAD) { + pfd[num].fd = readfd0; + pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI; + pfd[num].revents = 0; + num++; + } + if(readfd1 != CURL_SOCKET_BAD) { + pfd[num].fd = readfd1; + pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI; + pfd[num].revents = 0; + num++; + } + if(writefd != CURL_SOCKET_BAD) { + pfd[num].fd = writefd; + pfd[num].events = POLLWRNORM|POLLOUT; + pfd[num].revents = 0; + num++; + } + + do { + if(timeout_ms < 0) + pending_ms = -1; + else if(!timeout_ms) + pending_ms = 0; + r = poll(pfd, num, pending_ms); + if(r != -1) + break; + error = SOCKERRNO; + if(error && error_not_EINTR) + break; + if(timeout_ms > 0) { + pending_ms = (int)(timeout_ms - elapsed_ms); + if(pending_ms <= 0) { + r = 0; /* Simulate a "call timed out" case */ + break; + } + } + } while(r == -1); + + if(r < 0) + return -1; + if(r == 0) + return 0; + + ret = 0; + num = 0; + if(readfd0 != CURL_SOCKET_BAD) { + if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP)) + ret |= CURL_CSELECT_IN; + if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL)) + ret |= CURL_CSELECT_ERR; + num++; + } + if(readfd1 != CURL_SOCKET_BAD) { + if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP)) + ret |= CURL_CSELECT_IN2; + if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL)) + ret |= CURL_CSELECT_ERR; + num++; + } + if(writefd != CURL_SOCKET_BAD) { + if(pfd[num].revents & (POLLWRNORM|POLLOUT)) + ret |= CURL_CSELECT_OUT; + if(pfd[num].revents & (POLLERR|POLLHUP|POLLNVAL)) + ret |= CURL_CSELECT_ERR; + } + + return ret; + +#else /* HAVE_POLL_FINE */ + + FD_ZERO(&fds_err); + maxfd = (curl_socket_t)-1; + + FD_ZERO(&fds_read); + if(readfd0 != CURL_SOCKET_BAD) { + VERIFY_SOCK(readfd0); + FD_SET(readfd0, &fds_read); + FD_SET(readfd0, &fds_err); + maxfd = readfd0; + } + if(readfd1 != CURL_SOCKET_BAD) { + VERIFY_SOCK(readfd1); + FD_SET(readfd1, &fds_read); + FD_SET(readfd1, &fds_err); + if(readfd1 > maxfd) + maxfd = readfd1; + } + + FD_ZERO(&fds_write); + if(writefd != CURL_SOCKET_BAD) { + VERIFY_SOCK(writefd); + FD_SET(writefd, &fds_write); + FD_SET(writefd, &fds_err); + if(writefd > maxfd) + maxfd = writefd; + } + + ptimeout = (timeout_ms < 0) ? NULL : &pending_tv; + + do { + if(timeout_ms > 0) { + pending_tv.tv_sec = pending_ms / 1000; + pending_tv.tv_usec = (pending_ms % 1000) * 1000; + } + else if(!timeout_ms) { + pending_tv.tv_sec = 0; + pending_tv.tv_usec = 0; + } + + /* WinSock select() must not be called with an fd_set that contains zero + fd flags, or it will return WSAEINVAL. But, it also can't be called + with no fd_sets at all! From the documentation: + + Any two of the parameters, readfds, writefds, or exceptfds, can be + given as null. At least one must be non-null, and any non-null + descriptor set must contain at least one handle to a socket. + + We know that we have at least one bit set in at least two fd_sets in + this case, but we may have no bits set in either fds_read or fd_write, + so check for that and handle it. Luckily, with WinSock, we can _also_ + ask how many bits are set on an fd_set. + + It is unclear why WinSock doesn't just handle this for us instead of + calling this an error. + + Note also that WinSock ignores the first argument, so we don't worry + about the fact that maxfd is computed incorrectly with WinSock (since + curl_socket_t is unsigned in such cases and thus -1 is the largest + value). + */ ++#ifdef USE_WINSOCK + r = select((int)maxfd + 1, - #ifndef USE_WINSOCK - &fds_read, - &fds_write, - #else + fds_read.fd_count ? &fds_read : NULL, + fds_write.fd_count ? &fds_write : NULL, - #endif + &fds_err, ptimeout); ++#else ++ r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); ++#endif ++ + if(r != -1) + break; + error = SOCKERRNO; + if(error && error_not_EINTR) + break; + if(timeout_ms > 0) { + pending_ms = timeout_ms - elapsed_ms; + if(pending_ms <= 0) { + r = 0; /* Simulate a "call timed out" case */ + break; + } + } + } while(r == -1); + + if(r < 0) + return -1; + if(r == 0) + return 0; + + ret = 0; + if(readfd0 != CURL_SOCKET_BAD) { + if(FD_ISSET(readfd0, &fds_read)) + ret |= CURL_CSELECT_IN; + if(FD_ISSET(readfd0, &fds_err)) + ret |= CURL_CSELECT_ERR; + } + if(readfd1 != CURL_SOCKET_BAD) { + if(FD_ISSET(readfd1, &fds_read)) + ret |= CURL_CSELECT_IN2; + if(FD_ISSET(readfd1, &fds_err)) + ret |= CURL_CSELECT_ERR; + } + if(writefd != CURL_SOCKET_BAD) { + if(FD_ISSET(writefd, &fds_write)) + ret |= CURL_CSELECT_OUT; + if(FD_ISSET(writefd, &fds_err)) + ret |= CURL_CSELECT_ERR; + } + + return ret; + +#endif /* HAVE_POLL_FINE */ + +} + +/* + * This is a wrapper around poll(). If poll() does not exist, then + * select() is used instead. An error is returned if select() is + * being used and a file descriptor is too large for FD_SETSIZE. + * A negative timeout value makes this function wait indefinitely, + * unles no valid file descriptor is given, when this happens the + * negative timeout is ignored and the function times out immediately. + * + * Return values: + * -1 = system call error or fd >= FD_SETSIZE + * 0 = timeout + * N = number of structures with non zero revent fields + */ +int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) +{ +#ifndef HAVE_POLL_FINE + struct timeval pending_tv; + struct timeval *ptimeout; + fd_set fds_read; + fd_set fds_write; + fd_set fds_err; + curl_socket_t maxfd; +#endif + struct timeval initial_tv = {0, 0}; + bool fds_none = TRUE; + unsigned int i; + int pending_ms = 0; + int error; + int r; + + if(ufds) { + for(i = 0; i < nfds; i++) { + if(ufds[i].fd != CURL_SOCKET_BAD) { + fds_none = FALSE; + break; + } + } + } + if(fds_none) { + r = Curl_wait_ms(timeout_ms); + return r; + } + + /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed + time in this function does not need to be measured. This happens + when function is called with a zero timeout or a negative timeout + value indicating a blocking call should be performed. */ + + if(timeout_ms > 0) { + pending_ms = timeout_ms; + initial_tv = curlx_tvnow(); + } + +#ifdef HAVE_POLL_FINE + + do { + if(timeout_ms < 0) + pending_ms = -1; + else if(!timeout_ms) + pending_ms = 0; + r = poll(ufds, nfds, pending_ms); + if(r != -1) + break; + error = SOCKERRNO; + if(error && error_not_EINTR) + break; + if(timeout_ms > 0) { + pending_ms = timeout_ms - elapsed_ms; + if(pending_ms <= 0) { + r = 0; /* Simulate a "call timed out" case */ + break; + } + } + } while(r == -1); + + if(r < 0) + return -1; + if(r == 0) + return 0; + + for(i = 0; i < nfds; i++) { + if(ufds[i].fd == CURL_SOCKET_BAD) + continue; + if(ufds[i].revents & POLLHUP) + ufds[i].revents |= POLLIN; + if(ufds[i].revents & POLLERR) + ufds[i].revents |= (POLLIN|POLLOUT); + } + +#else /* HAVE_POLL_FINE */ + + FD_ZERO(&fds_read); + FD_ZERO(&fds_write); + FD_ZERO(&fds_err); + maxfd = (curl_socket_t)-1; + + for(i = 0; i < nfds; i++) { + ufds[i].revents = 0; + if(ufds[i].fd == CURL_SOCKET_BAD) + continue; + VERIFY_SOCK(ufds[i].fd); + if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI| + POLLRDNORM|POLLWRNORM|POLLRDBAND)) { + if(ufds[i].fd > maxfd) + maxfd = ufds[i].fd; + if(ufds[i].events & (POLLRDNORM|POLLIN)) + FD_SET(ufds[i].fd, &fds_read); + if(ufds[i].events & (POLLWRNORM|POLLOUT)) + FD_SET(ufds[i].fd, &fds_write); + if(ufds[i].events & (POLLRDBAND|POLLPRI)) + FD_SET(ufds[i].fd, &fds_err); + } + } + +#ifdef USE_WINSOCK + /* WinSock select() can't handle zero events. See the comment about this in + Curl_check_socket(). */ + if(fds_read.fd_count == 0 && fds_write.fd_count == 0 + && fds_err.fd_count == 0) { + r = Curl_wait_ms(timeout_ms); + return r; + } +#endif + + ptimeout = (timeout_ms < 0) ? NULL : &pending_tv; + + do { + if(timeout_ms > 0) { + pending_tv.tv_sec = pending_ms / 1000; + pending_tv.tv_usec = (pending_ms % 1000) * 1000; + } + else if(!timeout_ms) { + pending_tv.tv_sec = 0; + pending_tv.tv_usec = 0; + } ++ ++#ifdef USE_WINSOCK + r = select((int)maxfd + 1, - #ifndef USE_WINSOCK - &fds_read, &fds_write, &fds_err, - #else + /* WinSock select() can't handle fd_sets with zero bits set, so + don't give it such arguments. See the comment about this in + Curl_check_socket(). + */ + fds_read.fd_count ? &fds_read : NULL, + fds_write.fd_count ? &fds_write : NULL, - fds_err.fd_count ? &fds_err : NULL, ++ fds_err.fd_count ? &fds_err : NULL, ptimeout); ++#else ++ r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); +#endif - ptimeout); + if(r != -1) + break; + error = SOCKERRNO; + if(error && error_not_EINTR) + break; + if(timeout_ms > 0) { + pending_ms = timeout_ms - elapsed_ms; + if(pending_ms <= 0) { + r = 0; /* Simulate a "call timed out" case */ + break; + } + } + } while(r == -1); + + if(r < 0) + return -1; + if(r == 0) + return 0; + + r = 0; + for(i = 0; i < nfds; i++) { + ufds[i].revents = 0; + if(ufds[i].fd == CURL_SOCKET_BAD) + continue; + if(FD_ISSET(ufds[i].fd, &fds_read)) + ufds[i].revents |= POLLIN; + if(FD_ISSET(ufds[i].fd, &fds_write)) + ufds[i].revents |= POLLOUT; + if(FD_ISSET(ufds[i].fd, &fds_err)) + ufds[i].revents |= POLLPRI; + if(ufds[i].revents != 0) + r++; + } + +#endif /* HAVE_POLL_FINE */ + + return r; +} + +#ifdef TPF +/* + * This is a replacement for select() on the TPF platform. + * It is used whenever libcurl calls select(). + * The call below to tpf_process_signals() is required because + * TPF's select calls are not signal interruptible. + * + * Return values are the same as select's. + */ +int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, + fd_set* excepts, struct timeval* tv) +{ + int rc; + + rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv); + tpf_process_signals(); + return rc; +} +#endif /* TPF */ diff --cc Utilities/cmcurl/lib/system_win32.c index 0000000,d6a998b..d6a998b mode 000000,100644..100644 --- a/Utilities/cmcurl/lib/system_win32.c +++ b/Utilities/cmcurl/lib/system_win32.c diff --cc Utilities/cmcurl/lib/system_win32.h index 0000000,1e77285..1e77285 mode 000000,100644..100644 --- a/Utilities/cmcurl/lib/system_win32.h +++ b/Utilities/cmcurl/lib/system_win32.h diff --cc Utilities/cmcurl/lib/vauth/cleartext.c index 0000000,4e906bc..4e906bc mode 000000,100644..100644 --- a/Utilities/cmcurl/lib/vauth/cleartext.c +++ b/Utilities/cmcurl/lib/vauth/cleartext.c diff --cc Utilities/cmcurl/lib/vauth/cram.c index 0000000,3074a16..3074a16 mode 000000,100644..100644 --- a/Utilities/cmcurl/lib/vauth/cram.c +++ b/Utilities/cmcurl/lib/vauth/cram.c diff --cc Utilities/cmcurl/lib/vauth/digest.c index 0000000,26ea7b5..26ea7b5 mode 000000,100644..100644 --- a/Utilities/cmcurl/lib/vauth/digest.c +++ b/Utilities/cmcurl/lib/vauth/digest.c diff --cc Utilities/cmcurl/lib/vauth/digest_sspi.c index 0000000,6a7315e..6a7315e mode 000000,100644..100644 --- a/Utilities/cmcurl/lib/vauth/digest_sspi.c +++ b/Utilities/cmcurl/lib/vauth/digest_sspi.c diff --cc Utilities/cmcurl/lib/vauth/krb5_sspi.c index 0000000,08774f6..08774f6 mode 000000,100644..100644 --- a/Utilities/cmcurl/lib/vauth/krb5_sspi.c +++ b/Utilities/cmcurl/lib/vauth/krb5_sspi.c diff --cc Utilities/cmcurl/lib/vauth/ntlm_sspi.c index 0000000,982a9d3..982a9d3 mode 000000,100644..100644 --- a/Utilities/cmcurl/lib/vauth/ntlm_sspi.c +++ b/Utilities/cmcurl/lib/vauth/ntlm_sspi.c diff --cc Utilities/cmcurl/lib/vauth/oauth2.c index 0000000,6288f89..6288f89 mode 000000,100644..100644 --- a/Utilities/cmcurl/lib/vauth/oauth2.c +++ b/Utilities/cmcurl/lib/vauth/oauth2.c diff --cc Utilities/cmcurl/lib/vauth/spnego_gssapi.c index 0000000,b256ee6..b256ee6 mode 000000,100644..100644 --- a/Utilities/cmcurl/lib/vauth/spnego_gssapi.c +++ b/Utilities/cmcurl/lib/vauth/spnego_gssapi.c diff --cc Utilities/cmcurl/lib/vauth/spnego_sspi.c index 0000000,b6176ec..b6176ec mode 000000,100644..100644 --- a/Utilities/cmcurl/lib/vauth/spnego_sspi.c +++ b/Utilities/cmcurl/lib/vauth/spnego_sspi.c diff --cc Utilities/cmcurl/lib/vauth/vauth.c index 0000000,702e2d4..702e2d4 mode 000000,100644..100644 --- a/Utilities/cmcurl/lib/vauth/vauth.c +++ b/Utilities/cmcurl/lib/vauth/vauth.c diff --cc Utilities/cmcurl/lib/vauth/vauth.h index 0000000,38806ee..38806ee mode 000000,100644..100644 --- a/Utilities/cmcurl/lib/vauth/vauth.h +++ b/Utilities/cmcurl/lib/vauth/vauth.h diff --cc Utilities/cmcurl/lib/vtls/mbedtls.c index 0000000,a1e7d23..a1e7d23 mode 000000,100644..100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls.c +++ b/Utilities/cmcurl/lib/vtls/mbedtls.c diff --cc Utilities/cmcurl/lib/vtls/mbedtls.h index 0000000,1021d54..1021d54 mode 000000,100644..100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls.h +++ b/Utilities/cmcurl/lib/vtls/mbedtls.h https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=202adcfe056681109fe61569ecdb3bd69f0b4f97 commit 202adcfe056681109fe61569ecdb3bd69f0b4f97 Author: Curl Upstream AuthorDate: Wed Aug 3 08:37:16 2016 +0200 Commit: Brad King CommitDate: Wed Aug 3 14:26:29 2016 -0400 curl 2016-08-03 (f2cb3a01) Code extracted from: https://github.com/bagder/curl.git at commit f2cb3a01192d36395d16acec6cdb93446ca6fd45 (curl-7_50_1). diff --git a/CMake/CurlTests.c b/CMake/CurlTests.c index 04d5e7e..ceff391 100644 --- a/CMake/CurlTests.c +++ b/CMake/CurlTests.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -139,7 +139,7 @@ int main(void) rc = gethostbyname_r(address, &h, &hdata); #elif defined(HAVE_GETHOSTBYNAME_R_5) || \ defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) - rc = gethostbyname_r(address, &h, buffer, 8192, 0, &h_errnop); + rc = gethostbyname_r(address, &h, buffer, 8192, &h_errnop); (void)hp; /* not used for test */ #elif defined(HAVE_GETHOSTBYNAME_R_6) || \ defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT) diff --git a/CMake/OtherTests.cmake b/CMake/OtherTests.cmake index 4f07f22..d599498 100644 --- a/CMake/OtherTests.cmake +++ b/CMake/OtherTests.cmake @@ -10,8 +10,8 @@ endmacro(add_header_include) set(signature_call_conv) if(HAVE_WINDOWS_H) - add_header_include(HAVE_WINDOWS_H "windows.h") add_header_include(HAVE_WINSOCK2_H "winsock2.h") + add_header_include(HAVE_WINDOWS_H "windows.h") add_header_include(HAVE_WINSOCK_H "winsock.h") set(_source_epilogue "${_source_epilogue}\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif") diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a42cc7..7f7c4d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms -# are also available at http://curl.haxx.se/docs/copyright.html. +# are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is @@ -64,7 +64,7 @@ message(STATUS "curl version=[${CURL_VERSION}]") # SET(PACKAGE_NAME "curl") # SET(PACKAGE_VERSION "-") # SET(PACKAGE_STRING "curl-") -# SET(PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/") +# SET(PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.haxx.se/mail/") set(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}") set(OS "\"${CMAKE_SYSTEM_NAME}\"") @@ -72,7 +72,6 @@ include_directories(${PROJECT_BINARY_DIR}/include/curl) include_directories( ${CURL_SOURCE_DIR}/include ) option(BUILD_CURL_EXE "Set to ON to build cURL executable." ON) -option(BUILD_CURL_TESTS "Set to ON to build cURL tests." ON) option(CURL_STATICLIB "Set to ON to build libcurl with static linking." OFF) option(ENABLE_ARES "Set to ON to enable c-ares support" OFF) option(ENABLE_THREADED_RESOLVER "Set to ON to enable POSIX threaded DNS lookup" OFF) @@ -108,12 +107,6 @@ if(ENABLE_ARES) set(CURL_LIBS ${CURL_LIBS} ${CARES_LIBRARY}) endif() -option(BUILD_DASHBOARD_REPORTS "Set to ON to activate reporting of cURL builds here http://www.cdash.org/CDashPublic/index.php?project=CURL" OFF) -if(BUILD_DASHBOARD_REPORTS) - #INCLUDE(Dart) - include(CTest) -endif(BUILD_DASHBOARD_REPORTS) - if(MSVC) option(BUILD_RELEASE_DEBUG_DIRS "Set OFF to build each configuration to a separate directory" OFF) mark_as_advanced(BUILD_RELEASE_DEBUG_DIRS) @@ -122,11 +115,6 @@ endif() option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON) mark_as_advanced(CURL_HIDDEN_SYMBOLS) -# IF(WIN32) -# OPTION(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without openssl" ON) -# MARK_AS_ADVANCED(CURL_WINDOWS_SSPI) -# ENDIF() - option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" OFF) mark_as_advanced(HTTP_ONLY) option(CURL_DISABLE_FTP "disables FTP" OFF) @@ -186,7 +174,7 @@ option(DISABLED_THREADSAFE "Set to explicitly specify we don't want to use threa mark_as_advanced(DISABLED_THREADSAFE) option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON) mark_as_advanced(ENABLE_IPV6) -if(ENABLE_IPV6) +if(ENABLE_IPV6 AND NOT WIN32) include(CheckStructHasMember) check_struct_has_member("struct sockaddr_in6" sin6_addr "netinet/in.h" HAVE_SOCKADDR_IN6_SIN6_ADDR) @@ -253,6 +241,7 @@ include (CheckLibraryExists) include (CheckSymbolExists) include (CheckTypeSize) include (CheckCSourceCompiles) +include (CMakeDependentOption) # On windows preload settings if(WIN32) @@ -290,14 +279,22 @@ endif(NOT NOT_NEED_LIBNSL) check_function_exists(gethostname HAVE_GETHOSTNAME) +set(OPENSSL_DEFAULT ON) if(WIN32) + set(OPENSSL_DEFAULT OFF) check_library_exists_concat("ws2_32" getch HAVE_LIBWS2_32) check_library_exists_concat("winmm" getch HAVE_LIBWINMM) endif() -option(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" ON) +option(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" ${OPENSSL_DEFAULT}) mark_as_advanced(CMAKE_USE_OPENSSL) +if(WIN32) + CMAKE_DEPENDENT_OPTION(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without openssl" ON + "NOT CMAKE_USE_OPENSSL" OFF) + mark_as_advanced(CURL_WINDOWS_SSPI) +endif() + set(USE_OPENSSL OFF) set(HAVE_LIBCRYPTO OFF) set(HAVE_LIBSSL OFF) @@ -320,15 +317,16 @@ if(CMAKE_USE_OPENSSL) check_include_file("openssl/ssl.h" HAVE_OPENSSL_SSL_H) check_include_file("openssl/x509.h" HAVE_OPENSSL_X509_H) check_include_file("openssl/rand.h" HAVE_OPENSSL_RAND_H) + elseif(WIN32) + set(CURL_WINDOWS_SSPI ON) endif() endif() if(NOT CURL_DISABLE_LDAP) - if(WIN32) option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON) if(USE_WIN32_LDAP) - check_library_exists("wldap32" cldap_open "" HAVE_WLDAP32) + check_library_exists_concat("wldap32" cldap_open HAVE_WLDAP32) if(NOT HAVE_WLDAP32) set(USE_WIN32_LDAP OFF) endif() @@ -343,75 +341,78 @@ if(NOT CURL_DISABLE_LDAP) if(CMAKE_USE_OPENLDAP AND USE_WIN32_LDAP) message(FATAL_ERROR "Cannot use USE_WIN32_LDAP and CMAKE_USE_OPENLDAP at the same time") endif() - + # Now that we know, we're not using windows LDAP... - if(NOT USE_WIN32_LDAP) + if(USE_WIN32_LDAP) + check_include_file_concat("winldap.h" HAVE_WINLDAP_H) + check_include_file_concat("winber.h" HAVE_WINBER_H) + else() # Check for LDAP set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES}) check_library_exists_concat(${CMAKE_LDAP_LIB} ldap_init HAVE_LIBLDAP) check_library_exists_concat(${CMAKE_LBER_LIB} ber_init HAVE_LIBLBER) - else() - check_include_file_concat("winldap.h" HAVE_WINLDAP_H) - check_include_file_concat("winber.h" HAVE_WINBER_H) - endif() - - set(CMAKE_LDAP_INCLUDE_DIR "" CACHE STRING "Path to LDAP include directory") - if(CMAKE_LDAP_INCLUDE_DIR) - set(CMAKE_REQUIRED_INCLUDES ${CMAKE_LDAP_INCLUDE_DIR}) - endif() - check_include_file_concat("ldap.h" HAVE_LDAP_H) - check_include_file_concat("lber.h" HAVE_LBER_H) - - if(NOT HAVE_LDAP_H) - message(STATUS "LDAP_H not found CURL_DISABLE_LDAP set ON") - set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE) - elseif(NOT HAVE_LIBLDAP) - message(STATUS "LDAP library '${CMAKE_LDAP_LIB}' not found CURL_DISABLE_LDAP set ON") - set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE) - else() - if(CMAKE_USE_OPENLDAP) - set(USE_OPENLDAP ON) - endif() + + set(CMAKE_REQUIRED_INCLUDES_BAK ${CMAKE_REQUIRED_INCLUDES}) + set(CMAKE_LDAP_INCLUDE_DIR "" CACHE STRING "Path to LDAP include directory") if(CMAKE_LDAP_INCLUDE_DIR) - include_directories(${CMAKE_LDAP_INCLUDE_DIR}) - endif() - set(NEED_LBER_H ON) - set(_HEADER_LIST) - if(HAVE_WINDOWS_H) - list(APPEND _HEADER_LIST "windows.h") + list(APPEND CMAKE_REQUIRED_INCLUDES ${CMAKE_LDAP_INCLUDE_DIR}) endif() - if(HAVE_SYS_TYPES_H) - list(APPEND _HEADER_LIST "sys/types.h") - endif() - list(APPEND _HEADER_LIST "ldap.h") + check_include_file_concat("ldap.h" HAVE_LDAP_H) + check_include_file_concat("lber.h" HAVE_LBER_H) + + if(NOT HAVE_LDAP_H) + message(STATUS "LDAP_H not found CURL_DISABLE_LDAP set ON") + set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE) + set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used + elseif(NOT HAVE_LIBLDAP) + message(STATUS "LDAP library '${CMAKE_LDAP_LIB}' not found CURL_DISABLE_LDAP set ON") + set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE) + set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used + else() + if(CMAKE_USE_OPENLDAP) + set(USE_OPENLDAP ON) + endif() + if(CMAKE_LDAP_INCLUDE_DIR) + include_directories(${CMAKE_LDAP_INCLUDE_DIR}) + endif() + set(NEED_LBER_H ON) + set(_HEADER_LIST) + if(HAVE_WINDOWS_H) + list(APPEND _HEADER_LIST "windows.h") + endif() + if(HAVE_SYS_TYPES_H) + list(APPEND _HEADER_LIST "sys/types.h") + endif() + list(APPEND _HEADER_LIST "ldap.h") - set(_SRC_STRING "") - foreach(_HEADER ${_HEADER_LIST}) - set(_INCLUDE_STRING "${_INCLUDE_STRING}#include <${_HEADER}>\n") - endforeach() + set(_SRC_STRING "") + foreach(_HEADER ${_HEADER_LIST}) + set(_INCLUDE_STRING "${_INCLUDE_STRING}#include <${_HEADER}>\n") + endforeach() - set(_SRC_STRING - " - ${_INCLUDE_STRING} - int main(int argc, char ** argv) - { - BerValue *bvp = NULL; - BerElement *bep = ber_init(bvp); - ber_free(bep, 1); - return 0; - }" - ) - set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DLDAP_DEPRECATED=1") - list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB}) - if(HAVE_LIBLBER) - list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB}) - endif() - check_c_source_compiles("${_SRC_STRING}" NOT_NEED_LBER_H) + set(_SRC_STRING + " + ${_INCLUDE_STRING} + int main(int argc, char ** argv) + { + BerValue *bvp = NULL; + BerElement *bep = ber_init(bvp); + ber_free(bep, 1); + return 0; + }" + ) + set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DLDAP_DEPRECATED=1") + list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB}) + if(HAVE_LIBLBER) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB}) + endif() + check_c_source_compiles("${_SRC_STRING}" NOT_NEED_LBER_H) - if(NOT_NEED_LBER_H) - set(NEED_LBER_H OFF) - else() - set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DNEED_LBER_H") + if(NOT_NEED_LBER_H) + set(NEED_LBER_H OFF) + else() + set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DNEED_LBER_H") + endif() endif() endif() @@ -448,6 +449,7 @@ if(CURL_ZLIB) set(HAVE_LIBZ ON) list(APPEND CURL_LIBS ${ZLIB_LIBRARIES}) include_directories(${ZLIB_INCLUDE_DIRS}) + list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS}) endif() endif() @@ -463,7 +465,7 @@ if(CMAKE_USE_LIBSSH2) if(LIBSSH2_FOUND) list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY}) set(CMAKE_REQUIRED_LIBRARIES ${LIBSSH2_LIBRARY}) - set(CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}") + list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}") include_directories("${LIBSSH2_INCLUDE_DIR}") set(HAVE_LIBSSH2 ON) set(USE_LIBSSH2 ON) @@ -496,7 +498,7 @@ if(CMAKE_USE_GSSAPI) message(STATUS "Found ${GSS_FLAVOUR} GSSAPI version: \"${GSS_VERSION}\"") - set(CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIR}) + list(APPEND CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIRECTORIES}) check_include_file_concat("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H) check_include_file_concat("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H) check_include_file_concat("gssapi/gssapi_krb5.h" HAVE_GSSAPI_GSSAPI_KRB5_H) @@ -532,7 +534,7 @@ if(CMAKE_USE_GSSAPI) endif() - include_directories(${GSS_INCLUDE_DIR}) + include_directories(${GSS_INCLUDE_DIRECTORIES}) link_directories(${GSS_LINK_DIRECTORIES}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_COMPILER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}") @@ -552,12 +554,26 @@ else() unset(USE_UNIX_SOCKETS CACHE) endif() + # Check for header files if(NOT UNIX) check_include_file_concat("windows.h" HAVE_WINDOWS_H) check_include_file_concat("winsock.h" HAVE_WINSOCK_H) check_include_file_concat("ws2tcpip.h" HAVE_WS2TCPIP_H) check_include_file_concat("winsock2.h" HAVE_WINSOCK2_H) + if(CURL_WINDOWS_SSPI) + set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DSECURITY_WIN32") + check_include_file_concat("sspi.h" HAVE_SSPI_H) + if(HAVE_SSPI_H) + check_include_file_concat("schannel.h" HAVE_SCHANNEL_H) + set(USE_WINDOWS_SSPI ON) + if(HAVE_SCHANNEL_H) + set(USE_SCHANNEL ON) + set(SSL_ENABLED ON) + set(CURL_LIBS ${CURL_LIBS} "crypt32") + endif() + endif() + endif() endif(NOT UNIX) check_include_file_concat("stdio.h" HAVE_STDIO_H) @@ -1018,7 +1034,9 @@ add_subdirectory(lib) if(BUILD_CURL_EXE) add_subdirectory(src) endif() -if(BUILD_CURL_TESTS) + +include(CTest) +if(BUILD_TESTING) add_subdirectory(tests) endif() @@ -1038,7 +1056,8 @@ endfunction() # Clear list and try to detect available features set(_items) -_add_if("SSL" SSL_ENABLED) +_add_if("WinSSL" SSL_ENABLED AND USE_WINDOWS_SSPI) +_add_if("OpenSSL" SSL_ENABLED AND USE_OPENSSL) _add_if("IPv6" ENABLE_IPV6) _add_if("unix-sockets" USE_UNIX_SOCKETS) _add_if("libz" HAVE_LIBZ) @@ -1136,7 +1155,7 @@ set(VERSIONNUM "${CURL_VERSION_NUM}") # Finally generate a "curl-config" matching this config configure_file("${CURL_SOURCE_DIR}/curl-config.in" "${CURL_BINARY_DIR}/curl-config" @ONLY) -install(FILES "${CMAKE_BINARY_DIR}/curl-config" +install(FILES "${CURL_BINARY_DIR}/curl-config" DESTINATION bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE @@ -1146,7 +1165,7 @@ install(FILES "${CMAKE_BINARY_DIR}/curl-config" # Finally generate a pkg-config file matching this config configure_file("${CURL_SOURCE_DIR}/libcurl.pc.in" "${CURL_BINARY_DIR}/libcurl.pc" @ONLY) -install(FILES "${CMAKE_BINARY_DIR}/libcurl.pc" +install(FILES "${CURL_BINARY_DIR}/libcurl.pc" DESTINATION lib/pkgconfig) # This needs to be run very last so other parts of the scripts can take advantage of this. diff --git a/COPYING b/COPYING index 6b5d59f..a98663e 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,7 @@ COPYRIGHT AND PERMISSION NOTICE -Copyright (c) 1996 - 2015, Daniel Stenberg, . +Copyright (c) 1996 - 2016, Daniel Stenberg, , and many +contributors, see the THANKS file. All rights reserved. diff --git a/include/curl/curl.h b/include/curl/curl.h index 64f9261..7fd6d1f 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -24,10 +24,10 @@ /* * If you have libcurl problems, all docs and details are found here: - * http://curl.haxx.se/libcurl/ + * https://curl.haxx.se/libcurl/ * * curl-library mailing list subscription and unsubscription web interface: - * http://cool.haxx.se/mailman/listinfo/curl-library/ + * https://cool.haxx.se/mailman/listinfo/curl-library/ */ #include "curlver.h" /* libcurl version defines */ @@ -56,7 +56,8 @@ #include #if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) -#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || defined(__LWIP_OPT_H__)) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ + defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) /* The check above prevents the winsock2 inclusion if winsock.h already was included, since they can't co-exist without problems */ #include @@ -90,7 +91,13 @@ extern "C" { #endif +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_easy CURL; +typedef struct Curl_share CURLSH; +#else typedef void CURL; +typedef void CURLSH; +#endif /* * libcurl external API function linkage decorations. @@ -112,7 +119,7 @@ typedef void CURL; #ifndef curl_socket_typedef /* socket typedef */ -#if defined(WIN32) && !defined(__LWIP_OPT_H__) +#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) typedef SOCKET curl_socket_t; #define CURL_SOCKET_BAD INVALID_SOCKET #else @@ -127,7 +134,8 @@ struct curl_httppost { char *name; /* pointer to allocated name */ long namelength; /* length of name length */ char *contents; /* pointer to allocated data contents */ - long contentslength; /* length of contents field */ + long contentslength; /* length of contents field, see also + CURL_HTTPPOST_LARGE */ char *buffer; /* pointer to allocated buffer contents */ long bufferlength; /* length of buffer field */ char *contenttype; /* Content-Type */ @@ -136,24 +144,33 @@ struct curl_httppost { file, this link should link to following files */ long flags; /* as defined below */ -#define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */ -#define HTTPPOST_READFILE (1<<1) /* specified content is a file name */ -#define HTTPPOST_PTRNAME (1<<2) /* name is only stored pointer - do not free in formfree */ -#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer - do not free in formfree */ -#define HTTPPOST_BUFFER (1<<4) /* upload file from buffer */ -#define HTTPPOST_PTRBUFFER (1<<5) /* upload file from pointer contents */ -#define HTTPPOST_CALLBACK (1<<6) /* upload file contents by using the - regular read callback to get the data - and pass the given pointer as custom - pointer */ + +/* specified content is a file name */ +#define CURL_HTTPPOST_FILENAME (1<<0) +/* specified content is a file name */ +#define CURL_HTTPPOST_READFILE (1<<1) +/* name is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRNAME (1<<2) +/* contents is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRCONTENTS (1<<3) +/* upload file from buffer */ +#define CURL_HTTPPOST_BUFFER (1<<4) +/* upload file from pointer contents */ +#define CURL_HTTPPOST_PTRBUFFER (1<<5) +/* upload file contents by using the regular read callback to get the data and + pass the given pointer as custom pointer */ +#define CURL_HTTPPOST_CALLBACK (1<<6) +/* use size in 'contentlen', added in 7.46.0 */ +#define CURL_HTTPPOST_LARGE (1<<7) char *showfilename; /* The file name to show. If not set, the actual file name will be used (if this is a file part) */ void *userp; /* custom pointer used for HTTPPOST_CALLBACK posts */ + curl_off_t contentlen; /* alternative length of contents + field. Used if CURL_HTTPPOST_LARGE is + set. Added in 7.46.0 */ }; /* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered @@ -362,6 +379,7 @@ typedef curlioerr (*curl_ioctl_callback)(CURL *handle, int cmd, void *clientp); +#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* * The following typedef's are signatures of malloc, free, realloc, strdup and * calloc respectively. Function pointers of these types can be passed to the @@ -374,6 +392,9 @@ typedef void *(*curl_realloc_callback)(void *ptr, size_t size); typedef char *(*curl_strdup_callback)(const char *str); typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); +#define CURL_DID_MEMORY_FUNC_TYPEDEFS +#endif + /* the kind of data that is passed to information_callback*/ typedef enum { CURLINFO_TEXT = 0, @@ -460,9 +481,9 @@ typedef enum { CURLE_OBSOLETE44, /* 44 - NOT USED */ CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ CURLE_OBSOLETE46, /* 46 - NOT USED */ - CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */ + CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */ CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ - CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */ + CURLE_TELNET_OPTION_SYNTAX, /* 49 - Malformed telnet option */ CURLE_OBSOLETE50, /* 50 - NOT USED */ CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint wasn't verified fine */ @@ -524,6 +545,8 @@ typedef enum { CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not match */ CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ + CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer + */ CURL_LAST /* never use! */ } CURLcode; @@ -818,9 +841,13 @@ typedef enum { but 32 */ #define CURLOPTTYPE_LONG 0 #define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_STRINGPOINT 10000 #define CURLOPTTYPE_FUNCTIONPOINT 20000 #define CURLOPTTYPE_OFF_T 30000 +/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the + string options from the header file */ + /* name is uppercase CURLOPT_, type is one of the defined CURLOPTTYPE_ number is unique identifier */ @@ -834,6 +861,7 @@ typedef enum { /* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ #define LONG CURLOPTTYPE_LONG #define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define STRINGPOINT CURLOPTTYPE_OBJECTPOINT #define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT #define OFF_T CURLOPTTYPE_OFF_T #define CINIT(name,type,number) CURLOPT_/**/name = type + number @@ -850,22 +878,22 @@ typedef enum { CINIT(WRITEDATA, OBJECTPOINT, 1), /* The full URL to get/put */ - CINIT(URL, OBJECTPOINT, 2), + CINIT(URL, STRINGPOINT, 2), /* Port number to connect to, if other than default. */ CINIT(PORT, LONG, 3), /* Name of proxy to use. */ - CINIT(PROXY, OBJECTPOINT, 4), + CINIT(PROXY, STRINGPOINT, 4), /* "user:password;options" to use when fetching. */ - CINIT(USERPWD, OBJECTPOINT, 5), + CINIT(USERPWD, STRINGPOINT, 5), /* "user:password" to use with proxy. */ - CINIT(PROXYUSERPWD, OBJECTPOINT, 6), + CINIT(PROXYUSERPWD, STRINGPOINT, 6), /* Range to get, specified as an ASCII string. */ - CINIT(RANGE, OBJECTPOINT, 7), + CINIT(RANGE, STRINGPOINT, 7), /* not used */ @@ -902,14 +930,14 @@ typedef enum { CINIT(POSTFIELDS, OBJECTPOINT, 15), /* Set the referrer page (needed by some CGIs) */ - CINIT(REFERER, OBJECTPOINT, 16), + CINIT(REFERER, STRINGPOINT, 16), /* Set the FTP PORT string (interface name, named or numerical IP address) Use i.e '-' to use default address. */ - CINIT(FTPPORT, OBJECTPOINT, 17), + CINIT(FTPPORT, STRINGPOINT, 17), /* Set the User-Agent string (examined by some CGIs) */ - CINIT(USERAGENT, OBJECTPOINT, 18), + CINIT(USERAGENT, STRINGPOINT, 18), /* If the download receives less than "low speed limit" bytes/second * during "low speed time" seconds, the operations is aborted. @@ -932,7 +960,7 @@ typedef enum { CINIT(RESUME_FROM, LONG, 21), /* Set cookie in request: */ - CINIT(COOKIE, OBJECTPOINT, 22), + CINIT(COOKIE, STRINGPOINT, 22), /* This points to a linked list of headers, struct curl_slist kind. This list is also used for RTSP (in spite of its name) */ @@ -942,10 +970,10 @@ typedef enum { CINIT(HTTPPOST, OBJECTPOINT, 24), /* name of the file keeping your private SSL-certificate */ - CINIT(SSLCERT, OBJECTPOINT, 25), + CINIT(SSLCERT, STRINGPOINT, 25), /* password for the SSL or SSH private key */ - CINIT(KEYPASSWD, OBJECTPOINT, 26), + CINIT(KEYPASSWD, STRINGPOINT, 26), /* send TYPE parameter? */ CINIT(CRLF, LONG, 27), @@ -959,7 +987,7 @@ typedef enum { /* point to a file to read the initial cookies from, also enables "cookie awareness" */ - CINIT(COOKIEFILE, OBJECTPOINT, 31), + CINIT(COOKIEFILE, STRINGPOINT, 31), /* What version to specifically try to use. See CURL_SSLVERSION defines below. */ @@ -978,9 +1006,9 @@ typedef enum { HTTP: DELETE, TRACE and others FTP: to use a different list command */ - CINIT(CUSTOMREQUEST, OBJECTPOINT, 36), + CINIT(CUSTOMREQUEST, STRINGPOINT, 36), - /* HTTP request, for odd commands like DELETE, TRACE and others */ + /* FILE handle to use instead of stderr */ CINIT(STDERR, OBJECTPOINT, 37), /* 38 is not used */ @@ -1037,19 +1065,19 @@ typedef enum { CINIT(HTTPPROXYTUNNEL, LONG, 61), /* Set the interface string to use as outgoing network interface */ - CINIT(INTERFACE, OBJECTPOINT, 62), + CINIT(INTERFACE, STRINGPOINT, 62), /* Set the krb4/5 security level, this also enables krb4/5 awareness. This * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string * is set but doesn't match one of these, 'private' will be used. */ - CINIT(KRBLEVEL, OBJECTPOINT, 63), + CINIT(KRBLEVEL, STRINGPOINT, 63), /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ CINIT(SSL_VERIFYPEER, LONG, 64), /* The CApath or CAfile used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ - CINIT(CAINFO, OBJECTPOINT, 65), + CINIT(CAINFO, STRINGPOINT, 65), /* 66 = OBSOLETE */ /* 67 = OBSOLETE */ @@ -1083,10 +1111,10 @@ typedef enum { /* Set to a file name that contains random data for libcurl to use to seed the random engine when doing SSL connects. */ - CINIT(RANDOM_FILE, OBJECTPOINT, 76), + CINIT(RANDOM_FILE, STRINGPOINT, 76), /* Set to the Entropy Gathering Daemon socket pathname */ - CINIT(EGDSOCKET, OBJECTPOINT, 77), + CINIT(EGDSOCKET, STRINGPOINT, 77), /* Time-out connect operations after this amount of seconds, if connects are OK within this time, then fine... This only aborts the connect phase. */ @@ -1108,10 +1136,10 @@ typedef enum { /* Specify which file name to write all known cookies in after completed operation. Set file name to "-" (dash) to make it go to stdout. */ - CINIT(COOKIEJAR, OBJECTPOINT, 82), + CINIT(COOKIEJAR, STRINGPOINT, 82), /* Specify which SSL ciphers to use */ - CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83), + CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83), /* Specify which HTTP version to use! This must be set to one of the CURL_HTTP_VERSION* enums set below. */ @@ -1123,16 +1151,16 @@ typedef enum { CINIT(FTP_USE_EPSV, LONG, 85), /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ - CINIT(SSLCERTTYPE, OBJECTPOINT, 86), + CINIT(SSLCERTTYPE, STRINGPOINT, 86), /* name of the file keeping your private SSL-key */ - CINIT(SSLKEY, OBJECTPOINT, 87), + CINIT(SSLKEY, STRINGPOINT, 87), /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ - CINIT(SSLKEYTYPE, OBJECTPOINT, 88), + CINIT(SSLKEYTYPE, STRINGPOINT, 88), /* crypto engine for the SSL-sub system */ - CINIT(SSLENGINE, OBJECTPOINT, 89), + CINIT(SSLENGINE, STRINGPOINT, 89), /* set the crypto engine for the SSL-sub system as default the param has no meaning... @@ -1159,7 +1187,7 @@ typedef enum { /* The CApath directory used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ - CINIT(CAPATH, OBJECTPOINT, 97), + CINIT(CAPATH, STRINGPOINT, 97), /* Instruct libcurl to use a smaller receive buffer */ CINIT(BUFFERSIZE, LONG, 98), @@ -1179,7 +1207,7 @@ typedef enum { /* Set the Accept-Encoding string. Use this to tell a server you would like the response to be compressed. Before 7.21.6, this was known as CURLOPT_ENCODING */ - CINIT(ACCEPT_ENCODING, OBJECTPOINT, 102), + CINIT(ACCEPT_ENCODING, STRINGPOINT, 102), /* Set pointer to private data */ CINIT(PRIVATE, OBJECTPOINT, 103), @@ -1260,7 +1288,7 @@ typedef enum { to parse (using the CURLOPT_NETRC option). If not set, libcurl will do a poor attempt to find the user's home directory and check for a .netrc file in there. */ - CINIT(NETRC_FILE, OBJECTPOINT, 118), + CINIT(NETRC_FILE, STRINGPOINT, 118), /* Enable SSL/TLS for FTP, pick one of: CURLUSESSL_TRY - try using SSL, proceed anyway otherwise @@ -1303,10 +1331,10 @@ typedef enum { /* zero terminated string for pass on to the FTP server when asked for "account" info */ - CINIT(FTP_ACCOUNT, OBJECTPOINT, 134), + CINIT(FTP_ACCOUNT, STRINGPOINT, 134), - /* feed cookies into cookie engine */ - CINIT(COOKIELIST, OBJECTPOINT, 135), + /* feed cookie into cookie engine */ + CINIT(COOKIELIST, STRINGPOINT, 135), /* ignore Content-Length */ CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), @@ -1352,7 +1380,7 @@ typedef enum { CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), /* Pointer to command string to send if USER/PASS fails. */ - CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147), + CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147), /* callback function for setting socket options */ CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), @@ -1366,8 +1394,8 @@ typedef enum { CINIT(SSH_AUTH_TYPES, LONG, 151), /* Used by scp/sftp to do public/private key authentication */ - CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152), - CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153), + CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152), + CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153), /* Send CCC (Clear Command Channel) after authentication */ CINIT(FTP_SSL_CCC, LONG, 154), @@ -1391,7 +1419,7 @@ typedef enum { CINIT(POSTREDIR, LONG, 161), /* used by scp/sftp to verify the host's public key */ - CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162), + CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162), /* Callback function for opening socket (instead of socket(2)). Optionally, callback is able change the address or refuse to connect returning @@ -1411,10 +1439,10 @@ typedef enum { CINIT(SEEKDATA, OBJECTPOINT, 168), /* CRL file */ - CINIT(CRLFILE, OBJECTPOINT, 169), + CINIT(CRLFILE, STRINGPOINT, 169), /* Issuer certificate */ - CINIT(ISSUERCERT, OBJECTPOINT, 170), + CINIT(ISSUERCERT, STRINGPOINT, 170), /* (IPv6) Address scope */ CINIT(ADDRESS_SCOPE, LONG, 171), @@ -1424,12 +1452,12 @@ typedef enum { CINIT(CERTINFO, LONG, 172), /* "name" and "pwd" to use when fetching. */ - CINIT(USERNAME, OBJECTPOINT, 173), - CINIT(PASSWORD, OBJECTPOINT, 174), + CINIT(USERNAME, STRINGPOINT, 173), + CINIT(PASSWORD, STRINGPOINT, 174), /* "name" and "pwd" to use with Proxy when fetching. */ - CINIT(PROXYUSERNAME, OBJECTPOINT, 175), - CINIT(PROXYPASSWORD, OBJECTPOINT, 176), + CINIT(PROXYUSERNAME, STRINGPOINT, 175), + CINIT(PROXYPASSWORD, STRINGPOINT, 176), /* Comma separated list of hostnames defining no-proxy zones. These should match both hostnames directly, and hostnames within a domain. For @@ -1438,13 +1466,13 @@ typedef enum { implementations of this, .local.com will be considered to be the same as local.com. A single * is the only valid wildcard, and effectively disables the use of proxy. */ - CINIT(NOPROXY, OBJECTPOINT, 177), + CINIT(NOPROXY, STRINGPOINT, 177), /* block size for TFTP transfers */ CINIT(TFTP_BLKSIZE, LONG, 178), /* Socks Service */ - CINIT(SOCKS5_GSSAPI_SERVICE, OBJECTPOINT, 179), + CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */ /* Socks Service */ CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), @@ -1462,7 +1490,7 @@ typedef enum { CINIT(REDIR_PROTOCOLS, LONG, 182), /* set the SSH knownhost file name to use */ - CINIT(SSH_KNOWNHOSTS, OBJECTPOINT, 183), + CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183), /* set the SSH host key callback, must point to a curl_sshkeycallback function */ @@ -1472,9 +1500,9 @@ typedef enum { CINIT(SSH_KEYDATA, OBJECTPOINT, 185), /* set the SMTP mail originator */ - CINIT(MAIL_FROM, OBJECTPOINT, 186), + CINIT(MAIL_FROM, STRINGPOINT, 186), - /* set the SMTP mail receiver(s) */ + /* set the list of SMTP mail receiver(s) */ CINIT(MAIL_RCPT, OBJECTPOINT, 187), /* FTP: send PRET before PASV */ @@ -1484,13 +1512,13 @@ typedef enum { CINIT(RTSP_REQUEST, LONG, 189), /* The RTSP session identifier */ - CINIT(RTSP_SESSION_ID, OBJECTPOINT, 190), + CINIT(RTSP_SESSION_ID, STRINGPOINT, 190), /* The RTSP stream URI */ - CINIT(RTSP_STREAM_URI, OBJECTPOINT, 191), + CINIT(RTSP_STREAM_URI, STRINGPOINT, 191), /* The Transport: header to use in RTSP requests */ - CINIT(RTSP_TRANSPORT, OBJECTPOINT, 192), + CINIT(RTSP_TRANSPORT, STRINGPOINT, 192), /* Manually initialize the client RTSP CSeq for this handle */ CINIT(RTSP_CLIENT_CSEQ, LONG, 193), @@ -1528,13 +1556,13 @@ typedef enum { CINIT(RESOLVE, OBJECTPOINT, 203), /* Set a username for authenticated TLS */ - CINIT(TLSAUTH_USERNAME, OBJECTPOINT, 204), + CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204), /* Set a password for authenticated TLS */ - CINIT(TLSAUTH_PASSWORD, OBJECTPOINT, 205), + CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205), /* Set authentication type for authenticated TLS */ - CINIT(TLSAUTH_TYPE, OBJECTPOINT, 206), + CINIT(TLSAUTH_TYPE, STRINGPOINT, 206), /* Set to 1 to enable the "TE:" header in HTTP requests to ask for compressed transfer-encoded responses. Set to 0 to disable the use of TE: @@ -1557,7 +1585,7 @@ typedef enum { CINIT(GSSAPI_DELEGATION, LONG, 210), /* Set the name servers to use for DNS resolution */ - CINIT(DNS_SERVERS, OBJECTPOINT, 211), + CINIT(DNS_SERVERS, STRINGPOINT, 211), /* Time-out accept operations (currently for FTP only) after this amount of miliseconds. */ @@ -1574,7 +1602,7 @@ typedef enum { CINIT(SSL_OPTIONS, LONG, 216), /* Set the SMTP auth originator */ - CINIT(MAIL_AUTH, OBJECTPOINT, 217), + CINIT(MAIL_AUTH, STRINGPOINT, 217), /* Enable/disable SASL initial response */ CINIT(SASL_IR, LONG, 218), @@ -1585,23 +1613,23 @@ typedef enum { CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), /* The XOAUTH2 bearer token */ - CINIT(XOAUTH2_BEARER, OBJECTPOINT, 220), + CINIT(XOAUTH2_BEARER, STRINGPOINT, 220), /* Set the interface string to use as outgoing network * interface for DNS requests. * Only supported by the c-ares DNS backend */ - CINIT(DNS_INTERFACE, OBJECTPOINT, 221), + CINIT(DNS_INTERFACE, STRINGPOINT, 221), /* Set the local IPv4 address to use for outgoing DNS requests. * Only supported by the c-ares DNS backend */ - CINIT(DNS_LOCAL_IP4, OBJECTPOINT, 222), + CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222), /* Set the local IPv4 address to use for outgoing DNS requests. * Only supported by the c-ares DNS backend */ - CINIT(DNS_LOCAL_IP6, OBJECTPOINT, 223), + CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223), /* Set authentication options directly */ - CINIT(LOGIN_OPTIONS, OBJECTPOINT, 224), + CINIT(LOGIN_OPTIONS, STRINGPOINT, 224), /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ CINIT(SSL_ENABLE_NPN, LONG, 225), @@ -1622,10 +1650,10 @@ typedef enum { /* The public key in DER form used to validate the peer public key this option is used only if SSL_VERIFYPEER is true */ - CINIT(PINNEDPUBLICKEY, OBJECTPOINT, 230), + CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230), /* Path to Unix domain socket */ - CINIT(UNIX_SOCKET_PATH, OBJECTPOINT, 231), + CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231), /* Set if we should verify the certificate status. */ CINIT(SSL_VERIFYSTATUS, LONG, 232), @@ -1637,14 +1665,36 @@ typedef enum { CINIT(PATH_AS_IS, LONG, 234), /* Proxy Service Name */ - CINIT(PROXY_SERVICE_NAME, OBJECTPOINT, 235), + CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235), /* Service Name */ - CINIT(SERVICE_NAME, OBJECTPOINT, 236), + CINIT(SERVICE_NAME, STRINGPOINT, 236), /* Wait/don't wait for pipe/mutex to clarify */ CINIT(PIPEWAIT, LONG, 237), + /* Set the protocol used when curl is given a URL without a protocol */ + CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238), + + /* Set stream weight, 1 - 256 (default is 16) */ + CINIT(STREAM_WEIGHT, LONG, 239), + + /* Set stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS, OBJECTPOINT, 240), + + /* Set E-xclusive stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241), + + /* Do not send any tftp option requests to the server */ + CINIT(TFTP_NO_OPTIONS, LONG, 242), + + /* Linked-list of host:port:connect-to-host:connect-to-port, + overrides the URL's host:port (only for the network layer) */ + CINIT(CONNECT_TO, OBJECTPOINT, 243), + + /* Set TCP Fast Open */ + CINIT(TCP_FASTOPEN, LONG, 244), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -1694,7 +1744,10 @@ enum { for us! */ CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ - CURL_HTTP_VERSION_2_0, /* please use HTTP 2.0 in the request */ + CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ + CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ + CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1 + Upgrade */ CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ }; @@ -1819,6 +1872,7 @@ typedef enum { CFINIT(OBSOLETE2), CFINIT(STREAM), + CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */ CURLFORM_LASTENTRY /* the last unused */ } CURLformoption; @@ -2073,12 +2127,18 @@ typedef enum { CURLSSLBACKEND_CYASSL = 7, CURLSSLBACKEND_SCHANNEL = 8, CURLSSLBACKEND_DARWINSSL = 9, - CURLSSLBACKEND_AXTLS = 10 + CURLSSLBACKEND_AXTLS = 10, + CURLSSLBACKEND_MBEDTLS = 11 } curl_sslbackend; +/* aliases for library clones and renames */ +#define CURLSSLBACKEND_LIBRESSL 1 +#define CURLSSLBACKEND_BORINGSSL 1 +#define CURLSSLBACKEND_WOLFSSL 6 + /* Information about the SSL library used and the respective internal SSL handle, which can be used to obtain further information regarding the - connection. Asked for with CURLINFO_TLS_SESSION. */ + connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ struct curl_tlssessioninfo { curl_sslbackend backend; void *internals; @@ -2088,6 +2148,7 @@ struct curl_tlssessioninfo { #define CURLINFO_LONG 0x200000 #define CURLINFO_DOUBLE 0x300000 #define CURLINFO_SLIST 0x400000 +#define CURLINFO_SOCKET 0x500000 #define CURLINFO_MASK 0x0fffff #define CURLINFO_TYPEMASK 0xf00000 @@ -2136,9 +2197,12 @@ typedef enum { CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, CURLINFO_TLS_SESSION = CURLINFO_SLIST + 43, + CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, + CURLINFO_TLS_SSL_PTR = CURLINFO_SLIST + 45, + CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, /* Fill in new entries below here! */ - CURLINFO_LASTONE = 43 + CURLINFO_LASTONE = 46 } CURLINFO; /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as @@ -2200,7 +2264,6 @@ typedef void (*curl_unlock_function)(CURL *handle, curl_lock_data data, void *userptr); -typedef void CURLSH; typedef enum { CURLSHE_OK, /* all is fine */ @@ -2298,6 +2361,8 @@ typedef struct { #define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ #define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ #define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ +#define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used + for cookie domain verification */ /* * NAME curl_version_info() diff --git a/include/curl/curlbuild.h.cmake b/include/curl/curlbuild.h.cmake index 60bc7a7..bbb31a9 100644 --- a/include/curl/curlbuild.h.cmake +++ b/include/curl/curlbuild.h.cmake @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -35,7 +35,7 @@ * * If you think that something actually needs to be changed, adjusted * or fixed in this file, then, report it on the libcurl development - * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/ + * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/ * * This header file shall only export symbols which are 'curl' or 'CURL' * prefixed, otherwise public name space would be polluted. diff --git a/include/curl/curlrules.h b/include/curl/curlrules.h index 7c2ede3..55d21f6 100644 --- a/include/curl/curlrules.h +++ b/include/curl/curlrules.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -47,7 +47,7 @@ * library is properly built and used. * * You can find further help on the libcurl development mailing list: - * http://cool.haxx.se/mailman/listinfo/curl-library/ + * https://cool.haxx.se/mailman/listinfo/curl-library/ * * NOTE 2 * ------ diff --git a/include/curl/curlver.h b/include/curl/curlver.h index f73d7de..81563f2 100644 --- a/include/curl/curlver.h +++ b/include/curl/curlver.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,17 +26,17 @@ a script at release-time. This was made its own header file in 7.11.2 */ /* This is the global package copyright */ -#define LIBCURL_COPYRIGHT "1996 - 2015 Daniel Stenberg, ." +#define LIBCURL_COPYRIGHT "1996 - 2016 Daniel Stenberg, ." /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.44.0-DEV" +#define LIBCURL_VERSION "7.50.1-DEV" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 44 -#define LIBCURL_VERSION_PATCH 0 +#define LIBCURL_VERSION_MINOR 50 +#define LIBCURL_VERSION_PATCH 1 /* This is the numeric version of the libcurl version number, meant for easier parsing and comparions by programs. The LIBCURL_VERSION_NUM define will @@ -57,7 +57,7 @@ CURL_VERSION_BITS() macro since curl's own configure script greps for it and needs it to contain the full number. */ -#define LIBCURL_VERSION_NUM 0x072C00 +#define LIBCURL_VERSION_NUM 0x073201 /* * This is the date and time when the full source package was created. The diff --git a/include/curl/easy.h b/include/curl/easy.h index c1e3e76..afc766c 100644 --- a/include/curl/easy.h +++ b/include/curl/easy.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/include/curl/mprintf.h b/include/curl/mprintf.h index c6b0d76..e20f546 100644 --- a/include/curl/mprintf.h +++ b/include/curl/mprintf.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -24,8 +24,7 @@ #include #include /* needed for FILE */ - -#include "curl.h" +#include "curl.h" /* for CURL_EXTERN */ #ifdef __cplusplus extern "C" { @@ -44,29 +43,6 @@ CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, CURL_EXTERN char *curl_maprintf(const char *format, ...); CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); -#ifdef _MPRINTF_REPLACE -# undef printf -# undef fprintf -# undef sprintf -# undef vsprintf -# undef snprintf -# undef vprintf -# undef vfprintf -# undef vsnprintf -# undef aprintf -# undef vaprintf -# define printf curl_mprintf -# define fprintf curl_mfprintf -# define sprintf curl_msprintf -# define vsprintf curl_mvsprintf -# define snprintf curl_msnprintf -# define vprintf curl_mvprintf -# define vfprintf curl_mvfprintf -# define vsnprintf curl_mvsnprintf -# define aprintf curl_maprintf -# define vaprintf curl_mvaprintf -#endif - #ifdef __cplusplus } #endif diff --git a/include/curl/multi.h b/include/curl/multi.h index 36e2e94..d1e00cc 100644 --- a/include/curl/multi.h +++ b/include/curl/multi.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -52,7 +52,11 @@ extern "C" { #endif +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_multi CURLM; +#else typedef void CURLM; +#endif typedef enum { CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or diff --git a/include/curl/stdcheaders.h b/include/curl/stdcheaders.h index ad82ef6..6f0f7f3 100644 --- a/include/curl/stdcheaders.h +++ b/include/curl/stdcheaders.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h index 13fb0fa..6ec8bcf 100644 --- a/include/curl/typecheck-gcc.h +++ b/include/curl/typecheck-gcc.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -218,60 +218,67 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, /* evaluates to true if option takes a char* argument */ #define _curl_is_string_option(option) \ - ((option) == CURLOPT_URL || \ - (option) == CURLOPT_PROXY || \ - (option) == CURLOPT_INTERFACE || \ - (option) == CURLOPT_NETRC_FILE || \ - (option) == CURLOPT_USERPWD || \ - (option) == CURLOPT_USERNAME || \ - (option) == CURLOPT_PASSWORD || \ - (option) == CURLOPT_PROXYUSERPWD || \ - (option) == CURLOPT_PROXYUSERNAME || \ - (option) == CURLOPT_PROXYPASSWORD || \ - (option) == CURLOPT_NOPROXY || \ - (option) == CURLOPT_ACCEPT_ENCODING || \ - (option) == CURLOPT_REFERER || \ - (option) == CURLOPT_USERAGENT || \ + ((option) == CURLOPT_ACCEPT_ENCODING || \ + (option) == CURLOPT_CAINFO || \ + (option) == CURLOPT_CAPATH || \ (option) == CURLOPT_COOKIE || \ (option) == CURLOPT_COOKIEFILE || \ (option) == CURLOPT_COOKIEJAR || \ (option) == CURLOPT_COOKIELIST || \ + (option) == CURLOPT_CRLFILE || \ + (option) == CURLOPT_CUSTOMREQUEST || \ + (option) == CURLOPT_DEFAULT_PROTOCOL || \ + (option) == CURLOPT_DNS_INTERFACE || \ + (option) == CURLOPT_DNS_LOCAL_IP4 || \ + (option) == CURLOPT_DNS_LOCAL_IP6 || \ + (option) == CURLOPT_DNS_SERVERS || \ + (option) == CURLOPT_EGDSOCKET || \ (option) == CURLOPT_FTPPORT || \ - (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ (option) == CURLOPT_FTP_ACCOUNT || \ - (option) == CURLOPT_RANGE || \ - (option) == CURLOPT_CUSTOMREQUEST || \ - (option) == CURLOPT_SSLCERT || \ - (option) == CURLOPT_SSLCERTTYPE || \ - (option) == CURLOPT_SSLKEY || \ - (option) == CURLOPT_SSLKEYTYPE || \ + (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ + (option) == CURLOPT_INTERFACE || \ + (option) == CURLOPT_ISSUERCERT || \ (option) == CURLOPT_KEYPASSWD || \ - (option) == CURLOPT_SSLENGINE || \ - (option) == CURLOPT_CAINFO || \ - (option) == CURLOPT_CAPATH || \ - (option) == CURLOPT_RANDOM_FILE || \ - (option) == CURLOPT_EGDSOCKET || \ - (option) == CURLOPT_SSL_CIPHER_LIST || \ (option) == CURLOPT_KRBLEVEL || \ - (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ - (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ - (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ - (option) == CURLOPT_CRLFILE || \ - (option) == CURLOPT_ISSUERCERT || \ - (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ - (option) == CURLOPT_SSH_KNOWNHOSTS || \ + (option) == CURLOPT_LOGIN_OPTIONS || \ + (option) == CURLOPT_MAIL_AUTH || \ (option) == CURLOPT_MAIL_FROM || \ + (option) == CURLOPT_NETRC_FILE || \ + (option) == CURLOPT_NOPROXY || \ + (option) == CURLOPT_PASSWORD || \ + (option) == CURLOPT_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PROXY || \ + (option) == CURLOPT_PROXYPASSWORD || \ + (option) == CURLOPT_PROXYUSERNAME || \ + (option) == CURLOPT_PROXYUSERPWD || \ + (option) == CURLOPT_PROXY_SERVICE_NAME || \ + (option) == CURLOPT_RANDOM_FILE || \ + (option) == CURLOPT_RANGE || \ + (option) == CURLOPT_REFERER || \ (option) == CURLOPT_RTSP_SESSION_ID || \ (option) == CURLOPT_RTSP_STREAM_URI || \ (option) == CURLOPT_RTSP_TRANSPORT || \ - (option) == CURLOPT_XOAUTH2_BEARER || \ - (option) == CURLOPT_DNS_SERVERS || \ - (option) == CURLOPT_DNS_INTERFACE || \ - (option) == CURLOPT_DNS_LOCAL_IP4 || \ - (option) == CURLOPT_DNS_LOCAL_IP6 || \ - (option) == CURLOPT_LOGIN_OPTIONS || \ - (option) == CURLOPT_PROXY_SERVICE_NAME || \ (option) == CURLOPT_SERVICE_NAME || \ + (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ + (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ + (option) == CURLOPT_SSH_KNOWNHOSTS || \ + (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ + (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ + (option) == CURLOPT_SSLCERT || \ + (option) == CURLOPT_SSLCERTTYPE || \ + (option) == CURLOPT_SSLENGINE || \ + (option) == CURLOPT_SSLKEY || \ + (option) == CURLOPT_SSLKEYTYPE || \ + (option) == CURLOPT_SSL_CIPHER_LIST || \ + (option) == CURLOPT_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_TLSAUTH_TYPE || \ + (option) == CURLOPT_TLSAUTH_USERNAME || \ + (option) == CURLOPT_UNIX_SOCKET_PATH || \ + (option) == CURLOPT_URL || \ + (option) == CURLOPT_USERAGENT || \ + (option) == CURLOPT_USERNAME || \ + (option) == CURLOPT_USERPWD || \ + (option) == CURLOPT_XOAUTH2_BEARER || \ 0) /* evaluates to true if option takes a curl_write_callback argument */ @@ -287,21 +294,22 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, /* evaluates to true if option takes a data argument to pass to a callback */ #define _curl_is_cb_data_option(option) \ - ((option) == CURLOPT_WRITEDATA || \ - (option) == CURLOPT_READDATA || \ + ((option) == CURLOPT_CHUNK_DATA || \ + (option) == CURLOPT_CLOSESOCKETDATA || \ + (option) == CURLOPT_DEBUGDATA || \ + (option) == CURLOPT_FNMATCH_DATA || \ + (option) == CURLOPT_HEADERDATA || \ + (option) == CURLOPT_INTERLEAVEDATA || \ (option) == CURLOPT_IOCTLDATA || \ - (option) == CURLOPT_SOCKOPTDATA || \ (option) == CURLOPT_OPENSOCKETDATA || \ + (option) == CURLOPT_PRIVATE || \ (option) == CURLOPT_PROGRESSDATA || \ - (option) == CURLOPT_HEADERDATA || \ - (option) == CURLOPT_DEBUGDATA || \ - (option) == CURLOPT_SSL_CTX_DATA || \ + (option) == CURLOPT_READDATA || \ (option) == CURLOPT_SEEKDATA || \ - (option) == CURLOPT_PRIVATE || \ + (option) == CURLOPT_SOCKOPTDATA || \ (option) == CURLOPT_SSH_KEYDATA || \ - (option) == CURLOPT_INTERLEAVEDATA || \ - (option) == CURLOPT_CHUNK_DATA || \ - (option) == CURLOPT_FNMATCH_DATA || \ + (option) == CURLOPT_SSL_CTX_DATA || \ + (option) == CURLOPT_WRITEDATA || \ 0) /* evaluates to true if option takes a POST data argument (void* or char*) */ @@ -312,13 +320,15 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, /* evaluates to true if option takes a struct curl_slist * argument */ #define _curl_is_slist_option(option) \ - ((option) == CURLOPT_HTTPHEADER || \ - (option) == CURLOPT_HTTP200ALIASES || \ - (option) == CURLOPT_QUOTE || \ + ((option) == CURLOPT_HTTP200ALIASES || \ + (option) == CURLOPT_HTTPHEADER || \ + (option) == CURLOPT_MAIL_RCPT || \ (option) == CURLOPT_POSTQUOTE || \ (option) == CURLOPT_PREQUOTE || \ + (option) == CURLOPT_PROXYHEADER || \ + (option) == CURLOPT_QUOTE || \ + (option) == CURLOPT_RESOLVE || \ (option) == CURLOPT_TELNETOPTIONS || \ - (option) == CURLOPT_MAIL_RCPT || \ 0) /* groups of curl_easy_getinfo infos that take the same type of argument */ diff --git a/lib/Makefile.inc b/lib/Makefile.inc index d444a6b..0ed998c 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -5,11 +5,11 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms -# are also available at http://curl.haxx.se/docs/copyright.html. +# are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is @@ -20,13 +20,22 @@ # ########################################################################### +LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \ + vauth/digest.c vauth/digest_sspi.c vauth/krb5_gssapi.c \ + vauth/krb5_sspi.c vauth/ntlm.c vauth/ntlm_sspi.c vauth/oauth2.c \ + vauth/spnego_gssapi.c vauth/spnego_sspi.c + +LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h + LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ vtls/polarssl.c vtls/polarssl_threadlock.c vtls/axtls.c \ - vtls/cyassl.c vtls/schannel.c vtls/darwinssl.c vtls/gskit.c + vtls/cyassl.c vtls/schannel.c vtls/darwinssl.c vtls/gskit.c \ + vtls/mbedtls.c LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \ vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h vtls/axtls.h \ - vtls/cyassl.h vtls/schannel.h vtls/darwinssl.h vtls/gskit.h + vtls/cyassl.h vtls/schannel.h vtls/darwinssl.h vtls/gskit.h \ + vtls/mbedtls.h LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ @@ -41,12 +50,10 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c \ pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \ openldap.c curl_gethostname.c gopher.c idn_win32.c \ - http_negotiate_sspi.c http_proxy.c non-ascii.c asyn-ares.c \ - asyn-thread.c curl_gssapi.c curl_ntlm.c curl_ntlm_wb.c \ - curl_ntlm_core.c curl_ntlm_msgs.c curl_sasl.c curl_multibyte.c \ - hostcheck.c conncache.c pipeline.c dotdot.c x509asn1.c \ - http2.c curl_sasl_sspi.c smb.c curl_sasl_gssapi.c curl_endian.c \ - curl_des.c + http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c \ + http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c \ + curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c \ + x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ @@ -61,13 +68,13 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ slist.h nonblock.h curl_memrchr.h imap.h pop3.h smtp.h pingpong.h \ rtsp.h curl_threads.h warnless.h curl_hmac.h curl_rtmp.h \ curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \ - curl_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \ - curl_ntlm_msgs.h curl_sasl.h curl_multibyte.h hostcheck.h \ - conncache.h curl_setup_once.h multihandle.h setup-vms.h pipeline.h \ - dotdot.h x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ - curl_printf.h + http_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \ + curl_sasl.h curl_multibyte.h hostcheck.h conncache.h \ + curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h \ + x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ + curl_printf.h system_win32.h LIB_RCFILES = libcurl.rc -CSOURCES = $(LIB_CFILES) $(LIB_VTLS_CFILES) -HHEADERS = $(LIB_HFILES) $(LIB_VTLS_HFILES) +CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) +HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) diff --git a/lib/amigaos.c b/lib/amigaos.c index e3ff85f..5591d22 100644 --- a/lib/amigaos.c +++ b/lib/amigaos.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -35,7 +35,7 @@ extern int errno, h_errno; #include void __request(const char *msg); #else -# define __request( msg ) Printf( msg "\n\a") +# define __request(msg) Printf(msg "\n\a") #endif void Curl_amiga_cleanup() diff --git a/lib/amigaos.h b/lib/amigaos.h index 76578be..02bee16 100644 --- a/lib/amigaos.h +++ b/lib/amigaos.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/arpa_telnet.h b/lib/arpa_telnet.h index 098d9a9..ec23872 100644 --- a/lib/arpa_telnet.h +++ b/lib/arpa_telnet.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 98ecdfd..2aed94f 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -68,7 +68,6 @@ #include "connect.h" #include "select.h" #include "progress.h" -#include "curl_printf.h" # if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) @@ -83,8 +82,9 @@ #define HAVE_CARES_CALLBACK_TIMEOUTS 1 #endif +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" struct ResolverResults { @@ -249,7 +249,7 @@ int Curl_resolver_getsock(struct connectdata *conn, static int waitperform(struct connectdata *conn, int timeout_ms) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int nfds; int bitmask; ares_socket_t socks[ARES_GETSOCK_MAXNUM]; @@ -309,7 +309,7 @@ static int waitperform(struct connectdata *conn, int timeout_ms) CURLcode Curl_resolver_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dns) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ResolverResults *res = (struct ResolverResults *) conn->async.os_specific; CURLcode result = CURLE_OK; @@ -353,7 +353,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, struct Curl_dns_entry **entry) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; long timeout; struct timeval now = Curl_tvnow(); struct Curl_dns_entry *temp_entry; @@ -492,7 +492,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, int *waitp) { char *bufp; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct in_addr in; int family = PF_INET; #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ @@ -583,7 +583,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, return NULL; /* no struct yet */ } -CURLcode Curl_set_dns_servers(struct SessionHandle *data, +CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers) { CURLcode result = CURLE_NOT_BUILT_IN; @@ -621,7 +621,7 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data, return result; } -CURLcode Curl_set_dns_interface(struct SessionHandle *data, +CURLcode Curl_set_dns_interface(struct Curl_easy *data, const char *interf) { #if (ARES_VERSION >= 0x010704) @@ -638,7 +638,7 @@ CURLcode Curl_set_dns_interface(struct SessionHandle *data, #endif } -CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, const char *local_ip4) { #if (ARES_VERSION >= 0x010704) @@ -663,7 +663,7 @@ CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, #endif } -CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, const char *local_ip6) { #if (ARES_VERSION >= 0x010704) && defined(ENABLE_IPV6) diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c index bd47d5a..7cce01a 100644 --- a/lib/asyn-thread.c +++ b/lib/asyn-thread.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -69,10 +69,9 @@ #include "inet_ntop.h" #include "curl_threads.h" #include "connect.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" - -/* The last #include file should be: */ #include "memdebug.h" /*********************************************************************** @@ -280,6 +279,9 @@ static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg) if(tsd->sock_error == 0) tsd->sock_error = RESOLVER_ENOMEM; } + else { + Curl_addrinfo_set_port(tsd->res, tsd->port); + } Curl_mutex_acquire(tsd->mtx); if(tsd->done) { @@ -495,7 +497,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, CURLcode Curl_resolver_is_resolved(struct connectdata *conn, struct Curl_dns_entry **entry) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct thread_data *td = (struct thread_data*) conn->async.os_specific; int done = 0; @@ -603,6 +605,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, *waitp = 0; /* default to synchronous response */ +#ifndef USE_RESOLVE_ON_IPS /* First check if this is an IPv4 address string */ if(Curl_inet_pton(AF_INET, hostname, &in) > 0) /* This is a dotted IP address 123.123.123.123-style */ @@ -610,10 +613,13 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, #ifdef CURLRES_IPV6 /* check if this is an IPv6 address string */ - if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0) + if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) /* This is an IPv6 address literal */ return Curl_ip2addr(AF_INET6, &in6, hostname, port); +#endif /* CURLRES_IPV6 */ +#endif /* !USE_RESOLVE_ON_IPS */ +#ifdef CURLRES_IPV6 /* * Check if a limited name resolve has been requested. */ @@ -632,7 +638,6 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, if((pf != PF_INET) && !Curl_ipv6works()) /* The stack seems to be a non-IPv6 one */ pf = PF_INET; - #endif /* CURLRES_IPV6 */ memset(&hints, 0, sizeof(hints)); @@ -657,12 +662,16 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, hostname, port, Curl_strerror(conn, SOCKERRNO)); return NULL; } + else { + Curl_addrinfo_set_port(res, port); + } + return res; } #endif /* !HAVE_GETADDRINFO */ -CURLcode Curl_set_dns_servers(struct SessionHandle *data, +CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers) { (void)data; @@ -671,7 +680,7 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data, } -CURLcode Curl_set_dns_interface(struct SessionHandle *data, +CURLcode Curl_set_dns_interface(struct Curl_easy *data, const char *interf) { (void)data; @@ -679,7 +688,7 @@ CURLcode Curl_set_dns_interface(struct SessionHandle *data, return CURLE_NOT_BUILT_IN; } -CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, const char *local_ip4) { (void)data; @@ -687,7 +696,7 @@ CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, return CURLE_NOT_BUILT_IN; } -CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, const char *local_ip6) { (void)data; diff --git a/lib/asyn.h b/lib/asyn.h index 1b681ea..3adc366 100644 --- a/lib/asyn.h +++ b/lib/asyn.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -27,7 +27,7 @@ struct addrinfo; struct hostent; -struct SessionHandle; +struct Curl_easy; struct connectdata; struct Curl_dns_entry; diff --git a/lib/base64.c b/lib/base64.c index 6b87eed..ad25459 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -23,13 +23,13 @@ /* Base64 encoding/decoding */ #include "curl_setup.h" -#include "curl_printf.h" -#include "urldata.h" /* for the SessionHandle definition */ +#include "urldata.h" /* for the Curl_easy definition */ #include "warnless.h" #include "curl_base64.h" #include "non-ascii.h" -/* The last #include files should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" @@ -169,11 +169,11 @@ CURLcode Curl_base64_decode(const char *src, } static CURLcode base64_encode(const char *table64, - struct SessionHandle *data, + struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen) { - CURLcode error; + CURLcode result; unsigned char ibuf[3]; unsigned char obuf[4]; int i; @@ -187,11 +187,11 @@ static CURLcode base64_encode(const char *table64, *outptr = NULL; *outlen = 0; - if(0 == insize) + if(!insize) insize = strlen(indata); - base64data = output = malloc(insize*4/3+4); - if(NULL == output) + base64data = output = malloc(insize * 4 / 3 + 4); + if(!output) return CURLE_OUT_OF_MEMORY; /* @@ -199,10 +199,10 @@ static CURLcode base64_encode(const char *table64, * not the host encoding. And we can't change the actual input * so we copy it to a buffer, translate it, and use that instead. */ - error = Curl_convert_clone(data, indata, insize, &convbuf); - if(error) { + result = Curl_convert_clone(data, indata, insize, &convbuf); + if(result) { free(output); - return error; + return result; } if(convbuf) @@ -233,28 +233,35 @@ static CURLcode base64_encode(const char *table64, table64[obuf[0]], table64[obuf[1]]); break; + case 2: /* two bytes read */ snprintf(output, 5, "%c%c%c=", table64[obuf[0]], table64[obuf[1]], table64[obuf[2]]); break; + default: snprintf(output, 5, "%c%c%c%c", table64[obuf[0]], table64[obuf[1]], table64[obuf[2]], - table64[obuf[3]] ); + table64[obuf[3]]); break; } output += 4; } + + /* Zero terminate */ *output = '\0'; - *outptr = base64data; /* return pointer to new data, allocated memory */ + + /* Return the pointer to the new data (allocated memory) */ + *outptr = base64data; free(convbuf); - *outlen = strlen(base64data); /* return the length of the new data */ + /* Return the length of the new data */ + *outlen = strlen(base64data); return CURLE_OK; } @@ -276,7 +283,7 @@ static CURLcode base64_encode(const char *table64, * * @unittest: 1302 */ -CURLcode Curl_base64_encode(struct SessionHandle *data, +CURLcode Curl_base64_encode(struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen) { @@ -300,10 +307,9 @@ CURLcode Curl_base64_encode(struct SessionHandle *data, * * @unittest: 1302 */ -CURLcode Curl_base64url_encode(struct SessionHandle *data, +CURLcode Curl_base64url_encode(struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen) { return base64_encode(base64url, data, inputbuff, insize, outptr, outlen); } -/* ---- End of Base64 Encoding ---- */ diff --git a/lib/conncache.c b/lib/conncache.c index c712ed7..32a7030 100644 --- a/lib/conncache.c +++ b/lib/conncache.c @@ -5,12 +5,12 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012, Linus Nielsen Feltzing, + * Copyright (C) 2012, 2016, Linus Nielsen Feltzing, * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -32,10 +32,9 @@ #include "sendf.h" #include "rawstr.h" #include "conncache.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" static void conn_llist_dtor(void *user, void *element) @@ -46,7 +45,7 @@ static void conn_llist_dtor(void *user, void *element) data->bundle = NULL; } -static CURLcode bundle_create(struct SessionHandle *data, +static CURLcode bundle_create(struct Curl_easy *data, struct connectbundle **cb_ptr) { (void)data; @@ -132,9 +131,16 @@ void Curl_conncache_destroy(struct conncache *connc) /* returns an allocated key to find a bundle for this connection */ static char *hashkey(struct connectdata *conn) { - return aprintf("%s:%d", - conn->bits.proxy?conn->proxy.name:conn->host.name, - conn->localport); + const char *hostname; + + if(conn->bits.proxy) + hostname = conn->proxy.name; + else if(conn->bits.conn_to_host) + hostname = conn->conn_to_host.name; + else + hostname = conn->host.name; + + return aprintf("%s:%d", hostname, conn->port); } /* Look up the bundle with all the connections to the same host this @@ -193,7 +199,7 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc, CURLcode result; struct connectbundle *bundle; struct connectbundle *new_bundle = NULL; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache); if(!bundle) { diff --git a/lib/conncache.h b/lib/conncache.h index 59181bf..b1dadf9 100644 --- a/lib/conncache.h +++ b/lib/conncache.h @@ -12,7 +12,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/connect.c b/lib/connect.c index 18ac32c..0047f9a 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -56,7 +56,6 @@ #include #endif -#include "curl_printf.h" #include "urldata.h" #include "sendf.h" #include "if2ip.h" @@ -73,8 +72,10 @@ #include "warnless.h" #include "conncache.h" #include "multihandle.h" +#include "system_win32.h" -/* The last #include files should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" @@ -103,7 +104,7 @@ struct tcp_keepalive { #endif static void -tcpkeepalive(struct SessionHandle *data, +tcpkeepalive(struct Curl_easy *data, curl_socket_t sockfd) { int optval = data->set.tcp_keepalive?1:0; @@ -178,7 +179,7 @@ singleipconnect(struct connectdata *conn, * * @unittest: 1303 */ -long Curl_timeleft(struct SessionHandle *data, +long Curl_timeleft(struct Curl_easy *data, struct timeval *nowp, bool duringconnect) { @@ -238,7 +239,7 @@ long Curl_timeleft(struct SessionHandle *data, static CURLcode bindlocal(struct connectdata *conn, curl_socket_t sockfd, int af, unsigned int scope) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct Curl_sockaddr_storage sa; struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */ @@ -619,7 +620,7 @@ static bool getaddressinfo(struct sockaddr* sa, char* addr, switch (sa->sa_family) { case AF_INET: - si = (struct sockaddr_in*) sa; + si = (struct sockaddr_in*)(void*) sa; if(Curl_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) { us_port = ntohs(si->sin_port); @@ -629,7 +630,7 @@ static bool getaddressinfo(struct sockaddr* sa, char* addr, break; #ifdef ENABLE_IPV6 case AF_INET6: - si6 = (struct sockaddr_in6*)sa; + si6 = (struct sockaddr_in6*)(void*) sa; if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr, addr, MAX_IPADR_LEN)) { us_port = ntohs(si6->sin6_port); @@ -662,13 +663,13 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) curl_socklen_t len; struct Curl_sockaddr_storage ssrem; struct Curl_sockaddr_storage ssloc; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(conn->socktype == SOCK_DGRAM) /* there's no connection! */ return; - if(!conn->bits.reuse) { + if(!conn->bits.reuse && !conn->bits.tcp_fastopen) { int error; len = sizeof(struct Curl_sockaddr_storage); @@ -719,7 +720,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, int sockindex, bool *connected) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; long allow; int error = 0; @@ -764,6 +765,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, rc = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0); if(rc == 0) { /* no connection yet */ + error = 0; if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) { infof(data, "After %ldms connect time, move on!\n", conn->timeoutms_per_addr); @@ -776,7 +778,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, trynextip(conn, sockindex, 1); } } - else if(rc == CURL_CSELECT_OUT) { + else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) { if(verifyconnect(conn->tempsock[i], &error)) { /* we are connected with TCP, awesome! */ @@ -841,6 +843,8 @@ CURLcode Curl_is_connected(struct connectdata *conn, if(result) { /* no more addresses to try */ + const char* hostname; + /* if the first address family runs out of addresses to try before the happy eyeball timeout, go ahead and try the next family now */ if(conn->tempaddr[1] == NULL) { @@ -849,20 +853,27 @@ CURLcode Curl_is_connected(struct connectdata *conn, return result; } + if(conn->bits.proxy) + hostname = conn->proxy.name; + else if(conn->bits.conn_to_host) + hostname = conn->conn_to_host.name; + else + hostname = conn->host.name; + failf(data, "Failed to connect to %s port %ld: %s", - conn->bits.proxy?conn->proxy.name:conn->host.name, - conn->port, Curl_strerror(conn, error)); + hostname, conn->port, Curl_strerror(conn, error)); } return result; } -static void tcpnodelay(struct connectdata *conn, - curl_socket_t sockfd) +void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd) { -#ifdef TCP_NODELAY - struct SessionHandle *data= conn->data; - curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay; +#if defined(TCP_NODELAY) +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) + struct Curl_easy *data = conn->data; +#endif + curl_socklen_t onoff = (curl_socklen_t) 1; int level = IPPROTO_TCP; #if 0 @@ -878,6 +889,10 @@ static void tcpnodelay(struct connectdata *conn, level = pe->p_proto; #endif +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) conn; +#endif + if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff, sizeof(onoff)) < 0) infof(data, "Could not set TCP_NODELAY: %s\n", @@ -898,7 +913,7 @@ static void tcpnodelay(struct connectdata *conn, static void nosigpipe(struct connectdata *conn, curl_socket_t sockfd) { - struct SessionHandle *data= conn->data; + struct Curl_easy *data= conn->data; int onoff = 1; if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff, sizeof(onoff)) < 0) @@ -913,7 +928,7 @@ static void nosigpipe(struct connectdata *conn, /* When you run a program that uses the Windows Sockets API, you may experience slow performance when you copy data to a TCP server. - http://support.microsoft.com/kb/823764 + https://support.microsoft.com/kb/823764 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send Buffer Size @@ -931,43 +946,15 @@ void Curl_sndbufset(curl_socket_t sockfd) int val = CURL_MAX_WRITE_SIZE + 32; int curval = 0; int curlen = sizeof(curval); - DWORD majorVersion = 6; static int detectOsState = DETECT_OS_NONE; if(detectOsState == DETECT_OS_NONE) { -#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ - (_WIN32_WINNT < _WIN32_WINNT_WIN2K) - OSVERSIONINFO osver; - - memset(&osver, 0, sizeof(osver)); - osver.dwOSVersionInfoSize = sizeof(osver); - - detectOsState = DETECT_OS_PREVISTA; - if(GetVersionEx(&osver)) { - if(osver.dwMajorVersion >= majorVersion) - detectOsState = DETECT_OS_VISTA_OR_LATER; - } -#else - ULONGLONG cm; - OSVERSIONINFOEX osver; - - memset(&osver, 0, sizeof(osver)); - osver.dwOSVersionInfoSize = sizeof(osver); - osver.dwMajorVersion = majorVersion; - - cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); - cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_GREATER_EQUAL); - cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); - cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); - - if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | - VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), - cm)) + if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) detectOsState = DETECT_OS_VISTA_OR_LATER; else detectOsState = DETECT_OS_PREVISTA; -#endif } if(detectOsState == DETECT_OS_VISTA_OR_LATER) @@ -995,10 +982,10 @@ static CURLcode singleipconnect(struct connectdata *conn, curl_socket_t *sockp) { struct Curl_sockaddr_ex addr; - int rc; + int rc = -1; int error = 0; bool isconnected = FALSE; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_socket_t sockfd; CURLcode result; char ipaddress[MAX_IPADR_LEN]; @@ -1033,7 +1020,7 @@ static CURLcode singleipconnect(struct connectdata *conn, is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM; #endif if(is_tcp && data->set.tcp_nodelay) - tcpnodelay(conn, sockfd); + Curl_tcpnodelay(conn, sockfd); nosigpipe(conn, sockfd); @@ -1084,7 +1071,29 @@ static CURLcode singleipconnect(struct connectdata *conn, /* Connect TCP sockets, bind UDP */ if(!isconnected && (conn->socktype == SOCK_STREAM)) { - rc = connect(sockfd, &addr.sa_addr, addr.addrlen); + if(conn->bits.tcp_fastopen) { +#if defined(CONNECT_DATA_IDEMPOTENT) /* OS X */ + sa_endpoints_t endpoints; + endpoints.sae_srcif = 0; + endpoints.sae_srcaddr = NULL; + endpoints.sae_srcaddrlen = 0; + endpoints.sae_dstaddr = &addr.sa_addr; + endpoints.sae_dstaddrlen = addr.addrlen; + + rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY, + CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT, + NULL, 0, NULL, NULL); +#elif defined(MSG_FASTOPEN) /* Linux */ + if(conn->given->flags & PROTOPT_SSL) + rc = connect(sockfd, &addr.sa_addr, addr.addrlen); + else + rc = 0; /* Do nothing */ +#endif + } + else { + rc = connect(sockfd, &addr.sa_addr, addr.addrlen); + } + if(-1 == rc) error = SOCKERRNO; } @@ -1140,7 +1149,7 @@ static CURLcode singleipconnect(struct connectdata *conn, CURLcode Curl_connecthost(struct connectdata *conn, /* context */ const struct Curl_dns_entry *remotehost) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct timeval before = Curl_tvnow(); CURLcode result = CURLE_COULDNT_CONNECT; @@ -1199,11 +1208,11 @@ static int conn_is_conn(struct connectdata *conn, void *param) /* * Used to extract socket and connectdata struct for the most recent - * transfer on the given SessionHandle. + * transfer on the given Curl_easy. * * The returned socket will be CURL_SOCKET_BAD in case of failure! */ -curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, +curl_socket_t Curl_getconnectinfo(struct Curl_easy *data, struct connectdata **connp) { curl_socket_t sockfd; @@ -1243,10 +1252,10 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, } /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */ #ifdef MSG_PEEK - else { + else if(sockfd != CURL_SOCKET_BAD) { /* use the socket */ char buf; - if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf, + if(recv((RECV_TYPE_ARG1)sockfd, (RECV_TYPE_ARG2)&buf, (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) { return CURL_SOCKET_BAD; /* FIN received */ } @@ -1303,7 +1312,7 @@ CURLcode Curl_socket(struct connectdata *conn, struct Curl_sockaddr_ex *addr, curl_socket_t *sockfd) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct Curl_sockaddr_ex dummy; if(!addr) diff --git a/lib/connect.h b/lib/connect.h index 91646c7..6d60e0d 100644 --- a/lib/connect.h +++ b/lib/connect.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -35,7 +35,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* generic function that returns how much time there's left to run, according to the timeouts set */ -long Curl_timeleft(struct SessionHandle *data, +long Curl_timeleft(struct Curl_easy *data, struct timeval *nowp, bool duringconnect); @@ -45,18 +45,18 @@ long Curl_timeleft(struct SessionHandle *data, /* * Used to extract socket and connectdata struct for the most recent - * transfer on the given SessionHandle. + * transfer on the given Curl_easy. * * The returned socket will be CURL_SOCKET_BAD in case of failure! */ -curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, +curl_socket_t Curl_getconnectinfo(struct Curl_easy *data, struct connectdata **connp); #ifdef USE_WINSOCK /* When you run a program that uses the Windows Sockets API, you may experience slow performance when you copy data to a TCP server. - http://support.microsoft.com/kb/823764 + https://support.microsoft.com/kb/823764 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send Buffer Size @@ -102,6 +102,8 @@ CURLcode Curl_socket(struct connectdata *conn, struct Curl_sockaddr_ex *addr, curl_socket_t *sockfd); +void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd); + #ifdef CURLDEBUG /* * Curl_connclose() sets the bit.close bit to TRUE with an explanation. diff --git a/lib/content_encoding.c b/lib/content_encoding.c index c68e6e5..fa36aca 100644 --- a/lib/content_encoding.c +++ b/lib/content_encoding.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -67,7 +67,7 @@ zfree_cb(voidpf opaque, voidpf ptr) static CURLcode process_zlib_error(struct connectdata *conn, z_stream *z) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(z->msg) failf (data, "Error while processing content unencoding: %s", z->msg); @@ -425,7 +425,7 @@ Curl_unencode_gzip_write(struct connectdata *conn, void Curl_unencode_cleanup(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SingleRequest *k = &data->req; z_stream *z = &k->z; if(k->zlib_init != ZLIB_UNINIT) diff --git a/lib/content_encoding.h b/lib/content_encoding.h index 501f6c8..3fadd28 100644 --- a/lib/content_encoding.h +++ b/lib/content_encoding.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/cookie.c b/lib/cookie.c index 22730cf..d5a83fd 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,13 +26,13 @@ RECEIVING COOKIE INFORMATION ============================ -struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, +struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, const char *file, struct CookieInfo *inc, bool newsession); Inits a cookie struct to store data in a local file. This is always called before any cookies are set. -struct Cookie *Curl_cookie_add(struct SessionHandle *data, +struct Cookie *Curl_cookie_add(struct Curl_easy *data, struct CookieInfo *c, bool httpheader, char *lineptr, const char *domain, const char *path); @@ -84,7 +84,10 @@ Example set of cookies: #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) -#include "curl_printf.h" +#ifdef USE_LIBPSL +# include +#endif + #include "urldata.h" #include "cookie.h" #include "strequal.h" @@ -97,7 +100,8 @@ Example set of cookies: #include "curl_memrchr.h" #include "inet_pton.h" -/* The last #include files should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" @@ -256,7 +260,7 @@ static char *sanitize_cookie_path(const char *cookie_path) * * NOTE: OOM or cookie parsing failures are ignored. */ -void Curl_cookie_loadfiles(struct SessionHandle *data) +void Curl_cookie_loadfiles(struct Curl_easy *data) { struct curl_slist *list = data->change.cookielist; if(list) { @@ -305,7 +309,7 @@ static void remove_expired(struct CookieInfo *cookies) pv = NULL; while(co) { nx = co->next; - if((co->expirestr || co->maxage) && co->expires < now) { + if(co->expires && co->expires < now) { if(co == cookies->cookies) { cookies->cookies = co->next; } @@ -358,7 +362,7 @@ static bool isip(const char *domain) ***************************************************************************/ struct Cookie * -Curl_cookie_add(struct SessionHandle *data, +Curl_cookie_add(struct Curl_easy *data, /* The 'data' pointer here may be NULL at times, and thus must only be used very carefully for things that can deal with data being NULL. Such as infof() and similar */ @@ -379,6 +383,10 @@ Curl_cookie_add(struct SessionHandle *data, bool replace_old = FALSE; bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */ +#ifdef USE_LIBPSL + const psl_ctx_t *psl; +#endif + #ifdef CURL_DISABLE_VERBOSE_STRINGS (void)data; #endif @@ -409,7 +417,7 @@ Curl_cookie_add(struct SessionHandle *data, do { /* we have a = pair or a stand-alone word here */ name[0]=what[0]=0; /* init the buffers */ - if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n =] =%" + if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%" MAX_COOKIE_LINE_TXT "[^;\r\n]", name, what)) { /* Use strstore() below to properly deal with received cookie @@ -419,15 +427,24 @@ Curl_cookie_add(struct SessionHandle *data, bool done = FALSE; bool sep; size_t len=strlen(what); - const char *endofn = &ptr[ strlen(name) ]; - - /* skip trailing spaces in name */ - while(*endofn && ISBLANK(*endofn)) - endofn++; + size_t nlen = strlen(name); + const char *endofn = &ptr[ nlen ]; /* name ends with a '=' ? */ sep = (*endofn == '=')?TRUE:FALSE; + if(nlen) { + endofn--; /* move to the last character */ + if(ISBLANK(*endofn)) { + /* skip trailing spaces in name */ + while(*endofn && ISBLANK(*endofn) && nlen) { + endofn--; + nlen--; + } + name[nlen]=0; /* new end of name */ + } + } + /* Strip off trailing whitespace from the 'what' */ while(len && ISBLANK(what[len-1])) { what[len-1]=0; @@ -439,7 +456,16 @@ Curl_cookie_add(struct SessionHandle *data, while(*whatptr && ISBLANK(*whatptr)) whatptr++; - if(!len) { + if(!co->name && sep) { + /* The very first name/value pair is the actual cookie name */ + co->name = strdup(name); + co->value = strdup(whatptr); + if(!co->name || !co->value) { + badcookie = TRUE; + break; + } + } + else if(!len) { /* this was a "=" with no content, and we must allow 'secure' and 'httponly' specified this weirdly */ done = TRUE; @@ -533,14 +559,6 @@ Curl_cookie_add(struct SessionHandle *data, break; } } - else if(!co->name) { - co->name = strdup(name); - co->value = strdup(whatptr); - if(!co->name || !co->value) { - badcookie = TRUE; - break; - } - } /* else this is the second (or more) name we don't know about! */ @@ -777,6 +795,21 @@ Curl_cookie_add(struct SessionHandle *data, /* at first, remove expired cookies */ remove_expired(c); +#ifdef USE_LIBPSL + /* Check if the domain is a Public Suffix and if yes, ignore the cookie. + This needs a libpsl compiled with builtin data. */ + if(domain && co->domain && !isip(co->domain)) { + if(((psl = psl_builtin()) != NULL) + && !psl_is_cookie_domain_acceptable(psl, domain, co->domain)) { + infof(data, + "cookie '%s' dropped, domain '%s' must not set cookies for '%s'\n", + co->name, domain, co->domain); + freecookie(co); + return NULL; + } + } +#endif + clist = c->cookies; replace_old = FALSE; while(clist) { @@ -880,7 +913,7 @@ Curl_cookie_add(struct SessionHandle *data, * * Returns NULL on out of memory. Invalid cookies are ignored. ****************************************************************************/ -struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, +struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, const char *file, struct CookieInfo *inc, bool newsession) @@ -1247,6 +1280,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) struct Cookie *co; FILE *out; bool use_stdout=FALSE; + char *format_ptr; if((NULL == c) || (0 == c->numcookies)) /* If there are no known cookies, we don't write or even create any @@ -1267,27 +1301,23 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) return 1; /* failure */ } - if(c) { - char *format_ptr; + fputs("# Netscape HTTP Cookie File\n" + "# https://curl.haxx.se/docs/http-cookies.html\n" + "# This file was generated by libcurl! Edit at your own risk.\n\n", + out); - fputs("# Netscape HTTP Cookie File\n" - "# http://curl.haxx.se/docs/http-cookies.html\n" - "# This file was generated by libcurl! Edit at your own risk.\n\n", - out); - - for(co = c->cookies; co; co = co->next) { - if(!co->domain) - continue; - format_ptr = get_netscape_format(co); - if(format_ptr == NULL) { - fprintf(out, "#\n# Fatal libcurl error\n"); - if(!use_stdout) - fclose(out); - return 1; - } - fprintf(out, "%s\n", format_ptr); - free(format_ptr); + for(co = c->cookies; co; co = co->next) { + if(!co->domain) + continue; + format_ptr = get_netscape_format(co); + if(format_ptr == NULL) { + fprintf(out, "#\n# Fatal libcurl error\n"); + if(!use_stdout) + fclose(out); + return 1; } + fprintf(out, "%s\n", format_ptr); + free(format_ptr); } if(!use_stdout) @@ -1296,7 +1326,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) return 0; } -struct curl_slist *Curl_cookie_list(struct SessionHandle *data) +struct curl_slist *Curl_cookie_list(struct Curl_easy *data) { struct curl_slist *list = NULL; struct curl_slist *beg; @@ -1327,7 +1357,7 @@ struct curl_slist *Curl_cookie_list(struct SessionHandle *data) return list; } -void Curl_flush_cookies(struct SessionHandle *data, int cleanup) +void Curl_flush_cookies(struct Curl_easy *data, int cleanup) { if(data->set.str[STRING_COOKIEJAR]) { if(data->change.cookielist) { diff --git a/lib/cookie.h b/lib/cookie.h index bd89082..cd7c54a 100644 --- a/lib/cookie.h +++ b/lib/cookie.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -70,13 +70,13 @@ struct CookieInfo { #define MAX_NAME 1024 #define MAX_NAME_TXT "1023" -struct SessionHandle; +struct Curl_easy; /* * Add a cookie to the internal list of cookies. The domain and path arguments * are only used if the header boolean is TRUE. */ -struct Cookie *Curl_cookie_add(struct SessionHandle *data, +struct Cookie *Curl_cookie_add(struct Curl_easy *data, struct CookieInfo *, bool header, char *lineptr, const char *domain, const char *path); @@ -93,12 +93,12 @@ void Curl_cookie_clearsess(struct CookieInfo *cookies); #define Curl_cookie_cleanup(x) Curl_nop_stmt #define Curl_flush_cookies(x,y) Curl_nop_stmt #else -void Curl_flush_cookies(struct SessionHandle *data, int cleanup); +void Curl_flush_cookies(struct Curl_easy *data, int cleanup); void Curl_cookie_cleanup(struct CookieInfo *); -struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, +struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, const char *, struct CookieInfo *, bool); -struct curl_slist *Curl_cookie_list(struct SessionHandle *data); -void Curl_cookie_loadfiles(struct SessionHandle *data); +struct curl_slist *Curl_cookie_list(struct Curl_easy *data); +void Curl_cookie_loadfiles(struct Curl_easy *data); #endif #endif /* HEADER_CURL_COOKIE_H */ diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c index 6627a6b..35eb2dd 100644 --- a/lib/curl_addrinfo.c +++ b/lib/curl_addrinfo.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -50,10 +50,9 @@ #include "curl_addrinfo.h" #include "inet_pton.h" #include "warnless.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" - -/* The last #include file should be: */ #include "memdebug.h" /* @@ -521,7 +520,11 @@ void curl_dofreeaddrinfo(struct addrinfo *freethis, int line, const char *source) { +#ifdef USE_LWIPSOCK + lwip_freeaddrinfo(freethis); +#else (freeaddrinfo)(freethis); +#endif curl_memlog("ADDR %s:%d freeaddrinfo(%p)\n", source, line, (void *)freethis); } @@ -544,7 +547,11 @@ curl_dogetaddrinfo(const char *hostname, struct addrinfo **result, int line, const char *source) { +#ifdef USE_LWIPSOCK + int res=lwip_getaddrinfo(hostname, service, hints, result); +#else int res=(getaddrinfo)(hostname, service, hints, result); +#endif if(0 == res) /* success */ curl_memlog("ADDR %s:%d getaddrinfo() = %p\n", @@ -556,3 +563,32 @@ curl_dogetaddrinfo(const char *hostname, } #endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */ +#if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS) +/* + * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and Mac OS X + * 10.11.5. + */ +void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port) +{ + Curl_addrinfo *ca; + struct sockaddr_in *addr; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 *addr6; +#endif + for(ca = addrinfo; ca != NULL; ca = ca->ai_next) { + switch (ca->ai_family) { + case AF_INET: + addr = (void *)ca->ai_addr; /* storage area for this info */ + addr->sin_port = htons((unsigned short)port); + break; + +#ifdef ENABLE_IPV6 + case AF_INET6: + addr6 = (void *)ca->ai_addr; /* storage area for this info */ + addr6->sin6_port = htons((unsigned short)port); + break; +#endif + } + } +} +#endif diff --git a/lib/curl_addrinfo.h b/lib/curl_addrinfo.h index 4ef8827..1a681e6 100644 --- a/lib/curl_addrinfo.h +++ b/lib/curl_addrinfo.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -83,7 +83,8 @@ Curl_addrinfo *Curl_str2addr(char *dotted, int port); Curl_addrinfo *Curl_unix2addr(const char *path); #endif -#if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) +#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \ + defined(HAVE_FREEADDRINFO) void curl_dofreeaddrinfo(struct addrinfo *freethis, int line, const char *source); @@ -98,4 +99,12 @@ curl_dogetaddrinfo(const char *hostname, int line, const char *source); #endif +#ifdef HAVE_GETADDRINFO +#ifdef USE_RESOLVE_ON_IPS +void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port); +#else +#define Curl_addrinfo_set_port(x,y) +#endif +#endif + #endif /* HEADER_CURL_ADDRINFO_H */ diff --git a/lib/curl_base64.h b/lib/curl_base64.h index 92896fe..7e9fc26 100644 --- a/lib/curl_base64.h +++ b/lib/curl_base64.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,10 +22,10 @@ * ***************************************************************************/ -CURLcode Curl_base64_encode(struct SessionHandle *data, +CURLcode Curl_base64_encode(struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen); -CURLcode Curl_base64url_encode(struct SessionHandle *data, +CURLcode Curl_base64url_encode(struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen); diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index 5376aa7..65a414b 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -24,6 +24,12 @@ /* to disable FTP */ #cmakedefine CURL_DISABLE_FTP 1 +/* to disable GOPHER */ +#cmakedefine CURL_DISABLE_GOPHER 1 + +/* to disable IMAP */ +#cmakedefine CURL_DISABLE_IMAP 1 + /* to disable HTTP */ #cmakedefine CURL_DISABLE_HTTP 1 @@ -33,9 +39,24 @@ /* to disable LDAPS */ #cmakedefine CURL_DISABLE_LDAPS 1 +/* to disable POP3 */ +#cmakedefine CURL_DISABLE_POP3 1 + /* to disable proxies */ #cmakedefine CURL_DISABLE_PROXY 1 +/* to disable RTSP */ +#cmakedefine CURL_DISABLE_RTSP 1 + +/* to disable RTMP */ +#cmakedefine CURL_DISABLE_RTMP 1 + +/* to disable SMB */ +#cmakedefine CURL_DISABLE_SMB 1 + +/* to disable SMTP */ +#cmakedefine CURL_DISABLE_SMTP 1 + /* to disable TELNET */ #cmakedefine CURL_DISABLE_TELNET 1 @@ -894,6 +915,9 @@ /* if PolarSSL is enabled */ #cmakedefine USE_POLARSSL 1 +/* if mbedTLS is enabled */ +#cmakedefine USE_MBEDTLS 1 + /* if libSSH2 is in use */ #cmakedefine USE_LIBSSH2 1 @@ -919,6 +943,9 @@ /* to enable SSPI support */ #cmakedefine USE_WINDOWS_SSPI 1 +/* to enable Windows SSL */ +#cmakedefine USE_SCHANNEL 1 + /* Define to 1 if using yaSSL in OpenSSL compatibility mode. */ #cmakedefine USE_YASSLEMUL 1 diff --git a/lib/curl_des.c b/lib/curl_des.c index 42c1df9..421c9f7 100644 --- a/lib/curl_des.c +++ b/lib/curl_des.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,7 +22,7 @@ #include "curl_setup.h" -#if defined(USE_NTLM) && (!defined(USE_OPENSSL) || defined(HAVE_BORINGSSL)) +#if defined(USE_NTLM) && !defined(USE_OPENSSL) #include "curl_des.h" @@ -60,4 +60,4 @@ void Curl_des_set_odd_parity(unsigned char *bytes, size_t len) } } -#endif /* USE_NTLM && (!USE_OPENSSL || HAVE_BORINGSSL) */ +#endif /* USE_NTLM && !USE_OPENSSL */ diff --git a/lib/curl_des.h b/lib/curl_des.h index b855db4..129060f 100644 --- a/lib/curl_des.h +++ b/lib/curl_des.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -24,11 +24,11 @@ #include "curl_setup.h" -#if defined(USE_NTLM) && (!defined(USE_OPENSSL) || defined(HAVE_BORINGSSL)) +#if defined(USE_NTLM) && !defined(USE_OPENSSL) /* Applies odd parity to the given byte array */ void Curl_des_set_odd_parity(unsigned char *bytes, size_t length); -#endif /* USE_NTLM && (!USE_OPENSSL || HAVE_BORINGSSL) */ +#endif /* USE_NTLM && !USE_OPENSSL */ #endif /* HEADER_CURL_DES_H */ diff --git a/lib/curl_endian.c b/lib/curl_endian.c index bcd66ed..76deca6 100644 --- a/lib/curl_endian.c +++ b/lib/curl_endian.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_endian.h b/lib/curl_endian.h index e384279..df8398c 100644 --- a/lib/curl_endian.h +++ b/lib/curl_endian.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_fnmatch.c b/lib/curl_fnmatch.c index 1e53918..e8108bb 100644 --- a/lib/curl_fnmatch.c +++ b/lib/curl_fnmatch.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,6 +22,8 @@ #include "curl_setup.h" +#include + #include "curl_fnmatch.h" #include "curl_memory.h" diff --git a/lib/curl_fnmatch.h b/lib/curl_fnmatch.h index 6335d03..69ffe39 100644 --- a/lib/curl_fnmatch.h +++ b/lib/curl_fnmatch.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_gethostname.c b/lib/curl_gethostname.c index ded1e6f..2591fd8 100644 --- a/lib/curl_gethostname.c +++ b/lib/curl_gethostname.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_gethostname.h b/lib/curl_gethostname.h index 48740f6..07517c5 100644 --- a/lib/curl_gethostname.h +++ b/lib/curl_gethostname.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_gssapi.c b/lib/curl_gssapi.c index 9baece5..bf7c766 100644 --- a/lib/curl_gssapi.c +++ b/lib/curl_gssapi.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2011 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2011 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -33,7 +33,7 @@ static char krb5_oid_bytes[] = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"; gss_OID_desc Curl_krb5_mech_oid = { 9, &krb5_oid_bytes }; OM_uint32 Curl_gss_init_sec_context( - struct SessionHandle *data, + struct Curl_easy *data, OM_uint32 *minor_status, gss_ctx_id_t *context, gss_name_t target_name, @@ -76,45 +76,56 @@ OM_uint32 Curl_gss_init_sec_context( NULL /* time_rec */); } -/* - * Curl_gss_log_error() - * - * This is used to log a GSS-API error status. - * - * Parameters: - * - * data [in] - The session handle. - * status [in] - The status code. - * prefix [in] - The prefix of the log message. - */ -void Curl_gss_log_error(struct SessionHandle *data, OM_uint32 status, - const char *prefix) -{ +#define GSS_LOG_BUFFER_LEN 1024 +static size_t display_gss_error(OM_uint32 status, int type, + char *buf, size_t len) { OM_uint32 maj_stat; OM_uint32 min_stat; OM_uint32 msg_ctx = 0; gss_buffer_desc status_string; - char buf[1024]; - size_t len; - snprintf(buf, sizeof(buf), "%s", prefix); - len = strlen(buf); do { maj_stat = gss_display_status(&min_stat, status, - GSS_C_MECH_CODE, + type, GSS_C_NO_OID, &msg_ctx, &status_string); - if(sizeof(buf) > len + status_string.length + 1) { - snprintf(buf + len, sizeof(buf) - len, - ": %s", (char*)status_string.value); - len += status_string.length; + if(GSS_LOG_BUFFER_LEN > len + status_string.length + 3) { + len += snprintf(buf + len, GSS_LOG_BUFFER_LEN - len, + "%.*s. ", (int)status_string.length, + (char*)status_string.value); } gss_release_buffer(&min_stat, &status_string); } while(!GSS_ERROR(maj_stat) && msg_ctx != 0); - infof(data, "%s\n", buf); + return len; +} + +/* + * Curl_gss_log_error() + * + * This is used to log a GSS-API error status. + * + * Parameters: + * + * data [in] - The session handle. + * prefix [in] - The prefix of the log message. + * major [in] - The major status code. + * minor [in] - The minor status code. + */ +void Curl_gss_log_error(struct Curl_easy *data, const char *prefix, + OM_uint32 major, OM_uint32 minor) +{ + char buf[GSS_LOG_BUFFER_LEN]; + size_t len = 0; + + if(major != GSS_S_FAILURE) + len = display_gss_error(major, GSS_C_GSS_CODE, buf, len); + + display_gss_error(minor, GSS_C_MECH_CODE, buf, len); + + infof(data, "%s%s\n", prefix, buf); } #endif /* HAVE_GSSAPI */ diff --git a/lib/curl_gssapi.h b/lib/curl_gssapi.h index 19aab64..9700a28 100644 --- a/lib/curl_gssapi.h +++ b/lib/curl_gssapi.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -44,7 +44,7 @@ extern gss_OID_desc Curl_krb5_mech_oid; /* Common method for using GSS-API */ OM_uint32 Curl_gss_init_sec_context( - struct SessionHandle *data, + struct Curl_easy *data, OM_uint32 *minor_status, gss_ctx_id_t *context, gss_name_t target_name, @@ -56,8 +56,8 @@ OM_uint32 Curl_gss_init_sec_context( OM_uint32 *ret_flags); /* Helper to log a GSS-API error status */ -void Curl_gss_log_error(struct SessionHandle *data, OM_uint32 status, - const char *prefix); +void Curl_gss_log_error(struct Curl_easy *data, const char *prefix, + OM_uint32 major, OM_uint32 minor); /* Provide some definitions missing in old headers */ #ifdef HAVE_OLD_GSSMIT diff --git a/lib/curl_hmac.h b/lib/curl_hmac.h index 9b65c8c..41703b4 100644 --- a/lib/curl_hmac.h +++ b/lib/curl_hmac.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_ldap.h b/lib/curl_ldap.h index 93fb4b0..27d0381 100644 --- a/lib/curl_ldap.h +++ b/lib/curl_ldap.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_md4.h b/lib/curl_md4.h index 13c7903..8c26d12 100644 --- a/lib/curl_md4.h +++ b/lib/curl_md4.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_md5.h b/lib/curl_md5.h index 9c0e0b5..5f70c96 100644 --- a/lib/curl_md5.h +++ b/lib/curl_md5.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_memory.h b/lib/curl_memory.h index bc744cc..6f792ff 100644 --- a/lib/curl_memory.h +++ b/lib/curl_memory.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -83,7 +83,20 @@ #ifndef CURLX_NO_MEMORY_CALLBACKS -#include /* for the callback typedefs */ +#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* only if not already done */ +/* + * The following memory function replacement typedef's are COPIED from + * curl/curl.h and MUST match the originals. We copy them to avoid having to + * include curl/curl.h here. We avoid that include since it includes stdio.h + * and other headers that may get messed up with defines done here. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); +#define CURL_DID_MEMORY_FUNC_TYPEDEFS +#endif extern curl_malloc_callback Curl_cmalloc; extern curl_free_callback Curl_cfree; diff --git a/lib/curl_memrchr.c b/lib/curl_memrchr.c index 6722c6a..c521497 100644 --- a/lib/curl_memrchr.c +++ b/lib/curl_memrchr.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,6 +21,9 @@ ***************************************************************************/ #include "curl_setup.h" + +#include + #include "curl_memrchr.h" #include "curl_memory.h" diff --git a/lib/curl_memrchr.h b/lib/curl_memrchr.h index 324c73a..747509c 100644 --- a/lib/curl_memrchr.h +++ b/lib/curl_memrchr.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_multibyte.c b/lib/curl_multibyte.c index 403d005..e78bb50 100644 --- a/lib/curl_multibyte.c +++ b/lib/curl_multibyte.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,6 +22,8 @@ #include "curl_setup.h" +#include + #if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \ defined(USE_WIN32_LDAP)) && defined(UNICODE)) diff --git a/lib/curl_multibyte.h b/lib/curl_multibyte.h index dc7ed4c..615f5c0 100644 --- a/lib/curl_multibyte.h +++ b/lib/curl_multibyte.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_ntlm_core.c b/lib/curl_ntlm_core.c index 2e5b573..f3fb013 100644 --- a/lib/curl_ntlm_core.c +++ b/lib/curl_ntlm_core.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -28,7 +28,7 @@ * NTLM details: * * http://davenport.sourceforge.net/ntlm.html - * http://www.innovation.ch/java/ntlm.html + * https://www.innovation.ch/java/ntlm.html */ #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) @@ -107,9 +107,8 @@ #include "warnless.h" #include "curl_endian.h" #include "curl_des.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -143,14 +142,10 @@ static void setup_des_key(const unsigned char *key_56, DES_cblock key; /* Expand the 56-bit key to 64-bits */ - extend_key_56_to_64(key_56, (char *) key); + extend_key_56_to_64(key_56, (char *) &key); /* Set the key parity to odd */ -#if defined(HAVE_BORINGSSL) - Curl_des_set_odd_parity((unsigned char *) &key, sizeof(key)); -#else DES_set_odd_parity(&key); -#endif /* Set the key */ DES_set_key(&key, ks); @@ -416,7 +411,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys, /* * Set up lanmanager hashed password */ -CURLcode Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, +CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data, const char *password, unsigned char *lmbuffer /* 21 bytes */) { @@ -510,7 +505,7 @@ static void ascii_uppercase_to_unicode_le(unsigned char *dest, * Set up nt hashed passwords * @unittest: 1600 */ -CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data, +CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data, const char *password, unsigned char *ntbuffer /* 21 bytes */) { @@ -664,21 +659,22 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, unsigned int len = 0; unsigned char *ptr = NULL; unsigned char hmac_output[NTLM_HMAC_MD5_LEN]; -#if defined(HAVE_LONGLONG) - long long tw; -#else - __int64 tw; -#endif + curl_off_t tw; + CURLcode result = CURLE_OK; +#if CURL_SIZEOF_CURL_OFF_T < 8 +#error "this section needs 64bit support to work" +#endif + /* Calculate the timestamp */ #ifdef DEBUGBUILD char *force_timestamp = getenv("CURL_FORCETIME"); if(force_timestamp) - tw = 11644473600ULL * 10000000ULL; + tw = CURL_OFF_T_C(11644473600) * 10000000; else #endif - tw = ((long long)time(NULL) + 11644473600ULL) * 10000000ULL; + tw = ((curl_off_t)time(NULL) + CURL_OFF_T_C(11644473600)) * 10000000; /* Calculate the response len */ len = NTLM_HMAC_MD5_LEN + NTLMv2_BLOB_LEN; diff --git a/lib/curl_ntlm_core.h b/lib/curl_ntlm_core.h index 3a76359..c5f90e7 100644 --- a/lib/curl_ntlm_core.h +++ b/lib/curl_ntlm_core.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -64,12 +64,12 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys, const unsigned char *plaintext, unsigned char *results); -CURLcode Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, +CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data, const char *password, unsigned char *lmbuffer /* 21 bytes */); #if USE_NTRESPONSES -CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data, +CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data, const char *password, unsigned char *ntbuffer /* 21 bytes */); diff --git a/lib/curl_ntlm_wb.c b/lib/curl_ntlm_wb.c index b2a5fb3..afdea16 100644 --- a/lib/curl_ntlm_wb.c +++ b/lib/curl_ntlm_wb.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -29,7 +29,7 @@ * NTLM details: * * http://davenport.sourceforge.net/ntlm.html - * http://www.innovation.ch/java/ntlm.html + * https://www.innovation.ch/java/ntlm.html */ #define DEBUG_ME 0 @@ -47,13 +47,12 @@ #include "urldata.h" #include "sendf.h" #include "select.h" -#include "curl_ntlm_msgs.h" +#include "vauth/ntlm.h" #include "curl_ntlm_wb.h" #include "url.h" #include "strerror.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -373,8 +372,8 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, * by delegating the NTLM challenge/response protocal to a helper * in ntlm_auth. * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html - * http://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html - * http://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html + * https://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html + * https://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html * Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this * feature is enabled and 'NTLM_WB_FILE' symbol holds absolute * filename of ntlm_auth helper. diff --git a/lib/curl_ntlm_wb.h b/lib/curl_ntlm_wb.h index 828bb57..aba3d46 100644 --- a/lib/curl_ntlm_wb.h +++ b/lib/curl_ntlm_wb.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_printf.h b/lib/curl_printf.h index 086923f..49857cd 100644 --- a/lib/curl_printf.h +++ b/lib/curl_printf.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_rtmp.c b/lib/curl_rtmp.c index 2938972..06dd047 100644 --- a/lib/curl_rtmp.c +++ b/lib/curl_rtmp.c @@ -10,7 +10,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -55,7 +55,7 @@ static Curl_recv rtmp_recv; static Curl_send rtmp_send; /* - * RTMP protocol handler.h, based on http://rtmpdump.mplayerhq.hu + * RTMP protocol handler.h, based on https://rtmpdump.mplayerhq.hu */ const struct Curl_handler Curl_handler_rtmp = { diff --git a/lib/curl_rtmp.h b/lib/curl_rtmp.h index 4a9e9e6..3306e22 100644 --- a/lib/curl_rtmp.h +++ b/lib/curl_rtmp.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c index 68646bc..35e9fea 100644 --- a/lib/curl_sasl.c +++ b/lib/curl_sasl.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -24,6 +24,7 @@ * RFC4422 Simple Authentication and Security Layer (SASL) * RFC4616 PLAIN authentication * RFC6749 OAuth 2.0 Authorization Framework + * RFC7628 A Set of SASL Mechanisms for OAuth * Draft LOGIN SASL Mechanism * ***************************************************************************/ @@ -35,6 +36,7 @@ #include "curl_base64.h" #include "curl_md5.h" +#include "vauth/vauth.h" #include "vtls/vtls.h" #include "curl_hmac.h" #include "curl_sasl.h" @@ -44,9 +46,8 @@ #include "rawstr.h" #include "sendf.h" #include "non-ascii.h" /* included for Curl_convert_... prototypes */ +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -56,1140 +57,18 @@ const struct { size_t len; /* Name length */ unsigned int bit; /* Flag bit */ } mechtable[] = { - { "LOGIN", 5, SASL_MECH_LOGIN }, - { "PLAIN", 5, SASL_MECH_PLAIN }, - { "CRAM-MD5", 8, SASL_MECH_CRAM_MD5 }, - { "DIGEST-MD5", 10, SASL_MECH_DIGEST_MD5 }, - { "GSSAPI", 6, SASL_MECH_GSSAPI }, - { "EXTERNAL", 8, SASL_MECH_EXTERNAL }, - { "NTLM", 4, SASL_MECH_NTLM }, - { "XOAUTH2", 7, SASL_MECH_XOAUTH2 }, - { ZERO_NULL, 0, 0 } + { "LOGIN", 5, SASL_MECH_LOGIN }, + { "PLAIN", 5, SASL_MECH_PLAIN }, + { "CRAM-MD5", 8, SASL_MECH_CRAM_MD5 }, + { "DIGEST-MD5", 10, SASL_MECH_DIGEST_MD5 }, + { "GSSAPI", 6, SASL_MECH_GSSAPI }, + { "EXTERNAL", 8, SASL_MECH_EXTERNAL }, + { "NTLM", 4, SASL_MECH_NTLM }, + { "XOAUTH2", 7, SASL_MECH_XOAUTH2 }, + { "OAUTHBEARER", 11, SASL_MECH_OAUTHBEARER }, + { ZERO_NULL, 0, 0 } }; -#if !defined(CURL_DISABLE_CRYPTO_AUTH) && !defined(USE_WINDOWS_SSPI) -#define DIGEST_QOP_VALUE_AUTH (1 << 0) -#define DIGEST_QOP_VALUE_AUTH_INT (1 << 1) -#define DIGEST_QOP_VALUE_AUTH_CONF (1 << 2) - -#define DIGEST_QOP_VALUE_STRING_AUTH "auth" -#define DIGEST_QOP_VALUE_STRING_AUTH_INT "auth-int" -#define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf" - -/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines. - It converts digest text to ASCII so the MD5 will be correct for - what ultimately goes over the network. -*/ -#define CURL_OUTPUT_DIGEST_CONV(a, b) \ - result = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \ - if(result) { \ - free(b); \ - return result; \ - } - -#endif - -#if !defined(CURL_DISABLE_CRYPTO_AUTH) -/* - * Returns 0 on success and then the buffers are filled in fine. - * - * Non-zero means failure to parse. - */ -int Curl_sasl_digest_get_pair(const char *str, char *value, char *content, - const char **endptr) -{ - int c; - bool starts_with_quote = FALSE; - bool escape = FALSE; - - for(c = DIGEST_MAX_VALUE_LENGTH - 1; (*str && (*str != '=') && c--); ) - *value++ = *str++; - *value = 0; - - if('=' != *str++) - /* eek, no match */ - return 1; - - if('\"' == *str) { - /* this starts with a quote so it must end with one as well! */ - str++; - starts_with_quote = TRUE; - } - - for(c = DIGEST_MAX_CONTENT_LENGTH - 1; *str && c--; str++) { - switch(*str) { - case '\\': - if(!escape) { - /* possibly the start of an escaped quote */ - escape = TRUE; - *content++ = '\\'; /* even though this is an escape character, we still - store it as-is in the target buffer */ - continue; - } - break; - case ',': - if(!starts_with_quote) { - /* this signals the end of the content if we didn't get a starting - quote and then we do "sloppy" parsing */ - c = 0; /* the end */ - continue; - } - break; - case '\r': - case '\n': - /* end of string */ - c = 0; - continue; - case '\"': - if(!escape && starts_with_quote) { - /* end of string */ - c = 0; - continue; - } - break; - } - escape = FALSE; - *content++ = *str; - } - *content = 0; - - *endptr = str; - - return 0; /* all is fine! */ -} -#endif - -#if !defined(CURL_DISABLE_CRYPTO_AUTH) && !defined(USE_WINDOWS_SSPI) -/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/ -static void sasl_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */ - unsigned char *dest) /* 33 bytes */ -{ - int i; - for(i = 0; i < 16; i++) - snprintf((char *)&dest[i*2], 3, "%02x", source[i]); -} - -/* Perform quoted-string escaping as described in RFC2616 and its errata */ -static char *sasl_digest_string_quoted(const char *source) -{ - char *dest, *d; - const char *s = source; - size_t n = 1; /* null terminator */ - - /* Calculate size needed */ - while(*s) { - ++n; - if(*s == '"' || *s == '\\') { - ++n; - } - ++s; - } - - dest = malloc(n); - if(dest) { - s = source; - d = dest; - while(*s) { - if(*s == '"' || *s == '\\') { - *d++ = '\\'; - } - *d++ = *s++; - } - *d = 0; - } - - return dest; -} - -/* Retrieves the value for a corresponding key from the challenge string - * returns TRUE if the key could be found, FALSE if it does not exists - */ -static bool sasl_digest_get_key_value(const char *chlg, - const char *key, - char *value, - size_t max_val_len, - char end_char) -{ - char *find_pos; - size_t i; - - find_pos = strstr(chlg, key); - if(!find_pos) - return FALSE; - - find_pos += strlen(key); - - for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i) - value[i] = *find_pos++; - value[i] = '\0'; - - return TRUE; -} - -static CURLcode sasl_digest_get_qop_values(const char *options, int *value) -{ - char *tmp; - char *token; - char *tok_buf; - - /* Initialise the output */ - *value = 0; - - /* Tokenise the list of qop values. Use a temporary clone of the buffer since - strtok_r() ruins it. */ - tmp = strdup(options); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - - token = strtok_r(tmp, ",", &tok_buf); - while(token != NULL) { - if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) - *value |= DIGEST_QOP_VALUE_AUTH; - else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) - *value |= DIGEST_QOP_VALUE_AUTH_INT; - else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF)) - *value |= DIGEST_QOP_VALUE_AUTH_CONF; - - token = strtok_r(NULL, ",", &tok_buf); - } - - free(tmp); - - return CURLE_OK; -} -#endif /* !CURL_DISABLE_CRYPTO_AUTH && !USE_WINDOWS_SSPI */ - -#if !defined(USE_WINDOWS_SSPI) -/* - * Curl_sasl_build_spn() - * - * This is used to build a SPN string in the format service/host. - * - * Parameters: - * - * service [in] - The service type such as www, smtp, pop or imap. - * host [in] - The host name or realm. - * - * Returns a pointer to the newly allocated SPN. - */ -char *Curl_sasl_build_spn(const char *service, const char *host) -{ - /* Generate and return our SPN */ - return aprintf("%s/%s", service, host); -} -#endif - -/* - * sasl_create_plain_message() - * - * This is used to generate an already encoded PLAIN message ready - * for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name. - * passdwp [in] - The user's password. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -static CURLcode sasl_create_plain_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - char **outptr, size_t *outlen) -{ - CURLcode result; - char *plainauth; - size_t ulen; - size_t plen; - - ulen = strlen(userp); - plen = strlen(passwdp); - - plainauth = malloc(2 * ulen + plen + 2); - if(!plainauth) { - *outlen = 0; - *outptr = NULL; - return CURLE_OUT_OF_MEMORY; - } - - /* Calculate the reply */ - memcpy(plainauth, userp, ulen); - plainauth[ulen] = '\0'; - memcpy(plainauth + ulen + 1, userp, ulen); - plainauth[2 * ulen + 1] = '\0'; - memcpy(plainauth + 2 * ulen + 2, passwdp, plen); - - /* Base64 encode the reply */ - result = Curl_base64_encode(data, plainauth, 2 * ulen + plen + 2, outptr, - outlen); - free(plainauth); - return result; -} - -/* - * sasl_create_login_message() - * - * This is used to generate an already encoded LOGIN message containing the - * user name or password ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * valuep [in] - The user name or user's password. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -static CURLcode sasl_create_login_message(struct SessionHandle *data, - const char *valuep, char **outptr, - size_t *outlen) -{ - size_t vlen = strlen(valuep); - - if(!vlen) { - /* Calculate an empty reply */ - *outptr = strdup("="); - if(*outptr) { - *outlen = (size_t) 1; - return CURLE_OK; - } - - *outlen = 0; - return CURLE_OUT_OF_MEMORY; - } - - /* Base64 encode the value */ - return Curl_base64_encode(data, valuep, vlen, outptr, outlen); -} - -/* - * sasl_create_external_message() - * - * This is used to generate an already encoded EXTERNAL message containing - * the user name ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * user [in] - The user name. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -static CURLcode sasl_create_external_message(struct SessionHandle *data, - const char *user, char **outptr, - size_t *outlen) -{ - /* This is the same formatting as the login message. */ - return sasl_create_login_message(data, user, outptr, outlen); -} - -#ifndef CURL_DISABLE_CRYPTO_AUTH - /* - * sasl_decode_cram_md5_message() - * - * This is used to decode an already encoded CRAM-MD5 challenge message. - * - * Parameters: - * - * chlg64 [in] - The base64 encoded challenge message. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -static CURLcode sasl_decode_cram_md5_message(const char *chlg64, char **outptr, - size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t chlg64len = strlen(chlg64); - - *outptr = NULL; - *outlen = 0; - - /* Decode the challenge if necessary */ - if(chlg64len && *chlg64 != '=') - result = Curl_base64_decode(chlg64, (unsigned char **) outptr, outlen); - - return result; - } - - /* - * sasl_create_cram_md5_message() - * - * This is used to generate an already encoded CRAM-MD5 response message ready - * for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * chlg [in] - The challenge. - * userp [in] - The user name. - * passdwp [in] - The user's password. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -static CURLcode sasl_create_cram_md5_message(struct SessionHandle *data, - const char *chlg, - const char *userp, - const char *passwdp, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t chlglen = 0; - HMAC_context *ctxt; - unsigned char digest[MD5_DIGEST_LEN]; - char *response; - - if(chlg) - chlglen = strlen(chlg); - - /* Compute the digest using the password as the key */ - ctxt = Curl_HMAC_init(Curl_HMAC_MD5, - (const unsigned char *) passwdp, - curlx_uztoui(strlen(passwdp))); - if(!ctxt) - return CURLE_OUT_OF_MEMORY; - - /* Update the digest with the given challenge */ - if(chlglen > 0) - Curl_HMAC_update(ctxt, (const unsigned char *) chlg, - curlx_uztoui(chlglen)); - - /* Finalise the digest */ - Curl_HMAC_final(ctxt, digest); - - /* Generate the response */ - response = aprintf( - "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - userp, digest[0], digest[1], digest[2], digest[3], digest[4], - digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], - digest[11], digest[12], digest[13], digest[14], digest[15]); - if(!response) - return CURLE_OUT_OF_MEMORY; - - /* Base64 encode the response */ - result = Curl_base64_encode(data, response, 0, outptr, outlen); - - free(response); - - return result; -} - -#ifndef USE_WINDOWS_SSPI -/* - * sasl_decode_digest_md5_message() - * - * This is used internally to decode an already encoded DIGEST-MD5 challenge - * message into the seperate attributes. - * - * Parameters: - * - * chlg64 [in] - The base64 encoded challenge message. - * nonce [in/out] - The buffer where the nonce will be stored. - * nlen [in] - The length of the nonce buffer. - * realm [in/out] - The buffer where the realm will be stored. - * rlen [in] - The length of the realm buffer. - * alg [in/out] - The buffer where the algorithm will be stored. - * alen [in] - The length of the algorithm buffer. - * qop [in/out] - The buffer where the qop-options will be stored. - * qlen [in] - The length of the qop buffer. - * - * Returns CURLE_OK on success. - */ -static CURLcode sasl_decode_digest_md5_message(const char *chlg64, - char *nonce, size_t nlen, - char *realm, size_t rlen, - char *alg, size_t alen, - char *qop, size_t qlen) -{ - CURLcode result = CURLE_OK; - unsigned char *chlg = NULL; - size_t chlglen = 0; - size_t chlg64len = strlen(chlg64); - - /* Decode the base-64 encoded challenge message */ - if(chlg64len && *chlg64 != '=') { - result = Curl_base64_decode(chlg64, &chlg, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!chlg) - return CURLE_BAD_CONTENT_ENCODING; - - /* Retrieve nonce string from the challenge */ - if(!sasl_digest_get_key_value((char *)chlg, "nonce=\"", nonce, nlen, '\"')) { - free(chlg); - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Retrieve realm string from the challenge */ - if(!sasl_digest_get_key_value((char *)chlg, "realm=\"", realm, rlen, '\"')) { - /* Challenge does not have a realm, set empty string [RFC2831] page 6 */ - strcpy(realm, ""); - } - - /* Retrieve algorithm string from the challenge */ - if(!sasl_digest_get_key_value((char *)chlg, "algorithm=", alg, alen, ',')) { - free(chlg); - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Retrieve qop-options string from the challenge */ - if(!sasl_digest_get_key_value((char *)chlg, "qop=\"", qop, qlen, '\"')) { - free(chlg); - return CURLE_BAD_CONTENT_ENCODING; - } - - free(chlg); - - return CURLE_OK; -} - -/* - * Curl_sasl_create_digest_md5_message() - * - * This is used to generate an already encoded DIGEST-MD5 response message - * ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * chlg64 [in] - The base64 encoded challenge message. - * userp [in] - The user name. - * passdwp [in] - The user's password. - * service [in] - The service type such as www, smtp, pop or imap. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, - const char *chlg64, - const char *userp, - const char *passwdp, - const char *service, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t i; - MD5_context *ctxt; - char *response = NULL; - unsigned char digest[MD5_DIGEST_LEN]; - char HA1_hex[2 * MD5_DIGEST_LEN + 1]; - char HA2_hex[2 * MD5_DIGEST_LEN + 1]; - char resp_hash_hex[2 * MD5_DIGEST_LEN + 1]; - char nonce[64]; - char realm[128]; - char algorithm[64]; - char qop_options[64]; - int qop_values; - char cnonce[33]; - unsigned int entropy[4]; - char nonceCount[] = "00000001"; - char method[] = "AUTHENTICATE"; - char qop[] = DIGEST_QOP_VALUE_STRING_AUTH; - char *spn = NULL; - - /* Decode the challange message */ - result = sasl_decode_digest_md5_message(chlg64, nonce, sizeof(nonce), - realm, sizeof(realm), - algorithm, sizeof(algorithm), - qop_options, sizeof(qop_options)); - if(result) - return result; - - /* We only support md5 sessions */ - if(strcmp(algorithm, "md5-sess") != 0) - return CURLE_BAD_CONTENT_ENCODING; - - /* Get the qop-values from the qop-options */ - result = sasl_digest_get_qop_values(qop_options, &qop_values); - if(result) - return result; - - /* We only support auth quality-of-protection */ - if(!(qop_values & DIGEST_QOP_VALUE_AUTH)) - return CURLE_BAD_CONTENT_ENCODING; - - /* Generate 16 bytes of random data */ - entropy[0] = Curl_rand(data); - entropy[1] = Curl_rand(data); - entropy[2] = Curl_rand(data); - entropy[3] = Curl_rand(data); - - /* Convert the random data into a 32 byte hex string */ - snprintf(cnonce, sizeof(cnonce), "%08x%08x%08x%08x", - entropy[0], entropy[1], entropy[2], entropy[3]); - - /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */ - ctxt = Curl_MD5_init(Curl_DIGEST_MD5); - if(!ctxt) - return CURLE_OUT_OF_MEMORY; - - Curl_MD5_update(ctxt, (const unsigned char *) userp, - curlx_uztoui(strlen(userp))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) realm, - curlx_uztoui(strlen(realm))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) passwdp, - curlx_uztoui(strlen(passwdp))); - Curl_MD5_final(ctxt, digest); - - ctxt = Curl_MD5_init(Curl_DIGEST_MD5); - if(!ctxt) - return CURLE_OUT_OF_MEMORY; - - Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) nonce, - curlx_uztoui(strlen(nonce))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) cnonce, - curlx_uztoui(strlen(cnonce))); - Curl_MD5_final(ctxt, digest); - - /* Convert calculated 16 octet hex into 32 bytes string */ - for(i = 0; i < MD5_DIGEST_LEN; i++) - snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]); - - /* Generate our SPN */ - spn = Curl_sasl_build_spn(service, realm); - if(!spn) - return CURLE_OUT_OF_MEMORY; - - /* Calculate H(A2) */ - ctxt = Curl_MD5_init(Curl_DIGEST_MD5); - if(!ctxt) { - free(spn); - - return CURLE_OUT_OF_MEMORY; - } - - Curl_MD5_update(ctxt, (const unsigned char *) method, - curlx_uztoui(strlen(method))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) spn, - curlx_uztoui(strlen(spn))); - Curl_MD5_final(ctxt, digest); - - for(i = 0; i < MD5_DIGEST_LEN; i++) - snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]); - - /* Now calculate the response hash */ - ctxt = Curl_MD5_init(Curl_DIGEST_MD5); - if(!ctxt) { - free(spn); - - return CURLE_OUT_OF_MEMORY; - } - - Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) nonce, - curlx_uztoui(strlen(nonce))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - - Curl_MD5_update(ctxt, (const unsigned char *) nonceCount, - curlx_uztoui(strlen(nonceCount))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) cnonce, - curlx_uztoui(strlen(cnonce))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) qop, - curlx_uztoui(strlen(qop))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - - Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN); - Curl_MD5_final(ctxt, digest); - - for(i = 0; i < MD5_DIGEST_LEN; i++) - snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]); - - /* Generate the response */ - response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\"," - "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s," - "qop=%s", - userp, realm, nonce, - cnonce, nonceCount, spn, resp_hash_hex, qop); - free(spn); - if(!response) - return CURLE_OUT_OF_MEMORY; - - /* Base64 encode the response */ - result = Curl_base64_encode(data, response, 0, outptr, outlen); - - free(response); - - return result; -} - -/* - * Curl_sasl_decode_digest_http_message() - * - * This is used to decode a HTTP DIGEST challenge message into the seperate - * attributes. - * - * Parameters: - * - * chlg [in] - The challenge message. - * digest [in/out] - The digest data struct being used and modified. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_decode_digest_http_message(const char *chlg, - struct digestdata *digest) -{ - bool before = FALSE; /* got a nonce before */ - bool foundAuth = FALSE; - bool foundAuthInt = FALSE; - char *token = NULL; - char *tmp = NULL; - - /* If we already have received a nonce, keep that in mind */ - if(digest->nonce) - before = TRUE; - - /* Clean up any former leftovers and initialise to defaults */ - Curl_sasl_digest_cleanup(digest); - - for(;;) { - char value[DIGEST_MAX_VALUE_LENGTH]; - char content[DIGEST_MAX_CONTENT_LENGTH]; - - /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) - chlg++; - - /* Extract a value=content pair */ - if(!Curl_sasl_digest_get_pair(chlg, value, content, &chlg)) { - if(Curl_raw_equal(value, "nonce")) { - digest->nonce = strdup(content); - if(!digest->nonce) - return CURLE_OUT_OF_MEMORY; - } - else if(Curl_raw_equal(value, "stale")) { - if(Curl_raw_equal(content, "true")) { - digest->stale = TRUE; - digest->nc = 1; /* we make a new nonce now */ - } - } - else if(Curl_raw_equal(value, "realm")) { - digest->realm = strdup(content); - if(!digest->realm) - return CURLE_OUT_OF_MEMORY; - } - else if(Curl_raw_equal(value, "opaque")) { - digest->opaque = strdup(content); - if(!digest->opaque) - return CURLE_OUT_OF_MEMORY; - } - else if(Curl_raw_equal(value, "qop")) { - char *tok_buf; - /* Tokenize the list and choose auth if possible, use a temporary - clone of the buffer since strtok_r() ruins it */ - tmp = strdup(content); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - - token = strtok_r(tmp, ",", &tok_buf); - while(token != NULL) { - if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) { - foundAuth = TRUE; - } - else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) { - foundAuthInt = TRUE; - } - token = strtok_r(NULL, ",", &tok_buf); - } - - free(tmp); - - /* Select only auth or auth-int. Otherwise, ignore */ - if(foundAuth) { - digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH); - if(!digest->qop) - return CURLE_OUT_OF_MEMORY; - } - else if(foundAuthInt) { - digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH_INT); - if(!digest->qop) - return CURLE_OUT_OF_MEMORY; - } - } - else if(Curl_raw_equal(value, "algorithm")) { - digest->algorithm = strdup(content); - if(!digest->algorithm) - return CURLE_OUT_OF_MEMORY; - - if(Curl_raw_equal(content, "MD5-sess")) - digest->algo = CURLDIGESTALGO_MD5SESS; - else if(Curl_raw_equal(content, "MD5")) - digest->algo = CURLDIGESTALGO_MD5; - else - return CURLE_BAD_CONTENT_ENCODING; - } - else { - /* unknown specifier, ignore it! */ - } - } - else - break; /* we're done here */ - - /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) - chlg++; - - /* Allow the list to be comma-separated */ - if(',' == *chlg) - chlg++; - } - - /* We had a nonce since before, and we got another one now without - 'stale=true'. This means we provided bad credentials in the previous - request */ - if(before && !digest->stale) - return CURLE_BAD_CONTENT_ENCODING; - - /* We got this header without a nonce, that's a bad Digest line! */ - if(!digest->nonce) - return CURLE_BAD_CONTENT_ENCODING; - - return CURLE_OK; -} - -/* - * Curl_sasl_create_digest_http_message() - * - * This is used to generate a HTTP DIGEST response message ready for sending - * to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name. - * passdwp [in] - The user's password. - * request [in] - The HTTP request. - * uripath [in] - The path of the HTTP uri. - * digest [in/out] - The digest data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - const unsigned char *request, - const unsigned char *uripath, - struct digestdata *digest, - char **outptr, size_t *outlen) -{ - CURLcode result; - unsigned char md5buf[16]; /* 16 bytes/128 bits */ - unsigned char request_digest[33]; - unsigned char *md5this; - unsigned char ha1[33];/* 32 digits and 1 zero byte */ - unsigned char ha2[33];/* 32 digits and 1 zero byte */ - char cnoncebuf[33]; - char *cnonce = NULL; - size_t cnonce_sz = 0; - char *userp_quoted; - char *response = NULL; - char *tmp = NULL; - - if(!digest->nc) - digest->nc = 1; - - if(!digest->cnonce) { - snprintf(cnoncebuf, sizeof(cnoncebuf), "%08x%08x%08x%08x", - Curl_rand(data), Curl_rand(data), - Curl_rand(data), Curl_rand(data)); - - result = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), - &cnonce, &cnonce_sz); - if(result) - return result; - - digest->cnonce = cnonce; - } - - /* - if the algorithm is "MD5" or unspecified (which then defaults to MD5): - - A1 = unq(username-value) ":" unq(realm-value) ":" passwd - - if the algorithm is "MD5-sess" then: - - A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd ) - ":" unq(nonce-value) ":" unq(cnonce-value) - */ - - md5this = (unsigned char *) - aprintf("%s:%s:%s", userp, digest->realm, passwdp); - if(!md5this) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - free(md5this); - sasl_digest_md5_to_ascii(md5buf, ha1); - - if(digest->algo == CURLDIGESTALGO_MD5SESS) { - /* nonce and cnonce are OUTSIDE the hash */ - tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, tmp); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, (unsigned char *)tmp); - free(tmp); - sasl_digest_md5_to_ascii(md5buf, ha1); - } - - /* - If the "qop" directive's value is "auth" or is unspecified, then A2 is: - - A2 = Method ":" digest-uri-value - - If the "qop" value is "auth-int", then A2 is: - - A2 = Method ":" digest-uri-value ":" H(entity-body) - - (The "Method" value is the HTTP request method as specified in section - 5.1.1 of RFC 2616) - */ - - md5this = (unsigned char *)aprintf("%s:%s", request, uripath); - - if(digest->qop && Curl_raw_equal(digest->qop, "auth-int")) { - /* We don't support auth-int for PUT or POST at the moment. - TODO: replace md5 of empty string with entity-body for PUT/POST */ - unsigned char *md5this2 = (unsigned char *) - aprintf("%s:%s", md5this, "d41d8cd98f00b204e9800998ecf8427e"); - free(md5this); - md5this = md5this2; - } - - if(!md5this) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - free(md5this); - sasl_digest_md5_to_ascii(md5buf, ha2); - - if(digest->qop) { - md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s", - ha1, - digest->nonce, - digest->nc, - digest->cnonce, - digest->qop, - ha2); - } - else { - md5this = (unsigned char *)aprintf("%s:%s:%s", - ha1, - digest->nonce, - ha2); - } - - if(!md5this) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - free(md5this); - sasl_digest_md5_to_ascii(md5buf, request_digest); - - /* for test case 64 (snooped from a Mozilla 1.3a request) - - Authorization: Digest username="testuser", realm="testrealm", \ - nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca" - - Digest parameters are all quoted strings. Username which is provided by - the user will need double quotes and backslashes within it escaped. For - the other fields, this shouldn't be an issue. realm, nonce, and opaque - are copied as is from the server, escapes and all. cnonce is generated - with web-safe characters. uri is already percent encoded. nc is 8 hex - characters. algorithm and qop with standard values only contain web-safe - chracters. - */ - userp_quoted = sasl_digest_string_quoted(userp); - if(!userp_quoted) - return CURLE_OUT_OF_MEMORY; - - if(digest->qop) { - response = aprintf("username=\"%s\", " - "realm=\"%s\", " - "nonce=\"%s\", " - "uri=\"%s\", " - "cnonce=\"%s\", " - "nc=%08x, " - "qop=%s, " - "response=\"%s\"", - userp_quoted, - digest->realm, - digest->nonce, - uripath, - digest->cnonce, - digest->nc, - digest->qop, - request_digest); - - if(Curl_raw_equal(digest->qop, "auth")) - digest->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 - padded which tells to the server how many times you are - using the same nonce in the qop=auth mode */ - } - else { - response = aprintf("username=\"%s\", " - "realm=\"%s\", " - "nonce=\"%s\", " - "uri=\"%s\", " - "response=\"%s\"", - userp_quoted, - digest->realm, - digest->nonce, - uripath, - request_digest); - } - free(userp_quoted); - if(!response) - return CURLE_OUT_OF_MEMORY; - - /* Add the optional fields */ - if(digest->opaque) { - /* Append the opaque */ - tmp = aprintf("%s, opaque=\"%s\"", response, digest->opaque); - free(response); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - - response = tmp; - } - - if(digest->algorithm) { - /* Append the algorithm */ - tmp = aprintf("%s, algorithm=\"%s\"", response, digest->algorithm); - free(response); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - - response = tmp; - } - - /* Return the output */ - *outptr = response; - *outlen = strlen(response); - - return CURLE_OK; -} - -/* - * Curl_sasl_digest_cleanup() - * - * This is used to clean up the digest specific data. - * - * Parameters: - * - * digest [in/out] - The digest data struct being cleaned up. - * - */ -void Curl_sasl_digest_cleanup(struct digestdata *digest) -{ - Curl_safefree(digest->nonce); - Curl_safefree(digest->cnonce); - Curl_safefree(digest->realm); - Curl_safefree(digest->opaque); - Curl_safefree(digest->qop); - Curl_safefree(digest->algorithm); - - digest->nc = 0; - digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */ - digest->stale = FALSE; /* default means normal, not stale */ -} -#endif /* !USE_WINDOWS_SSPI */ - -#endif /* CURL_DISABLE_CRYPTO_AUTH */ - -#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) -/* - * Curl_sasl_ntlm_cleanup() - * - * This is used to clean up the ntlm specific data. - * - * Parameters: - * - * ntlm [in/out] - The ntlm data struct being cleaned up. - * - */ -void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm) -{ - /* Free the target info */ - Curl_safefree(ntlm->target_info); - - /* Reset any variables */ - ntlm->target_info_len = 0; -} -#endif /* USE_NTLM && !USE_WINDOWS_SSPI*/ - -/* - * sasl_create_xoauth2_message() - * - * This is used to generate an already encoded OAuth 2.0 message ready for - * sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * user [in] - The user name. - * bearer [in] - The bearer token. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -static CURLcode sasl_create_xoauth2_message(struct SessionHandle *data, - const char *user, - const char *bearer, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - char *xoauth = NULL; - - /* Generate the message */ - xoauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer); - if(!xoauth) - return CURLE_OUT_OF_MEMORY; - - /* Base64 encode the reply */ - result = Curl_base64_encode(data, xoauth, strlen(xoauth), outptr, outlen); - - free(xoauth); - - return result; -} - /* * Curl_sasl_cleanup() * @@ -1206,14 +85,14 @@ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused) #if defined(USE_KERBEROS5) /* Cleanup the gssapi structure */ if(authused == SASL_MECH_GSSAPI) { - Curl_sasl_gssapi_cleanup(&conn->krb5); + Curl_auth_gssapi_cleanup(&conn->krb5); } #endif #if defined(USE_NTLM) - /* Cleanup the ntlm structure */ + /* Cleanup the NTLM structure */ if(authused == SASL_MECH_NTLM) { - Curl_sasl_ntlm_cleanup(&conn->ntlm); + Curl_auth_ntlm_cleanup(&conn->ntlm); } #endif @@ -1275,18 +154,20 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, if(!len) return CURLE_URL_MALFORMAT; - if(sasl->resetprefs) { - sasl->resetprefs = FALSE; - sasl->prefmech = SASL_AUTH_NONE; - } + if(sasl->resetprefs) { + sasl->resetprefs = FALSE; + sasl->prefmech = SASL_AUTH_NONE; + } - if(strnequal(value, "*", len)) - sasl->prefmech = SASL_AUTH_DEFAULT; - else if((mechbit = Curl_sasl_decode_mech(value, len, &mechlen)) && - mechlen == len) + if(strnequal(value, "*", len)) + sasl->prefmech = SASL_AUTH_DEFAULT; + else { + mechbit = Curl_sasl_decode_mech(value, len, &mechlen); + if(mechbit && mechlen == len) sasl->prefmech |= mechbit; else result = CURLE_URL_MALFORMAT; + } return result; } @@ -1332,7 +213,8 @@ static void state(struct SASL *sasl, struct connectdata *conn, "GSSAPI", "GSSAPI_TOKEN", "GSSAPI_NO_DATA", - "XOAUTH2", + "OAUTH2", + "OAUTH2_RESP", "CANCEL", "FINAL", /* LAST */ @@ -1375,13 +257,18 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, bool force_ir, saslprogress *progress) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; unsigned int enabledmechs; const char *mech = NULL; char *resp = NULL; size_t len = 0; saslstate state1 = SASL_STOP; saslstate state2 = SASL_FINAL; +#if defined(USE_KERBEROS5) + const char* service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : + sasl->params->service; +#endif sasl->force_ir = force_ir; /* Latch for future use */ sasl->authused = 0; /* No mechanism used yet */ @@ -1396,7 +283,8 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, sasl->authused = SASL_MECH_EXTERNAL; if(force_ir || data->set.sasl_ir) - result = sasl_create_external_message(data, conn->user, &resp, &len); + result = Curl_auth_create_external_message(data, conn->user, &resp, + &len); } else if(conn->bits.user_passwd) { #if defined(USE_KERBEROS5) @@ -1408,9 +296,11 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, sasl->authused = SASL_MECH_GSSAPI; if(force_ir || data->set.sasl_ir) - result = Curl_sasl_create_gssapi_user_message(data, conn->user, + result = Curl_auth_create_gssapi_user_message(data, conn->user, conn->passwd, - sasl->params->service, + service, + data->easy_conn-> + host.name, sasl->mutual_auth, NULL, &conn->krb5, &resp, &len); @@ -1438,20 +328,34 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, sasl->authused = SASL_MECH_NTLM; if(force_ir || data->set.sasl_ir) - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, + result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd, &conn->ntlm, &resp, &len); } else #endif - if((enabledmechs & SASL_MECH_XOAUTH2) || conn->xoauth2_bearer) { + if((enabledmechs & SASL_MECH_OAUTHBEARER) && conn->oauth_bearer) { + mech = SASL_MECH_STRING_OAUTHBEARER; + state1 = SASL_OAUTH2; + state2 = SASL_OAUTH2_RESP; + sasl->authused = SASL_MECH_OAUTHBEARER; + + if(force_ir || data->set.sasl_ir) + result = Curl_auth_create_oauth_bearer_message(data, conn->user, + conn->host.name, + conn->port, + conn->oauth_bearer, + &resp, &len); + } + else if((enabledmechs & SASL_MECH_XOAUTH2) && conn->oauth_bearer) { mech = SASL_MECH_STRING_XOAUTH2; - state1 = SASL_XOAUTH2; + state1 = SASL_OAUTH2; sasl->authused = SASL_MECH_XOAUTH2; if(force_ir || data->set.sasl_ir) - result = sasl_create_xoauth2_message(data, conn->user, - conn->xoauth2_bearer, - &resp, &len); + result = Curl_auth_create_oauth_bearer_message(data, conn->user, + NULL, 0, + conn->oauth_bearer, + &resp, &len); } else if(enabledmechs & SASL_MECH_LOGIN) { mech = SASL_MECH_STRING_LOGIN; @@ -1460,7 +364,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, sasl->authused = SASL_MECH_LOGIN; if(force_ir || data->set.sasl_ir) - result = sasl_create_login_message(data, conn->user, &resp, &len); + result = Curl_auth_create_login_message(data, conn->user, &resp, &len); } else if(enabledmechs & SASL_MECH_PLAIN) { mech = SASL_MECH_STRING_PLAIN; @@ -1468,24 +372,22 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, sasl->authused = SASL_MECH_PLAIN; if(force_ir || data->set.sasl_ir) - result = sasl_create_plain_message(data, conn->user, conn->passwd, - &resp, &len); + result = Curl_auth_create_plain_message(data, conn->user, conn->passwd, + &resp, &len); } } - if(!result) { + if(!result && mech) { if(resp && sasl->params->maxirlen && strlen(mech) + len > sasl->params->maxirlen) { free(resp); resp = NULL; } - if(mech) { - result = sasl->params->sendauth(conn, mech, resp); - if(!result) { - *progress = SASL_INPROGRESS; - state(sasl, conn, resp? state2: state1); - } + result = sasl->params->sendauth(conn, mech, resp); + if(!result) { + *progress = SASL_INPROGRESS; + state(sasl, conn, resp ? state2 : state1); } } @@ -1503,7 +405,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, int code, saslprogress *progress) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; saslstate newstate = SASL_FINAL; char *resp = NULL; #if !defined(CURL_DISABLE_CRYPTO_AUTH) @@ -1511,6 +413,11 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, char *chlg = NULL; size_t chlglen = 0; #endif +#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) + const char *service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : + sasl->params->service; +#endif size_t len = 0; *progress = SASL_INPROGRESS; @@ -1523,7 +430,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, return result; } - if(sasl->state != SASL_CANCEL && code != sasl->params->contcode) { + if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP && + code != sasl->params->contcode) { *progress = SASL_DONE; state(sasl, conn, SASL_STOP); return CURLE_LOGIN_DENIED; @@ -1534,39 +442,41 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, *progress = SASL_DONE; return result; case SASL_PLAIN: - result = sasl_create_plain_message(data, conn->user, conn->passwd, &resp, - &len); + result = Curl_auth_create_plain_message(data, conn->user, conn->passwd, + &resp, + &len); break; case SASL_LOGIN: - result = sasl_create_login_message(data, conn->user, &resp, &len); + result = Curl_auth_create_login_message(data, conn->user, &resp, &len); newstate = SASL_LOGIN_PASSWD; break; case SASL_LOGIN_PASSWD: - result = sasl_create_login_message(data, conn->passwd, &resp, &len); + result = Curl_auth_create_login_message(data, conn->passwd, &resp, &len); break; case SASL_EXTERNAL: - result = sasl_create_external_message(data, conn->user, &resp, &len); + result = Curl_auth_create_external_message(data, conn->user, &resp, &len); break; #ifndef CURL_DISABLE_CRYPTO_AUTH case SASL_CRAMMD5: sasl->params->getmessage(data->state.buffer, &serverdata); - result = sasl_decode_cram_md5_message(serverdata, &chlg, &chlglen); + result = Curl_auth_decode_cram_md5_message(serverdata, &chlg, &chlglen); if(!result) - result = sasl_create_cram_md5_message(data, chlg, conn->user, - conn->passwd, &resp, &len); + result = Curl_auth_create_cram_md5_message(data, chlg, conn->user, + conn->passwd, &resp, &len); free(chlg); break; case SASL_DIGESTMD5: sasl->params->getmessage(data->state.buffer, &serverdata); - result = Curl_sasl_create_digest_md5_message(data, serverdata, + result = Curl_auth_create_digest_md5_message(data, serverdata, conn->user, conn->passwd, - sasl->params->service, + service, &resp, &len); newstate = SASL_DIGESTMD5_RESP; break; case SASL_DIGESTMD5_RESP: - if(!(resp = strdup(""))) + resp = strdup(""); + if(!resp) result = CURLE_OUT_OF_MEMORY; break; #endif @@ -1574,17 +484,17 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, #ifdef USE_NTLM case SASL_NTLM: /* Create the type-1 message */ - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, + result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd, &conn->ntlm, &resp, &len); newstate = SASL_NTLM_TYPE2MSG; break; case SASL_NTLM_TYPE2MSG: /* Decode the type-2 message */ sasl->params->getmessage(data->state.buffer, &serverdata); - result = Curl_sasl_decode_ntlm_type2_message(data, serverdata, + result = Curl_auth_decode_ntlm_type2_message(data, serverdata, &conn->ntlm); if(!result) - result = Curl_sasl_create_ntlm_type3_message(data, conn->user, + result = Curl_auth_create_ntlm_type3_message(data, conn->user, conn->passwd, &conn->ntlm, &resp, &len); break; @@ -1592,9 +502,10 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, #if defined(USE_KERBEROS5) case SASL_GSSAPI: - result = Curl_sasl_create_gssapi_user_message(data, conn->user, + result = Curl_auth_create_gssapi_user_message(data, conn->user, conn->passwd, - sasl->params->service, + service, + data->easy_conn->host.name, sasl->mutual_auth, NULL, &conn->krb5, &resp, &len); @@ -1605,7 +516,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, if(sasl->mutual_auth) { /* Decode the user token challenge and create the optional response message */ - result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL, + result = Curl_auth_create_gssapi_user_message(data, NULL, NULL, + NULL, NULL, sasl->mutual_auth, serverdata, &conn->krb5, &resp, &len); @@ -1613,24 +525,60 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, } else /* Decode the security challenge and create the response message */ - result = Curl_sasl_create_gssapi_security_message(data, serverdata, + result = Curl_auth_create_gssapi_security_message(data, serverdata, &conn->krb5, &resp, &len); break; case SASL_GSSAPI_NO_DATA: sasl->params->getmessage(data->state.buffer, &serverdata); /* Decode the security challenge and create the response message */ - result = Curl_sasl_create_gssapi_security_message(data, serverdata, + result = Curl_auth_create_gssapi_security_message(data, serverdata, &conn->krb5, &resp, &len); break; #endif - case SASL_XOAUTH2: + case SASL_OAUTH2: /* Create the authorisation message */ - result = sasl_create_xoauth2_message(data, conn->user, - conn->xoauth2_bearer, &resp, &len); + if(sasl->authused == SASL_MECH_OAUTHBEARER) { + result = Curl_auth_create_oauth_bearer_message(data, conn->user, + conn->host.name, + conn->port, + conn->oauth_bearer, + &resp, &len); + + /* Failures maybe sent by the server as continuations for OAUTHBEARER */ + newstate = SASL_OAUTH2_RESP; + } + else + result = Curl_auth_create_oauth_bearer_message(data, conn->user, + NULL, 0, + conn->oauth_bearer, + &resp, &len); break; + + case SASL_OAUTH2_RESP: + /* The continuation is optional so check the response code */ + if(code == sasl->params->finalcode) { + /* Final response was received so we are done */ + *progress = SASL_DONE; + state(sasl, conn, SASL_STOP); + return result; + } + else if(code == sasl->params->contcode) { + /* Acknowledge the continuation by sending a 0x01 response base64 + encoded */ + resp = strdup("AQ=="); + if(!resp) + result = CURLE_OUT_OF_MEMORY; + break; + } + else { + *progress = SASL_DONE; + state(sasl, conn, SASL_STOP); + return CURLE_LOGIN_DENIED; + } + case SASL_CANCEL: /* Remove the offending mechanism from the supported list */ sasl->authmechs ^= sasl->authused; diff --git a/lib/curl_sasl.h b/lib/curl_sasl.h index 117d60e..7647a48 100644 --- a/lib/curl_sasl.h +++ b/lib/curl_sasl.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -24,21 +24,9 @@ #include -struct SessionHandle; +struct Curl_easy; struct connectdata; -#if !defined(CURL_DISABLE_CRYPTO_AUTH) -struct digestdata; -#endif - -#if defined(USE_NTLM) -struct ntlmdata; -#endif - -#if defined(USE_KERBEROS5) -struct kerberos5data; -#endif - /* Authentication mechanism flags */ #define SASL_MECH_LOGIN (1 << 0) #define SASL_MECH_PLAIN (1 << 1) @@ -48,32 +36,23 @@ struct kerberos5data; #define SASL_MECH_EXTERNAL (1 << 5) #define SASL_MECH_NTLM (1 << 6) #define SASL_MECH_XOAUTH2 (1 << 7) +#define SASL_MECH_OAUTHBEARER (1 << 8) /* Authentication mechanism values */ #define SASL_AUTH_NONE 0 #define SASL_AUTH_ANY ~0U -#define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & \ - ~(SASL_MECH_EXTERNAL | SASL_MECH_XOAUTH2)) +#define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL) /* Authentication mechanism strings */ -#define SASL_MECH_STRING_LOGIN "LOGIN" -#define SASL_MECH_STRING_PLAIN "PLAIN" -#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5" -#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5" -#define SASL_MECH_STRING_GSSAPI "GSSAPI" -#define SASL_MECH_STRING_EXTERNAL "EXTERNAL" -#define SASL_MECH_STRING_NTLM "NTLM" -#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2" - -#if !defined(CURL_DISABLE_CRYPTO_AUTH) -#define DIGEST_MAX_VALUE_LENGTH 256 -#define DIGEST_MAX_CONTENT_LENGTH 1024 -#endif - -enum { - CURLDIGESTALGO_MD5, - CURLDIGESTALGO_MD5SESS -}; +#define SASL_MECH_STRING_LOGIN "LOGIN" +#define SASL_MECH_STRING_PLAIN "PLAIN" +#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5" +#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5" +#define SASL_MECH_STRING_GSSAPI "GSSAPI" +#define SASL_MECH_STRING_EXTERNAL "EXTERNAL" +#define SASL_MECH_STRING_NTLM "NTLM" +#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2" +#define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER" /* SASL machine states */ typedef enum { @@ -90,7 +69,8 @@ typedef enum { SASL_GSSAPI, SASL_GSSAPI_TOKEN, SASL_GSSAPI_NO_DATA, - SASL_XOAUTH2, + SASL_OAUTH2, + SASL_OAUTH2_RESP, SASL_CANCEL, SASL_FINAL } saslstate; @@ -134,97 +114,6 @@ struct SASL { (wordlen == (sizeof(mech) - 1) / sizeof(char) && \ !memcmp(line, mech, wordlen)) -/* This is used to build a SPN string */ -#if !defined(USE_WINDOWS_SSPI) -char *Curl_sasl_build_spn(const char *service, const char *instance); -#else -TCHAR *Curl_sasl_build_spn(const char *service, const char *instance); -#endif - -/* This is used to extract the realm from a challenge message */ -int Curl_sasl_digest_get_pair(const char *str, char *value, char *content, - const char **endptr); - -#if defined(HAVE_GSSAPI) -char *Curl_sasl_build_gssapi_spn(const char *service, const char *host); -#endif - -#ifndef CURL_DISABLE_CRYPTO_AUTH - -/* This is used to generate a base64 encoded DIGEST-MD5 response message */ -CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, - const char *chlg64, - const char *userp, - const char *passwdp, - const char *service, - char **outptr, size_t *outlen); - -/* This is used to decode a HTTP DIGEST challenge message */ -CURLcode Curl_sasl_decode_digest_http_message(const char *chlg, - struct digestdata *digest); - -/* This is used to generate a HTTP DIGEST response message */ -CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - const unsigned char *request, - const unsigned char *uri, - struct digestdata *digest, - char **outptr, size_t *outlen); - -/* This is used to clean up the digest specific data */ -void Curl_sasl_digest_cleanup(struct digestdata *digest); -#endif - -#ifdef USE_NTLM -/* This is used to generate a base64 encoded NTLM type-1 message */ -CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, - size_t *outlen); - -/* This is used to decode a base64 encoded NTLM type-2 message */ -CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data, - const char *type2msg, - struct ntlmdata *ntlm); - -/* This is used to generate a base64 encoded NTLM type-3 message */ -CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, size_t *outlen); - -/* This is used to clean up the ntlm specific data */ -void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm); - -#endif /* USE_NTLM */ - -#if defined(USE_KERBEROS5) -/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token - message */ -CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - const char *service, - const bool mutual, - const char *chlg64, - struct kerberos5data *krb5, - char **outptr, size_t *outlen); - -/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security - token message */ -CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, - const char *input, - struct kerberos5data *krb5, - char **outptr, - size_t *outlen); - -/* This is used to clean up the gssapi specific data */ -void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5); -#endif /* USE_KERBEROS5 */ - /* This is used to cleanup any libraries or curl modules used by the sasl functions */ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused); diff --git a/lib/curl_sasl_sspi.c b/lib/curl_sasl_sspi.c deleted file mode 100644 index b149530..0000000 --- a/lib/curl_sasl_sspi.c +++ /dev/null @@ -1,1281 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2014 - 2015, Daniel Stenberg, , et al. - * Copyright (C) 2014, Steve Holme, . - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * RFC2617 Basic and Digest Access Authentication - * RFC2831 DIGEST-MD5 authentication - * RFC4422 Simple Authentication and Security Layer (SASL) - * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_WINDOWS_SSPI) - -#include - -#include "curl_sasl.h" -#include "urldata.h" -#include "curl_base64.h" -#include "warnless.h" -#include "curl_multibyte.h" -#include "sendf.h" -#include "strdup.h" -#include "curl_printf.h" -#include "rawstr.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Curl_sasl_build_spn() - * - * This is used to build a SPN string in the format service/host. - * - * Parameters: - * - * serivce [in] - The service type such as www, smtp, pop or imap. - * host [in] - The host name or realm. - * - * Returns a pointer to the newly allocated SPN. - */ -TCHAR *Curl_sasl_build_spn(const char *service, const char *host) -{ - char *utf8_spn = NULL; - TCHAR *tchar_spn = NULL; - - /* Note: We could use DsMakeSPN() or DsClientMakeSpnForTargetServer() rather - than doing this ourselves but the first is only available in Windows XP - and Windows Server 2003 and the latter is only available in Windows 2000 - but not Windows95/98/ME or Windows NT4.0 unless the Active Directory - Client Extensions are installed. As such it is far simpler for us to - formulate the SPN instead. */ - - /* Allocate our UTF8 based SPN */ - utf8_spn = aprintf("%s/%s", service, host); - if(!utf8_spn) { - return NULL; - } - - /* Allocate our TCHAR based SPN */ - tchar_spn = Curl_convert_UTF8_to_tchar(utf8_spn); - if(!tchar_spn) { - free(utf8_spn); - - return NULL; - } - - /* Release the UTF8 variant when operating with Unicode */ - Curl_unicodefree(utf8_spn); - - /* Return our newly allocated SPN */ - return tchar_spn; -} - -#if !defined(CURL_DISABLE_CRYPTO_AUTH) -/* - * Curl_sasl_create_digest_md5_message() - * - * This is used to generate an already encoded DIGEST-MD5 response message - * ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * chlg64 [in] - The base64 encoded challenge message. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * service [in] - The service type such as www, smtp, pop or imap. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, - const char *chlg64, - const char *userp, - const char *passwdp, - const char *service, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - TCHAR *spn = NULL; - size_t chlglen = 0; - size_t token_max = 0; - unsigned char *input_token = NULL; - unsigned char *output_token = NULL; - CredHandle credentials; - CtxtHandle context; - PSecPkgInfo SecurityPackage; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; - SecBuffer chlg_buf; - SecBuffer resp_buf; - SecBufferDesc chlg_desc; - SecBufferDesc resp_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - - /* Decode the base-64 encoded challenge message */ - if(strlen(chlg64) && *chlg64 != '=') { - result = Curl_base64_decode(chlg64, &input_token, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!input_token) { - infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Query the security package for DigestSSP */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), - &SecurityPackage); - if(status != SEC_E_OK) { - free(input_token); - - return CURLE_NOT_BUILT_IN; - } - - token_max = SecurityPackage->cbMaxToken; - - /* Release the package buffer as it is not required anymore */ - s_pSecFn->FreeContextBuffer(SecurityPackage); - - /* Allocate our response buffer */ - output_token = malloc(token_max); - if(!output_token) { - free(input_token); - - return CURLE_OUT_OF_MEMORY; - } - - /* Generate our SPN */ - spn = Curl_sasl_build_spn(service, data->easy_conn->host.name); - if(!spn) { - free(output_token); - free(input_token); - - return CURLE_OUT_OF_MEMORY; - } - - if(userp && *userp) { - /* Populate our identity structure */ - result = Curl_create_sspi_identity(userp, passwdp, &identity); - if(result) { - free(spn); - free(output_token); - free(input_token); - - return result; - } - - /* Allow proper cleanup of the identity structure */ - p_identity = &identity; - } - else - /* Use the current Windows user */ - p_identity = NULL; - - /* Acquire our credentials handle */ - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT(SP_NAME_DIGEST), - SECPKG_CRED_OUTBOUND, NULL, - p_identity, NULL, NULL, - &credentials, &expiry); - - if(status != SEC_E_OK) { - Curl_sspi_free_identity(p_identity); - free(spn); - free(output_token); - free(input_token); - - return CURLE_LOGIN_DENIED; - } - - /* Setup the challenge "input" security buffer */ - chlg_desc.ulVersion = SECBUFFER_VERSION; - chlg_desc.cBuffers = 1; - chlg_desc.pBuffers = &chlg_buf; - chlg_buf.BufferType = SECBUFFER_TOKEN; - chlg_buf.pvBuffer = input_token; - chlg_buf.cbBuffer = curlx_uztoul(chlglen); - - /* Setup the response "output" security buffer */ - resp_desc.ulVersion = SECBUFFER_VERSION; - resp_desc.cBuffers = 1; - resp_desc.pBuffers = &resp_buf; - resp_buf.BufferType = SECBUFFER_TOKEN; - resp_buf.pvBuffer = output_token; - resp_buf.cbBuffer = curlx_uztoul(token_max); - - /* Generate our response message */ - status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, - 0, 0, 0, &chlg_desc, 0, - &context, &resp_desc, &attrs, - &expiry); - - if(status == SEC_I_COMPLETE_NEEDED || - status == SEC_I_COMPLETE_AND_CONTINUE) - s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); - else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { - s_pSecFn->FreeCredentialsHandle(&credentials); - Curl_sspi_free_identity(p_identity); - free(spn); - free(output_token); - free(input_token); - - return CURLE_RECV_ERROR; - } - - /* Base64 encode the response */ - result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer, - outptr, outlen); - - /* Free our handles */ - s_pSecFn->DeleteSecurityContext(&context); - s_pSecFn->FreeCredentialsHandle(&credentials); - - /* Free the identity structure */ - Curl_sspi_free_identity(p_identity); - - /* Free the SPN */ - free(spn); - - /* Free the response buffer */ - free(output_token); - - /* Free the decoded challenge message */ - free(input_token); - - return result; -} - -/* -* Curl_override_sspi_http_realm() -* -* This is used to populate the domain in a SSPI identity structure -* The realm is extracted from the challenge message and used as the -* domain if it is not already explicitly set. -* -* Parameters: -* -* chlg [in] - The challenge message. -* identity [in/out] - The identity structure. -* -* Returns CURLE_OK on success. -*/ -CURLcode Curl_override_sspi_http_realm(const char *chlg, - SEC_WINNT_AUTH_IDENTITY *identity) -{ - xcharp_u domain, dup_domain; - - /* If domain is blank or unset, check challenge message for realm */ - if(!identity->Domain || !identity->DomainLength) { - for(;;) { - char value[DIGEST_MAX_VALUE_LENGTH]; - char content[DIGEST_MAX_CONTENT_LENGTH]; - - /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) - chlg++; - - /* Extract a value=content pair */ - if(!Curl_sasl_digest_get_pair(chlg, value, content, &chlg)) { - if(Curl_raw_equal(value, "realm")) { - - /* Setup identity's domain and length */ - domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)content); - if(!domain.tchar_ptr) - return CURLE_OUT_OF_MEMORY; - dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr); - if(!dup_domain.tchar_ptr) { - Curl_unicodefree(domain.tchar_ptr); - return CURLE_OUT_OF_MEMORY; - } - identity->Domain = dup_domain.tbyte_ptr; - identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr)); - dup_domain.tchar_ptr = NULL; - - Curl_unicodefree(domain.tchar_ptr); - } - else { - /* unknown specifier, ignore it! */ - } - } - else - break; /* we're done here */ - - /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) - chlg++; - - /* Allow the list to be comma-separated */ - if(',' == *chlg) - chlg++; - } - } - - return CURLE_OK; -} - -/* - * Curl_sasl_decode_digest_http_message() - * - * This is used to decode a HTTP DIGEST challenge message into the seperate - * attributes. - * - * Parameters: - * - * chlg [in] - The challenge message. - * digest [in/out] - The digest data struct being used and modified. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_decode_digest_http_message(const char *chlg, - struct digestdata *digest) -{ - size_t chlglen = strlen(chlg); - - /* We had an input token before and we got another one now. This means we - provided bad credentials in the previous request. */ - if(digest->input_token) - return CURLE_BAD_CONTENT_ENCODING; - - /* Simply store the challenge for use later */ - digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen); - if(!digest->input_token) - return CURLE_OUT_OF_MEMORY; - - digest->input_token_len = chlglen; - - return CURLE_OK; -} - -/* - * Curl_sasl_create_digest_http_message() - * - * This is used to generate a HTTP DIGEST response message ready for sending - * to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * request [in] - The HTTP request. - * uripath [in] - The path of the HTTP uri. - * digest [in/out] - The digest data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - const unsigned char *request, - const unsigned char *uripath, - struct digestdata *digest, - char **outptr, size_t *outlen) -{ - size_t token_max; - CredHandle credentials; - CtxtHandle context; - char *resp; - BYTE *output_token; - PSecPkgInfo SecurityPackage; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; - SecBuffer chlg_buf[3]; - SecBuffer resp_buf; - SecBufferDesc chlg_desc; - SecBufferDesc resp_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - - (void) data; - - /* Query the security package for DigestSSP */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), - &SecurityPackage); - if(status != SEC_E_OK) - return CURLE_NOT_BUILT_IN; - - token_max = SecurityPackage->cbMaxToken; - - /* Release the package buffer as it is not required anymore */ - s_pSecFn->FreeContextBuffer(SecurityPackage); - - /* Allocate the output buffer according to the max token size as indicated - by the security package */ - output_token = malloc(token_max); - if(!output_token) - return CURLE_OUT_OF_MEMORY; - - if(userp && *userp) { - /* Populate our identity structure */ - if(Curl_create_sspi_identity(userp, passwdp, &identity)) - return CURLE_OUT_OF_MEMORY; - - /* Populate our identity domain */ - if(Curl_override_sspi_http_realm((const char*)digest->input_token, - &identity)) - return CURLE_OUT_OF_MEMORY; - - /* Allow proper cleanup of the identity structure */ - p_identity = &identity; - } - else - /* Use the current Windows user */ - p_identity = NULL; - - /* Acquire our credentials handle */ - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT(SP_NAME_DIGEST), - SECPKG_CRED_OUTBOUND, NULL, - p_identity, NULL, NULL, - &credentials, &expiry); - if(status != SEC_E_OK) { - free(output_token); - - return CURLE_LOGIN_DENIED; - } - - /* Setup the challenge "input" security buffer if present */ - chlg_desc.ulVersion = SECBUFFER_VERSION; - chlg_desc.cBuffers = 3; - chlg_desc.pBuffers = chlg_buf; - chlg_buf[0].BufferType = SECBUFFER_TOKEN; - chlg_buf[0].pvBuffer = digest->input_token; - chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len); - chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; - chlg_buf[1].pvBuffer = (void *)request; - chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); - chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; - chlg_buf[2].pvBuffer = NULL; - chlg_buf[2].cbBuffer = 0; - - /* Setup the response "output" security buffer */ - resp_desc.ulVersion = SECBUFFER_VERSION; - resp_desc.cBuffers = 1; - resp_desc.pBuffers = &resp_buf; - resp_buf.BufferType = SECBUFFER_TOKEN; - resp_buf.pvBuffer = output_token; - resp_buf.cbBuffer = curlx_uztoul(token_max); - - /* Generate our reponse message */ - status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, - (TCHAR *) uripath, - ISC_REQ_USE_HTTP_STYLE, 0, 0, - &chlg_desc, 0, &context, - &resp_desc, &attrs, &expiry); - - if(status == SEC_I_COMPLETE_NEEDED || - status == SEC_I_COMPLETE_AND_CONTINUE) - s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); - else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { - s_pSecFn->FreeCredentialsHandle(&credentials); - - free(output_token); - - return CURLE_OUT_OF_MEMORY; - } - - resp = malloc(resp_buf.cbBuffer + 1); - if(!resp) { - s_pSecFn->DeleteSecurityContext(&context); - s_pSecFn->FreeCredentialsHandle(&credentials); - - free(output_token); - - return CURLE_OUT_OF_MEMORY; - } - - /* Copy the generated reponse */ - memcpy(resp, resp_buf.pvBuffer, resp_buf.cbBuffer); - resp[resp_buf.cbBuffer] = 0x00; - - /* Return the response */ - *outptr = resp; - *outlen = resp_buf.cbBuffer; - - /* Free our handles */ - s_pSecFn->DeleteSecurityContext(&context); - s_pSecFn->FreeCredentialsHandle(&credentials); - - /* Free the identity structure */ - Curl_sspi_free_identity(p_identity); - - /* Free the response buffer */ - free(output_token); - - return CURLE_OK; -} - -/* - * Curl_sasl_digest_cleanup() - * - * This is used to clean up the digest specific data. - * - * Parameters: - * - * digest [in/out] - The digest data struct being cleaned up. - * - */ -void Curl_sasl_digest_cleanup(struct digestdata *digest) -{ - /* Free the input token */ - Curl_safefree(digest->input_token); - - /* Reset any variables */ - digest->input_token_len = 0; -} -#endif /* !CURL_DISABLE_CRYPTO_AUTH */ - -#if defined USE_NTLM -/* -* Curl_sasl_create_ntlm_type1_message() -* -* This is used to generate an already encoded NTLM type-1 message ready for -* sending to the recipient. -* -* Parameters: -* -* userp [in] - The user name in the format User or Domain\User. -* passdwp [in] - The user's password. -* ntlm [in/out] - The ntlm data struct being used and modified. -* outptr [in/out] - The address where a pointer to newly allocated memory -* holding the result will be stored upon completion. -* outlen [out] - The length of the output message. -* -* Returns CURLE_OK on success. -*/ -CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, size_t *outlen) -{ - PSecPkgInfo SecurityPackage; - SecBuffer type_1_buf; - SecBufferDesc type_1_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - - /* Clean up any former leftovers and initialise to defaults */ - Curl_sasl_ntlm_cleanup(ntlm); - - /* Query the security package for NTLM */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), - &SecurityPackage); - if(status != SEC_E_OK) - return CURLE_NOT_BUILT_IN; - - ntlm->token_max = SecurityPackage->cbMaxToken; - - /* Release the package buffer as it is not required anymore */ - s_pSecFn->FreeContextBuffer(SecurityPackage); - - /* Allocate our output buffer */ - ntlm->output_token = malloc(ntlm->token_max); - if(!ntlm->output_token) - return CURLE_OUT_OF_MEMORY; - - if(userp && *userp) { - CURLcode result; - - /* Populate our identity structure */ - result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity); - if(result) - return result; - - /* Allow proper cleanup of the identity structure */ - ntlm->p_identity = &ntlm->identity; - } - else - /* Use the current Windows user */ - ntlm->p_identity = NULL; - - /* Allocate our credentials handle */ - ntlm->credentials = malloc(sizeof(CredHandle)); - if(!ntlm->credentials) - return CURLE_OUT_OF_MEMORY; - - memset(ntlm->credentials, 0, sizeof(CredHandle)); - - /* Acquire our credentials handle */ - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT(SP_NAME_NTLM), - SECPKG_CRED_OUTBOUND, NULL, - ntlm->p_identity, NULL, NULL, - ntlm->credentials, &expiry); - if(status != SEC_E_OK) - return CURLE_LOGIN_DENIED; - - /* Allocate our new context handle */ - ntlm->context = malloc(sizeof(CtxtHandle)); - if(!ntlm->context) - return CURLE_OUT_OF_MEMORY; - - memset(ntlm->context, 0, sizeof(CtxtHandle)); - - /* Setup the type-1 "output" security buffer */ - type_1_desc.ulVersion = SECBUFFER_VERSION; - type_1_desc.cBuffers = 1; - type_1_desc.pBuffers = &type_1_buf; - type_1_buf.BufferType = SECBUFFER_TOKEN; - type_1_buf.pvBuffer = ntlm->output_token; - type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max); - - /* Generate our type-1 message */ - status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL, - (TCHAR *) TEXT(""), - 0, 0, SECURITY_NETWORK_DREP, - NULL, 0, - ntlm->context, &type_1_desc, - &attrs, &expiry); - if(status == SEC_I_COMPLETE_NEEDED || - status == SEC_I_COMPLETE_AND_CONTINUE) - s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); - else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) - return CURLE_RECV_ERROR; - - /* Base64 encode the response */ - return Curl_base64_encode(NULL, (char *) ntlm->output_token, - type_1_buf.cbBuffer, outptr, outlen); -} - -/* -* Curl_sasl_decode_ntlm_type2_message() -* -* This is used to decode an already encoded NTLM type-2 message. -* -* Parameters: -* -* data [in] - The session handle. -* type2msg [in] - The base64 encoded type-2 message. -* ntlm [in/out] - The ntlm data struct being used and modified. -* -* Returns CURLE_OK on success. -*/ -CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data, - const char *type2msg, - struct ntlmdata *ntlm) -{ - CURLcode result = CURLE_OK; - unsigned char *type2 = NULL; - size_t type2_len = 0; - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) data; -#endif - - /* Decode the base-64 encoded type-2 message */ - if(strlen(type2msg) && *type2msg != '=') { - result = Curl_base64_decode(type2msg, &type2, &type2_len); - if(result) - return result; - } - - /* Ensure we have a valid type-2 message */ - if(!type2) { - infof(data, "NTLM handshake failure (empty type-2 message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Simply store the challenge for use later */ - ntlm->input_token = type2; - ntlm->input_token_len = type2_len; - - return result; -} - -/* -* Curl_sasl_create_ntlm_type3_message() -* -* This is used to generate an already encoded NTLM type-3 message ready for -* sending to the recipient. -* -* Parameters: -* -* data [in] - The session handle. -* userp [in] - The user name in the format User or Domain\User. -* passdwp [in] - The user's password. -* ntlm [in/out] - The ntlm data struct being used and modified. -* outptr [in/out] - The address where a pointer to newly allocated memory -* holding the result will be stored upon completion. -* outlen [out] - The length of the output message. -* -* Returns CURLE_OK on success. -*/ -CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - SecBuffer type_2_buf; - SecBuffer type_3_buf; - SecBufferDesc type_2_desc; - SecBufferDesc type_3_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - - (void) passwdp; - (void) userp; - - /* Setup the type-2 "input" security buffer */ - type_2_desc.ulVersion = SECBUFFER_VERSION; - type_2_desc.cBuffers = 1; - type_2_desc.pBuffers = &type_2_buf; - type_2_buf.BufferType = SECBUFFER_TOKEN; - type_2_buf.pvBuffer = ntlm->input_token; - type_2_buf.cbBuffer = curlx_uztoul(ntlm->input_token_len); - - /* Setup the type-3 "output" security buffer */ - type_3_desc.ulVersion = SECBUFFER_VERSION; - type_3_desc.cBuffers = 1; - type_3_desc.pBuffers = &type_3_buf; - type_3_buf.BufferType = SECBUFFER_TOKEN; - type_3_buf.pvBuffer = ntlm->output_token; - type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max); - - /* Generate our type-3 message */ - status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, - ntlm->context, - (TCHAR *) TEXT(""), - 0, 0, SECURITY_NETWORK_DREP, - &type_2_desc, - 0, ntlm->context, - &type_3_desc, - &attrs, &expiry); - if(status != SEC_E_OK) { - infof(data, "NTLM handshake failure (type-3 message): Status=%x\n", - status); - - return CURLE_RECV_ERROR; - } - - /* Base64 encode the response */ - result = Curl_base64_encode(data, (char *) ntlm->output_token, - type_3_buf.cbBuffer, outptr, outlen); - - Curl_sasl_ntlm_cleanup(ntlm); - - return result; -} - -/* - * Curl_sasl_ntlm_cleanup() - * - * This is used to clean up the ntlm specific data. - * - * Parameters: - * - * ntlm [in/out] - The ntlm data struct being cleaned up. - * - */ -void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm) -{ - /* Free our security context */ - if(ntlm->context) { - s_pSecFn->DeleteSecurityContext(ntlm->context); - free(ntlm->context); - ntlm->context = NULL; - } - - /* Free our credentials handle */ - if(ntlm->credentials) { - s_pSecFn->FreeCredentialsHandle(ntlm->credentials); - free(ntlm->credentials); - ntlm->credentials = NULL; - } - - /* Free our identity */ - Curl_sspi_free_identity(ntlm->p_identity); - ntlm->p_identity = NULL; - - /* Free the input and output tokens */ - Curl_safefree(ntlm->input_token); - Curl_safefree(ntlm->output_token); - - /* Reset any variables */ - ntlm->token_max = 0; -} -#endif /* USE_NTLM */ - -#if defined(USE_KERBEROS5) -/* - * Curl_sasl_create_gssapi_user_message() - * - * This is used to generate an already encoded GSSAPI (Kerberos V5) user token - * message ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * service [in] - The service type such as www, smtp, pop or imap. - * mutual_auth [in] - Flag specifing whether or not mutual authentication - * is enabled. - * chlg64 [in] - The optional base64 encoded challenge message. - * krb5 [in/out] - The gssapi data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - const char *service, - const bool mutual_auth, - const char *chlg64, - struct kerberos5data *krb5, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t chlglen = 0; - unsigned char *chlg = NULL; - CtxtHandle context; - PSecPkgInfo SecurityPackage; - SecBuffer chlg_buf; - SecBuffer resp_buf; - SecBufferDesc chlg_desc; - SecBufferDesc resp_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - - if(!krb5->credentials) { - /* Query the security package for Kerberos */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) - TEXT(SP_NAME_KERBEROS), - &SecurityPackage); - if(status != SEC_E_OK) { - return CURLE_NOT_BUILT_IN; - } - - krb5->token_max = SecurityPackage->cbMaxToken; - - /* Release the package buffer as it is not required anymore */ - s_pSecFn->FreeContextBuffer(SecurityPackage); - - /* Allocate our response buffer */ - krb5->output_token = malloc(krb5->token_max); - if(!krb5->output_token) - return CURLE_OUT_OF_MEMORY; - - /* Generate our SPN */ - krb5->spn = Curl_sasl_build_spn(service, data->easy_conn->host.name); - if(!krb5->spn) - return CURLE_OUT_OF_MEMORY; - - if(userp && *userp) { - /* Populate our identity structure */ - result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity); - if(result) - return result; - - /* Allow proper cleanup of the identity structure */ - krb5->p_identity = &krb5->identity; - } - else - /* Use the current Windows user */ - krb5->p_identity = NULL; - - /* Allocate our credentials handle */ - krb5->credentials = malloc(sizeof(CredHandle)); - if(!krb5->credentials) - return CURLE_OUT_OF_MEMORY; - - memset(krb5->credentials, 0, sizeof(CredHandle)); - - /* Acquire our credentials handle */ - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) - TEXT(SP_NAME_KERBEROS), - SECPKG_CRED_OUTBOUND, NULL, - krb5->p_identity, NULL, NULL, - krb5->credentials, &expiry); - if(status != SEC_E_OK) - return CURLE_LOGIN_DENIED; - - /* Allocate our new context handle */ - krb5->context = malloc(sizeof(CtxtHandle)); - if(!krb5->context) - return CURLE_OUT_OF_MEMORY; - - memset(krb5->context, 0, sizeof(CtxtHandle)); - } - else { - /* Decode the base-64 encoded challenge message */ - if(strlen(chlg64) && *chlg64 != '=') { - result = Curl_base64_decode(chlg64, &chlg, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!chlg) { - infof(data, "GSSAPI handshake failure (empty challenge message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Setup the challenge "input" security buffer */ - chlg_desc.ulVersion = SECBUFFER_VERSION; - chlg_desc.cBuffers = 1; - chlg_desc.pBuffers = &chlg_buf; - chlg_buf.BufferType = SECBUFFER_TOKEN; - chlg_buf.pvBuffer = chlg; - chlg_buf.cbBuffer = curlx_uztoul(chlglen); - } - - /* Setup the response "output" security buffer */ - resp_desc.ulVersion = SECBUFFER_VERSION; - resp_desc.cBuffers = 1; - resp_desc.pBuffers = &resp_buf; - resp_buf.BufferType = SECBUFFER_TOKEN; - resp_buf.pvBuffer = krb5->output_token; - resp_buf.cbBuffer = curlx_uztoul(krb5->token_max); - - /* Generate our challenge-response message */ - status = s_pSecFn->InitializeSecurityContext(krb5->credentials, - chlg ? krb5->context : NULL, - krb5->spn, - (mutual_auth ? - ISC_REQ_MUTUAL_AUTH : 0), - 0, SECURITY_NATIVE_DREP, - chlg ? &chlg_desc : NULL, 0, - &context, - &resp_desc, &attrs, - &expiry); - - if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { - free(chlg); - - return CURLE_RECV_ERROR; - } - - if(memcmp(&context, krb5->context, sizeof(context))) { - s_pSecFn->DeleteSecurityContext(krb5->context); - - memcpy(krb5->context, &context, sizeof(context)); - } - - if(resp_buf.cbBuffer) { - /* Base64 encode the response */ - result = Curl_base64_encode(data, (char *)resp_buf.pvBuffer, - resp_buf.cbBuffer, outptr, outlen); - } - - /* Free the decoded challenge */ - free(chlg); - - return result; -} - -/* - * Curl_sasl_create_gssapi_security_message() - * - * This is used to generate an already encoded GSSAPI (Kerberos V5) security - * token message ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * chlg64 [in] - The optional base64 encoded challenge message. - * krb5 [in/out] - The gssapi data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, - const char *chlg64, - struct kerberos5data *krb5, - char **outptr, - size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t offset = 0; - size_t chlglen = 0; - size_t messagelen = 0; - size_t appdatalen = 0; - unsigned char *chlg = NULL; - unsigned char *trailer = NULL; - unsigned char *message = NULL; - unsigned char *padding = NULL; - unsigned char *appdata = NULL; - SecBuffer input_buf[2]; - SecBuffer wrap_buf[3]; - SecBufferDesc input_desc; - SecBufferDesc wrap_desc; - unsigned long indata = 0; - unsigned long outdata = 0; - unsigned long qop = 0; - unsigned long sec_layer = 0; - unsigned long max_size = 0; - SecPkgContext_Sizes sizes; - SecPkgCredentials_Names names; - SECURITY_STATUS status; - char *user_name; - - /* Decode the base-64 encoded input message */ - if(strlen(chlg64) && *chlg64 != '=') { - result = Curl_base64_decode(chlg64, &chlg, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!chlg) { - infof(data, "GSSAPI handshake failure (empty security message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Get our response size information */ - status = s_pSecFn->QueryContextAttributes(krb5->context, - SECPKG_ATTR_SIZES, - &sizes); - if(status != SEC_E_OK) { - free(chlg); - - return CURLE_OUT_OF_MEMORY; - } - - /* Get the fully qualified username back from the context */ - status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials, - SECPKG_CRED_ATTR_NAMES, - &names); - if(status != SEC_E_OK) { - free(chlg); - - return CURLE_RECV_ERROR; - } - - /* Setup the "input" security buffer */ - input_desc.ulVersion = SECBUFFER_VERSION; - input_desc.cBuffers = 2; - input_desc.pBuffers = input_buf; - input_buf[0].BufferType = SECBUFFER_STREAM; - input_buf[0].pvBuffer = chlg; - input_buf[0].cbBuffer = curlx_uztoul(chlglen); - input_buf[1].BufferType = SECBUFFER_DATA; - input_buf[1].pvBuffer = NULL; - input_buf[1].cbBuffer = 0; - - /* Decrypt the inbound challenge and obtain the qop */ - status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop); - if(status != SEC_E_OK) { - infof(data, "GSSAPI handshake failure (empty security message)\n"); - - free(chlg); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ - if(input_buf[1].cbBuffer != 4) { - infof(data, "GSSAPI handshake failure (invalid security data)\n"); - - free(chlg); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Copy the data out and free the challenge as it is not required anymore */ - memcpy(&indata, input_buf[1].pvBuffer, 4); - s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer); - free(chlg); - - /* Extract the security layer */ - sec_layer = indata & 0x000000FF; - if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) { - infof(data, "GSSAPI handshake failure (invalid security layer)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Extract the maximum message size the server can receive */ - max_size = ntohl(indata & 0xFFFFFF00); - if(max_size > 0) { - /* The server has told us it supports a maximum receive buffer, however, as - we don't require one unless we are encrypting data, we tell the server - our receive buffer is zero. */ - max_size = 0; - } - - /* Allocate the trailer */ - trailer = malloc(sizes.cbSecurityTrailer); - if(!trailer) - return CURLE_OUT_OF_MEMORY; - - /* Convert the user name to UTF8 when operating with Unicode */ - user_name = Curl_convert_tchar_to_UTF8(names.sUserName); - if(!user_name) { - free(trailer); - - return CURLE_OUT_OF_MEMORY; - } - - /* Allocate our message */ - messagelen = sizeof(outdata) + strlen(user_name) + 1; - message = malloc(messagelen); - if(!message) { - free(trailer); - Curl_unicodefree(user_name); - - return CURLE_OUT_OF_MEMORY; - } - - /* Populate the message with the security layer, client supported receive - message size and authorization identity including the 0x00 based - terminator. Note: Dispite RFC4752 Section 3.1 stating "The authorization - identity is not terminated with the zero-valued (%x00) octet." it seems - necessary to include it. */ - outdata = htonl(max_size) | sec_layer; - memcpy(message, &outdata, sizeof(outdata)); - strcpy((char *) message + sizeof(outdata), user_name); - Curl_unicodefree(user_name); - - /* Allocate the padding */ - padding = malloc(sizes.cbBlockSize); - if(!padding) { - free(message); - free(trailer); - - return CURLE_OUT_OF_MEMORY; - } - - /* Setup the "authentication data" security buffer */ - wrap_desc.ulVersion = SECBUFFER_VERSION; - wrap_desc.cBuffers = 3; - wrap_desc.pBuffers = wrap_buf; - wrap_buf[0].BufferType = SECBUFFER_TOKEN; - wrap_buf[0].pvBuffer = trailer; - wrap_buf[0].cbBuffer = sizes.cbSecurityTrailer; - wrap_buf[1].BufferType = SECBUFFER_DATA; - wrap_buf[1].pvBuffer = message; - wrap_buf[1].cbBuffer = curlx_uztoul(messagelen); - wrap_buf[2].BufferType = SECBUFFER_PADDING; - wrap_buf[2].pvBuffer = padding; - wrap_buf[2].cbBuffer = sizes.cbBlockSize; - - /* Encrypt the data */ - status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT, - &wrap_desc, 0); - if(status != SEC_E_OK) { - free(padding); - free(message); - free(trailer); - - return CURLE_OUT_OF_MEMORY; - } - - /* Allocate the encryption (wrap) buffer */ - appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer + - wrap_buf[2].cbBuffer; - appdata = malloc(appdatalen); - if(!appdata) { - free(padding); - free(message); - free(trailer); - - return CURLE_OUT_OF_MEMORY; - } - - /* Populate the encryption buffer */ - memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer); - offset += wrap_buf[0].cbBuffer; - memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer); - offset += wrap_buf[1].cbBuffer; - memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer); - - /* Base64 encode the response */ - result = Curl_base64_encode(data, (char *)appdata, appdatalen, outptr, - outlen); - - /* Free all of our local buffers */ - free(appdata); - free(padding); - free(message); - free(trailer); - - return result; -} - -/* - * Curl_sasl_gssapi_cleanup() - * - * This is used to clean up the gssapi specific data. - * - * Parameters: - * - * krb5 [in/out] - The kerberos 5 data struct being cleaned up. - * - */ -void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5) -{ - /* Free our security context */ - if(krb5->context) { - s_pSecFn->DeleteSecurityContext(krb5->context); - free(krb5->context); - krb5->context = NULL; - } - - /* Free our credentials handle */ - if(krb5->credentials) { - s_pSecFn->FreeCredentialsHandle(krb5->credentials); - free(krb5->credentials); - krb5->credentials = NULL; - } - - /* Free our identity */ - Curl_sspi_free_identity(krb5->p_identity); - krb5->p_identity = NULL; - - /* Free the SPN and output token */ - Curl_safefree(krb5->spn); - Curl_safefree(krb5->output_token); - - /* Reset any variables */ - krb5->token_max = 0; -} -#endif /* USE_KERBEROS5 */ - -#endif /* USE_WINDOWS_SSPI */ diff --git a/lib/curl_sec.h b/lib/curl_sec.h index 6c48da2..3f94e14 100644 --- a/lib/curl_sec.h +++ b/lib/curl_sec.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_setup.h b/lib/curl_setup.h index ab0c139..7dcc4c4 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -181,9 +181,6 @@ # ifndef CURL_DISABLE_SMTP # define CURL_DISABLE_SMTP # endif -# ifndef CURL_DISABLE_RTSP -# define CURL_DISABLE_RTSP -# endif # ifndef CURL_DISABLE_RTMP # define CURL_DISABLE_RTMP # endif @@ -225,6 +222,15 @@ #endif /* + * Use getaddrinfo to resolve the IPv4 address literal. If the current network + * interface doesn???t support IPv4, but supports IPv6, NAT64, and DNS64, + * performing this task will result in a synthesized IPv6 address. + */ +#ifdef __APPLE__ +#define USE_RESOLVE_ON_IPS 1 +#endif + +/* * Include header files for windows builds before redefining anything. * Use this preprocessor block only to include or exclude windows.h, * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs @@ -249,7 +255,7 @@ # ifdef HAVE_WINSOCK2_H # include # ifdef HAVE_WS2TCPIP_H -# include +# include # endif # else # ifdef HAVE_WINSOCK_H @@ -476,7 +482,7 @@ # endif # ifndef fileno /* sunos 4 have this as a macro! */ - int fileno( FILE *stream); + int fileno(FILE *stream); # endif #endif /* WIN32 */ @@ -484,9 +490,10 @@ /* * msvc 6.0 requires PSDK in order to have INET6_ADDRSTRLEN * defined in ws2tcpip.h as well as to provide IPv6 support. + * Does not apply if lwIP is used. */ -#if defined(_MSC_VER) && !defined(__POCC__) +#if defined(_MSC_VER) && !defined(__POCC__) && !defined(USE_LWIPSOCK) # if !defined(HAVE_WS2TCPIP_H) || \ ((_MSC_VER < 1300) && !defined(INET6_ADDRSTRLEN)) # undef HAVE_GETADDRINFO_THREADSAFE @@ -530,6 +537,7 @@ # define CURLRES_ARES /* now undef the stock libc functions just to avoid them being used */ # undef HAVE_GETADDRINFO +# undef HAVE_FREEADDRINFO # undef HAVE_GETHOSTBYNAME #elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) # define CURLRES_ASYNCH @@ -605,7 +613,7 @@ int netware_init(void); #define LIBIDN_REQUIRED_VERSION "0.4.1" #if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \ - defined(USE_POLARSSL) || defined(USE_AXTLS) || \ + defined(USE_POLARSSL) || defined(USE_AXTLS) || defined(USE_MBEDTLS) || \ defined(USE_CYASSL) || defined(USE_SCHANNEL) || \ defined(USE_DARWINSSL) || defined(USE_GSKIT) #define USE_SSL /* SSL support has been enabled */ @@ -629,13 +637,9 @@ int netware_init(void); defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) || \ defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) -#ifdef HAVE_BORINGSSL /* BoringSSL is not NTLM capable */ -#undef USE_NTLM -#else #define USE_NTLM #endif #endif -#endif /* non-configure builds may define CURL_WANTS_CA_BUNDLE_ENV */ #if defined(CURL_WANTS_CA_BUNDLE_ENV) && !defined(CURL_CA_BUNDLE) @@ -677,7 +681,7 @@ int netware_init(void); * Ensure that Winsock and lwIP TCP/IP stacks are not mixed. */ -#if defined(__LWIP_OPT_H__) +#if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H) # if defined(SOCKET) || \ defined(USE_WINSOCK) || \ defined(HAVE_WINSOCK_H) || \ @@ -708,7 +712,7 @@ int netware_init(void); #endif /* In Windows the default file mode is text but an application can override it. -Therefore we specify it explicitly. https://github.com/bagder/curl/pull/258 +Therefore we specify it explicitly. https://github.com/curl/curl/pull/258 */ #if defined(WIN32) || defined(MSDOS) #define FOPEN_READTEXT "rt" @@ -727,4 +731,19 @@ endings either CRLF or LF so 't' is appropriate. #define FOPEN_WRITETEXT "w" #endif +/* WinSock destroys recv() buffer when send() failed. + * Enabled automatically for Windows and for Cygwin as Cygwin sockets are + * wrappers for WinSock sockets. https://github.com/curl/curl/issues/657 + * Define DONT_USE_RECV_BEFORE_SEND_WORKAROUND to force disable workaround. + */ +#if !defined(DONT_USE_RECV_BEFORE_SEND_WORKAROUND) +# if defined(WIN32) || defined(__CYGWIN__) +# define USE_RECV_BEFORE_SEND_WORKAROUND +# endif +#else /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */ +# ifdef USE_RECV_BEFORE_SEND_WORKAROUND +# undef USE_RECV_BEFORE_SEND_WORKAROUND +# endif +#endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */ + #endif /* HEADER_CURL_SETUP_H */ diff --git a/lib/curl_setup_once.h b/lib/curl_setup_once.h index 69d6d47..4da8349 100644 --- a/lib/curl_setup_once.h +++ b/lib/curl_setup_once.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c index 070424d..ee3f1b1 100644 --- a/lib/curl_sspi.c +++ b/lib/curl_sspi.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -27,6 +27,7 @@ #include #include "curl_sspi.h" #include "curl_multibyte.h" +#include "system_win32.h" #include "warnless.h" /* The last #include files should be: */ @@ -66,7 +67,6 @@ PSecurityFunctionTable s_pSecFn = NULL; */ CURLcode Curl_sspi_global_init(void) { - bool securityDll = FALSE; INITSECURITYINTERFACE_FN pInitSecurityInterface; /* If security interface is not yet initialized try to do this */ @@ -74,52 +74,12 @@ CURLcode Curl_sspi_global_init(void) /* Security Service Provider Interface (SSPI) functions are located in * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP * have both these DLLs (security.dll forwards calls to secur32.dll) */ - DWORD majorVersion = 4; - DWORD platformId = VER_PLATFORM_WIN32_NT; - -#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ - (_WIN32_WINNT < _WIN32_WINNT_WIN2K) - OSVERSIONINFO osver; - - memset(&osver, 0, sizeof(osver)); - osver.dwOSVersionInfoSize = sizeof(osver); - - /* Find out Windows version */ - if(!GetVersionEx(&osver)) - return CURLE_FAILED_INIT; - - /* Verify the major version number == 4 and platform id == WIN_NT */ - if(osver.dwMajorVersion == majorVersion && - osver.dwPlatformId == platformId) - securityDll = TRUE; -#else - ULONGLONG cm; - OSVERSIONINFOEX osver; - - memset(&osver, 0, sizeof(osver)); - osver.dwOSVersionInfoSize = sizeof(osver); - osver.dwMajorVersion = majorVersion; - osver.dwPlatformId = platformId; - - cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); - cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_GREATER_EQUAL); - cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); - cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); - cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL); - - /* Verify the major version number == 4 and platform id == WIN_NT */ - if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | - VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR | - VER_PLATFORMID), - cm)) - securityDll = TRUE; -#endif /* Load SSPI dll into the address space of the calling process */ - if(securityDll) - s_hSecDll = LoadLibrary(TEXT("security.dll")); + if(Curl_verify_windows_version(4, 0, PLATFORM_WINNT, VERSION_EQUAL)) + s_hSecDll = Curl_load_library(TEXT("security.dll")); else - s_hSecDll = LoadLibrary(TEXT("secur32.dll")); + s_hSecDll = Curl_load_library(TEXT("secur32.dll")); if(!s_hSecDll) return CURLE_FAILED_INIT; diff --git a/lib/curl_sspi.h b/lib/curl_sspi.h index 8655715..2bbf947 100644 --- a/lib/curl_sspi.h +++ b/lib/curl_sspi.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -327,6 +327,10 @@ extern PSecurityFunctionTable s_pSecFn; # define SEC_I_SIGNATURE_NEEDED ((HRESULT)0x0009035CL) #endif +#ifndef CRYPT_E_REVOKED +# define CRYPT_E_REVOKED ((HRESULT)0x80092010L) +#endif + #ifdef UNICODE # define SECFLAG_WINNT_AUTH_IDENTITY \ (unsigned long)SEC_WINNT_AUTH_IDENTITY_UNICODE diff --git a/lib/curl_threads.c b/lib/curl_threads.c index f9b812e..c98d8bb 100644 --- a/lib/curl_threads.c +++ b/lib/curl_threads.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,6 +22,8 @@ #include "curl_setup.h" +#include + #if defined(USE_THREADS_POSIX) # ifdef HAVE_PTHREAD_H # include diff --git a/lib/curl_threads.h b/lib/curl_threads.h index 0f3191a..8cbac63 100644 --- a/lib/curl_threads.h +++ b/lib/curl_threads.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/curlx.h b/lib/curlx.h index 979e7d7..448a34f 100644 --- a/lib/curlx.h +++ b/lib/curlx.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/dict.c b/lib/dict.c index 06d7699..a7b5965 100644 --- a/lib/dict.c +++ b/lib/dict.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -91,7 +91,7 @@ const struct Curl_handler Curl_handler_dict = { PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ }; -static char *unescape_word(struct SessionHandle *data, const char *inputbuff) +static char *unescape_word(struct Curl_easy *data, const char *inputbuff) { char *newp; char *dictp; @@ -133,7 +133,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done) char *nthdef = NULL; /* This is not part of the protocol, but required by RFC 2229 */ CURLcode result=CURLE_OK; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; char *path = data->state.path; diff --git a/lib/dict.h b/lib/dict.h index 44fd9d4..12c0f33 100644 --- a/lib/dict.h +++ b/lib/dict.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/dotdot.c b/lib/dotdot.c index ae16941..ea7c8a0 100644 --- a/lib/dotdot.c +++ b/lib/dotdot.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,19 +22,22 @@ #include "curl_setup.h" -#include "dotdot.h" +#include +#include "dotdot.h" #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" /* * "Remove Dot Segments" - * http://tools.ietf.org/html/rfc3986#section-5.2.4 + * https://tools.ietf.org/html/rfc3986#section-5.2.4 */ /* * Curl_dedotdotify() + * @unittest: 1395 * * This function gets a zero-terminated path with dot and dotdot sequences * passed in and strips them off according to the rules in RFC 3986 section @@ -68,6 +71,12 @@ char *Curl_dedotdotify(const char *input) orgclone = clone; outptr = out; + if(!*clone) { + /* zero length string, return that */ + free(out); + return clone; + } + /* * To handle query-parts properly, we must find it and remove it during the * dotdot-operation and then append it again at the end to the output diff --git a/lib/dotdot.h b/lib/dotdot.h index cd57822..fac8e6f 100644 --- a/lib/dotdot.h +++ b/lib/dotdot.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/easy.c b/lib/easy.c index 316acb1..dc7139f 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -64,7 +64,6 @@ #include "easyif.h" #include "select.h" #include "sendf.h" /* for failf function prototype */ -#include "curl_ntlm.h" #include "connect.h" /* for Curl_getconnectinfo */ #include "slist.h" #include "amigaos.h" @@ -74,12 +73,13 @@ #include "multiif.h" #include "sigpipe.h" #include "ssh.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" +void Curl_version_init(void); + /* win32_cleanup() is for win32 socket cleanup functionality, the opposite of win32_init() */ static void win32_cleanup(void) @@ -120,8 +120,8 @@ static CURLcode win32_init(void) /* wVersionRequested in wVersion. wHighVersion contains the */ /* highest supported version. */ - if(LOBYTE( wsaData.wVersion ) != LOBYTE(wVersionRequested) || - HIBYTE( wsaData.wVersion ) != HIBYTE(wVersionRequested) ) { + if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) || + HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) { /* Tell the user that we couldn't find a useable */ /* winsock.dll. */ @@ -220,20 +220,22 @@ curl_calloc_callback Curl_ccalloc; * curl_global_init() globally initializes cURL given a bitwise set of the * different features of what to initialize. */ -CURLcode curl_global_init(long flags) +static CURLcode global_init(long flags, bool memoryfuncs) { if(initialized++) return CURLE_OK; - /* Setup the default memory functions here (again) */ - Curl_cmalloc = (curl_malloc_callback)malloc; - Curl_cfree = (curl_free_callback)free; - Curl_crealloc = (curl_realloc_callback)realloc; - Curl_cstrdup = (curl_strdup_callback)system_strdup; - Curl_ccalloc = (curl_calloc_callback)calloc; + if(memoryfuncs) { + /* Setup the default memory functions here (again) */ + Curl_cmalloc = (curl_malloc_callback)malloc; + Curl_cfree = (curl_free_callback)free; + Curl_crealloc = (curl_realloc_callback)realloc; + Curl_cstrdup = (curl_strdup_callback)system_strdup; + Curl_ccalloc = (curl_calloc_callback)calloc; #if defined(WIN32) && defined(UNICODE) - Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup; + Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup; #endif + } if(flags & CURL_GLOBAL_SSL) if(!Curl_ssl_init()) { @@ -269,6 +271,8 @@ CURLcode curl_global_init(long flags) return CURLE_FAILED_INIT; } + (void)Curl_ipv6works(); + #if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_INIT) if(libssh2_init(0)) { DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n")); @@ -279,11 +283,23 @@ CURLcode curl_global_init(long flags) if(flags & CURL_GLOBAL_ACK_EINTR) Curl_ack_eintr = 1; - init_flags = flags; + init_flags = flags; + + Curl_version_init(); return CURLE_OK; } + +/** + * curl_global_init() globally initializes cURL given a bitwise set of the + * different features of what to initialize. + */ +CURLcode curl_global_init(long flags) +{ + return global_init(flags, TRUE); +} + /* * curl_global_init_mem() globally initializes cURL and also registers the * user provided callback routines. @@ -292,8 +308,6 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, curl_free_callback f, curl_realloc_callback r, curl_strdup_callback s, curl_calloc_callback c) { - CURLcode result = CURLE_OK; - /* Invalid input, return immediately */ if(!m || !f || !r || !s || !c) return CURLE_FAILED_INIT; @@ -306,17 +320,16 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, return CURLE_OK; } - /* Call the actual init function first */ - result = curl_global_init(flags); - if(!result) { - Curl_cmalloc = m; - Curl_cfree = f; - Curl_cstrdup = s; - Curl_crealloc = r; - Curl_ccalloc = c; - } + /* set memory functions before global_init() in case it wants memory + functions */ + Curl_cmalloc = m; + Curl_cfree = f; + Curl_cstrdup = s; + Curl_crealloc = r; + Curl_ccalloc = c; - return result; + /* Call the actual init function, but without setting */ + return global_init(flags, FALSE); } /** @@ -354,10 +367,10 @@ void curl_global_cleanup(void) * curl_easy_init() is the external interface to alloc, setup and init an * easy handle that is returned. If anything goes wrong, NULL is returned. */ -CURL *curl_easy_init(void) +struct Curl_easy *curl_easy_init(void) { CURLcode result; - struct SessionHandle *data; + struct Curl_easy *data; /* Make sure we inited the global SSL stuff */ if(!initialized) { @@ -385,13 +398,12 @@ CURL *curl_easy_init(void) */ #undef curl_easy_setopt -CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...) +CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...) { va_list arg; - struct SessionHandle *data = curl; CURLcode result; - if(!curl) + if(!data) return CURLE_BAD_FUNCTION_ARGUMENT; va_start(arg, tag); @@ -423,7 +435,7 @@ struct events { * updated. */ -static int events_timer(CURLM *multi, /* multi handle */ +static int events_timer(struct Curl_multi *multi, /* multi handle */ long timeout_ms, /* see above */ void *userp) /* private callback pointer */ { @@ -478,7 +490,7 @@ static short socketcb2poll(int pollmask) * Callback that gets called with information about socket activity to * monitor. */ -static int events_socket(CURL *easy, /* easy handle */ +static int events_socket(struct Curl_easy *easy, /* easy handle */ curl_socket_t s, /* socket */ int what, /* see above */ void *userp, /* private callback @@ -532,14 +544,18 @@ static int events_socket(CURL *easy, /* easy handle */ } else { m = malloc(sizeof(struct socketmonitor)); - m->next = ev->list; - m->socket.fd = s; - m->socket.events = socketcb2poll(what); - m->socket.revents = 0; - ev->list = m; - infof(easy, "socket cb: socket %d ADDED as %s%s\n", s, - what&CURL_POLL_IN?"IN":"", - what&CURL_POLL_OUT?"OUT":""); + if(m) { + m->next = ev->list; + m->socket.fd = s; + m->socket.events = socketcb2poll(what); + m->socket.revents = 0; + ev->list = m; + infof(easy, "socket cb: socket %d ADDED as %s%s\n", s, + what&CURL_POLL_IN?"IN":"", + what&CURL_POLL_OUT?"OUT":""); + } + else + return CURLE_OUT_OF_MEMORY; } } @@ -552,7 +568,7 @@ static int events_socket(CURL *easy, /* easy handle */ * * Do the multi handle setups that only event-based transfers need. */ -static void events_setup(CURLM *multi, struct events *ev) +static void events_setup(struct Curl_multi *multi, struct events *ev) { /* timer callback */ curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer); @@ -609,7 +625,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) if(0 == pollrc) { /* timeout! */ ev->ms = 0; - /* fprintf(stderr, "call curl_multi_socket_action( TIMEOUT )\n"); */ + /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */ mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, &ev->running_handles); } @@ -619,7 +635,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) if(fds[i].revents) { /* socket activity, tell libcurl */ int act = poll2cselect(fds[i].revents); /* convert */ - infof(multi->easyp, "call curl_multi_socket_action( socket %d )\n", + infof(multi->easyp, "call curl_multi_socket_action(socket %d)\n", fds[i].fd); mcode = curl_multi_socket_action(multi, fds[i].fd, act, &ev->running_handles); @@ -656,7 +672,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) * * Runs a transfer in a blocking manner using the events-based API */ -static CURLcode easy_events(CURLM *multi) +static CURLcode easy_events(struct Curl_multi *multi) { struct events evs= {2, FALSE, 0, NULL, 0}; @@ -670,7 +686,7 @@ static CURLcode easy_events(CURLM *multi) #define easy_events(x) CURLE_NOT_BUILT_IN #endif -static CURLcode easy_transfer(CURLM *multi) +static CURLcode easy_transfer(struct Curl_multi *multi) { bool done = FALSE; CURLMcode mcode = CURLM_OK; @@ -681,26 +697,22 @@ static CURLcode easy_transfer(CURLM *multi) while(!done && !mcode) { int still_running = 0; - int ret; + int rc; before = curlx_tvnow(); - mcode = curl_multi_wait(multi, NULL, 0, 1000, &ret); + mcode = curl_multi_wait(multi, NULL, 0, 1000, &rc); - if(mcode == CURLM_OK) { - if(ret == -1) { - /* poll() failed not on EINTR, indicate a network problem */ - result = CURLE_RECV_ERROR; - break; - } - else if(ret == 0) { + if(!mcode) { + if(!rc) { struct timeval after = curlx_tvnow(); + /* If it returns without any filedescriptor instantly, we need to avoid busy-looping during periods where it has nothing particular to wait for */ if(curlx_tvdiff(after, before) <= 10) { without_fds++; if(without_fds > 2) { - int sleep_ms = without_fds < 10 ? (1 << (without_fds-1)): 1000; + int sleep_ms = without_fds < 10 ? (1 << (without_fds - 1)) : 1000; Curl_wait_ms(sleep_ms); } } @@ -716,8 +728,7 @@ static CURLcode easy_transfer(CURLM *multi) } /* only read 'still_running' if curl_multi_perform() return OK */ - if((mcode == CURLM_OK) && !still_running) { - int rc; + if(!mcode && !still_running) { CURLMsg *msg = curl_multi_info_read(multi, &rc); if(msg) { result = msg->data.result; @@ -728,10 +739,10 @@ static CURLcode easy_transfer(CURLM *multi) /* Make sure to return some kind of error if there was a multi problem */ if(mcode) { - return (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY : - /* The other multi errors should never happen, so return - something suitably generic */ - CURLE_BAD_FUNCTION_ARGUMENT; + result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY : + /* The other multi errors should never happen, so return + something suitably generic */ + CURLE_BAD_FUNCTION_ARGUMENT; } return result; @@ -755,9 +766,9 @@ static CURLcode easy_transfer(CURLM *multi) * DEBUG: if 'events' is set TRUE, this function will use a replacement engine * instead of curl_multi_perform() and use curl_multi_socket_action(). */ -static CURLcode easy_perform(struct SessionHandle *data, bool events) +static CURLcode easy_perform(struct Curl_easy *data, bool events) { - CURLM *multi; + struct Curl_multi *multi; CURLMcode mcode; CURLcode result = CURLE_OK; SIGPIPE_VARIABLE(pipe_st); @@ -817,9 +828,9 @@ static CURLcode easy_perform(struct SessionHandle *data, bool events) * curl_easy_perform() is the external interface that performs a blocking * transfer as previously setup. */ -CURLcode curl_easy_perform(CURL *easy) +CURLcode curl_easy_perform(struct Curl_easy *data) { - return easy_perform(easy, FALSE); + return easy_perform(data, FALSE); } #ifdef CURLDEBUG @@ -827,9 +838,9 @@ CURLcode curl_easy_perform(CURL *easy) * curl_easy_perform_ev() is the external interface that performs a blocking * transfer using the event-based API internally. */ -CURLcode curl_easy_perform_ev(CURL *easy) +CURLcode curl_easy_perform_ev(struct Curl_easy *data) { - return easy_perform(easy, TRUE); + return easy_perform(data, TRUE); } #endif @@ -838,9 +849,8 @@ CURLcode curl_easy_perform_ev(CURL *easy) * curl_easy_cleanup() is the external interface to cleaning/freeing the given * easy handle. */ -void curl_easy_cleanup(CURL *curl) +void curl_easy_cleanup(struct Curl_easy *data) { - struct SessionHandle *data = (struct SessionHandle *)curl; SIGPIPE_VARIABLE(pipe_st); if(!data) @@ -856,12 +866,11 @@ void curl_easy_cleanup(CURL *curl) * information from a performed transfer and similar. */ #undef curl_easy_getinfo -CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...) +CURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...) { va_list arg; void *paramp; CURLcode result; - struct SessionHandle *data = (struct SessionHandle *)curl; va_start(arg, info); paramp = va_arg(arg, void *); @@ -877,11 +886,9 @@ CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...) * given input easy handle. The returned handle will be a new working handle * with all options set exactly as the input source handle. */ -CURL *curl_easy_duphandle(CURL *incurl) +struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) { - struct SessionHandle *data=(struct SessionHandle *)incurl; - - struct SessionHandle *outcurl = calloc(1, sizeof(struct SessionHandle)); + struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy)); if(NULL == outcurl) goto fail; @@ -972,10 +979,8 @@ CURL *curl_easy_duphandle(CURL *incurl) * curl_easy_reset() is an external interface that allows an app to re- * initialize a session handle to the default values. */ -void curl_easy_reset(CURL *curl) +void curl_easy_reset(struct Curl_easy *data) { - struct SessionHandle *data = (struct SessionHandle *)curl; - Curl_safefree(data->state.pathbuffer); data->state.path = NULL; @@ -1004,9 +1009,8 @@ void curl_easy_reset(CURL *curl) * * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h */ -CURLcode curl_easy_pause(CURL *curl, int action) +CURLcode curl_easy_pause(struct Curl_easy *data, int action) { - struct SessionHandle *data = (struct SessionHandle *)curl; struct SingleRequest *k = &data->req; CURLcode result = CURLE_OK; @@ -1046,7 +1050,7 @@ CURLcode curl_easy_pause(CURL *curl, int action) } -static CURLcode easy_connection(struct SessionHandle *data, +static CURLcode easy_connection(struct Curl_easy *data, curl_socket_t *sfd, struct connectdata **connp) { @@ -1074,13 +1078,13 @@ static CURLcode easy_connection(struct SessionHandle *data, * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. * Returns CURLE_OK on success, error code on error. */ -CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n) +CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen, + size_t *n) { curl_socket_t sfd; CURLcode result; ssize_t n1; struct connectdata *c; - struct SessionHandle *data = (struct SessionHandle *)curl; result = easy_connection(data, &sfd, &c); if(result) @@ -1101,14 +1105,13 @@ CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n) * Sends data over the connected socket. Use after successful * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. */ -CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen, - size_t *n) +CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer, + size_t buflen, size_t *n) { curl_socket_t sfd; CURLcode result; ssize_t n1; struct connectdata *c = NULL; - struct SessionHandle *data = (struct SessionHandle *)curl; result = easy_connection(data, &sfd, &c); if(result) diff --git a/lib/easyif.h b/lib/easyif.h index 043ff43..f6132cc 100644 --- a/lib/easyif.h +++ b/lib/easyif.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,7 +26,7 @@ * Prototypes for library-wide functions provided by easy.c */ #ifdef CURLDEBUG -CURL_EXTERN CURLcode curl_easy_perform_ev(CURL *easy); +CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy); #endif #endif /* HEADER_CURL_EASYIF_H */ diff --git a/lib/escape.c b/lib/escape.c index 24abb93..04230b4 100644 --- a/lib/escape.c +++ b/lib/escape.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -31,15 +31,14 @@ #include "warnless.h" #include "non-ascii.h" #include "escape.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* Portable character check (remember EBCDIC). Do not use isalnum() because its behavior is altered by the current locale. - See http://tools.ietf.org/html/rfc3986#section-2.3 + See https://tools.ietf.org/html/rfc3986#section-2.3 */ static bool Curl_isunreserved(unsigned char in) { @@ -76,7 +75,8 @@ char *curl_unescape(const char *string, int length) return curl_easy_unescape(NULL, string, length, NULL); } -char *curl_easy_escape(CURL *handle, const char *string, int inlength) +char *curl_easy_escape(struct Curl_easy *data, const char *string, + int inlength) { size_t alloc = (inlength?(size_t)inlength:strlen(string))+1; char *ns; @@ -105,7 +105,7 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength) alloc *= 2; testing_ptr = realloc(ns, alloc); if(!testing_ptr) { - free( ns ); + free(ns); return NULL; } else { @@ -113,7 +113,7 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength) } } - result = Curl_convert_to_network(handle, &in, 1); + result = Curl_convert_to_network(data, &in, 1); if(result) { /* Curl_convert_to_network calls failf if unsuccessful */ free(ns); @@ -140,7 +140,7 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength) * *olen. If length == 0, the length is assumed to be strlen(string). * */ -CURLcode Curl_urldecode(struct SessionHandle *data, +CURLcode Curl_urldecode(struct Curl_easy *data, const char *string, size_t length, char **ostring, size_t *olen, bool reject_ctrl) @@ -207,13 +207,13 @@ CURLcode Curl_urldecode(struct SessionHandle *data, * If length == 0, the length is assumed to be strlen(string). * If olen == NULL, no output length is stored. */ -char *curl_easy_unescape(CURL *handle, const char *string, int length, - int *olen) +char *curl_easy_unescape(struct Curl_easy *data, const char *string, + int length, int *olen) { char *str = NULL; size_t inputlen = length; size_t outputlen; - CURLcode res = Curl_urldecode(handle, string, inputlen, &str, &outputlen, + CURLcode res = Curl_urldecode(data, string, inputlen, &str, &outputlen, FALSE); if(res) return NULL; diff --git a/lib/escape.h b/lib/escape.h index 731b136..638666f 100644 --- a/lib/escape.h +++ b/lib/escape.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -24,7 +24,7 @@ /* Escape and unescape URL encoding in strings. The functions return a new * allocated string or NULL if an error occurred. */ -CURLcode Curl_urldecode(struct SessionHandle *data, +CURLcode Curl_urldecode(struct Curl_easy *data, const char *string, size_t length, char **ostring, size_t *olen, bool reject_crlf); diff --git a/lib/file.c b/lib/file.c index 175b107..b534ec1 100644 --- a/lib/file.c +++ b/lib/file.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -61,9 +61,8 @@ #include "url.h" #include "parsedate.h" /* for the week day and month names */ #include "warnless.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -136,7 +135,7 @@ static CURLcode file_range(struct connectdata *conn) curl_off_t totalsize=-1; char *ptr; char *ptr2; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(data->state.use_range && data->state.range) { from=curlx_strtoofft(data->state.range, &ptr, 0); @@ -186,7 +185,7 @@ static CURLcode file_range(struct connectdata *conn) */ static CURLcode file_connect(struct connectdata *conn, bool *done) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char *real_path; struct FILEPROTO *file = data->req.protop; int fd; @@ -228,15 +227,19 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) for(i=0; i < real_path_len; ++i) if(actual_path[i] == '/') actual_path[i] = '\\'; - else if(!actual_path[i]) /* binary zero */ + else if(!actual_path[i]) { /* binary zero */ + Curl_safefree(real_path); return CURLE_URL_MALFORMAT; + } fd = open_readonly(actual_path, O_RDONLY|O_BINARY); file->path = actual_path; #else - if(memchr(real_path, 0, real_path_len)) + if(memchr(real_path, 0, real_path_len)) { /* binary zeroes indicate foul play */ + Curl_safefree(real_path); return CURLE_URL_MALFORMAT; + } fd = open_readonly(real_path, O_RDONLY); file->path = real_path; @@ -302,7 +305,7 @@ static CURLcode file_upload(struct connectdata *conn) int fd; int mode; CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char *buf = data->state.buffer; size_t nread; size_t nwrite; @@ -368,7 +371,7 @@ static CURLcode file_upload(struct connectdata *conn) /*skip bytes before resume point*/ if(data->state.resume_from) { - if((curl_off_t)nread <= data->state.resume_from ) { + if((curl_off_t)nread <= data->state.resume_from) { data->state.resume_from -= nread; nread = 0; buf2 = buf; @@ -426,9 +429,10 @@ static CURLcode file_do(struct connectdata *conn, bool *done) Windows version to have a different struct without having to redefine the simple word 'stat' */ curl_off_t expected_size=0; + bool size_known; bool fstated=FALSE; ssize_t nread; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char *buf = data->state.buffer; curl_off_t bytecount = 0; int fd; @@ -468,6 +472,9 @@ static CURLcode file_do(struct connectdata *conn, bool *done) information. Which for FILE can't be much more than the file size and date. */ if(data->set.opt_no_body && data->set.include_header && fstated) { + time_t filetime; + struct tm buffer; + const struct tm *tm = &buffer; snprintf(buf, sizeof(data->state.buffer), "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size); result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); @@ -479,29 +486,24 @@ static CURLcode file_do(struct connectdata *conn, bool *done) if(result) return result; - if(fstated) { - time_t filetime = (time_t)statbuf.st_mtime; - struct tm buffer; - const struct tm *tm = &buffer; - result = Curl_gmtime(filetime, &buffer); - if(result) - return result; - - /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ - snprintf(buf, BUFSIZE-1, - "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", - Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); - result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); - } - /* if we fstat()ed the file, set the file size to make it available post- - transfer */ - if(fstated) + filetime = (time_t)statbuf.st_mtime; + result = Curl_gmtime(filetime, &buffer); + if(result) + return result; + + /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ + snprintf(buf, BUFSIZE-1, + "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", + Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); + result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); + if(!result) + /* set the file size to make it available post transfer */ Curl_pgrsSetDownloadSize(data, expected_size); return result; } @@ -531,8 +533,10 @@ static CURLcode file_do(struct connectdata *conn, bool *done) if(data->req.maxdownload > 0) expected_size = data->req.maxdownload; - if(fstated && (expected_size == 0)) - return CURLE_OK; + if(!fstated || (expected_size == 0)) + size_known = FALSE; + else + size_known = TRUE; /* The following is a shortcut implementation of file reading this is both more efficient than the former call to download() and @@ -551,20 +555,27 @@ static CURLcode file_do(struct connectdata *conn, bool *done) while(!result) { /* Don't fill a whole buffer if we want less than all data */ - size_t bytestoread = - (expected_size < CURL_OFF_T_C(BUFSIZE) - CURL_OFF_T_C(1)) ? - curlx_sotouz(expected_size) : BUFSIZE - 1; + size_t bytestoread; + + if(size_known) { + bytestoread = + (expected_size < CURL_OFF_T_C(BUFSIZE) - CURL_OFF_T_C(1)) ? + curlx_sotouz(expected_size) : BUFSIZE - 1; + } + else + bytestoread = BUFSIZE-1; nread = read(fd, buf, bytestoread); if(nread > 0) buf[nread] = 0; - if(nread <= 0 || expected_size == 0) + if(nread <= 0 || (size_known && (expected_size == 0))) break; bytecount += nread; - expected_size -= nread; + if(size_known) + expected_size -= nread; result = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread); if(result) diff --git a/lib/file.h b/lib/file.h index 997474b..c12ae0e 100644 --- a/lib/file.h +++ b/lib/file.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/fileinfo.c b/lib/fileinfo.c index 0904937..144c65b 100644 --- a/lib/fileinfo.c +++ b/lib/fileinfo.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/fileinfo.h b/lib/fileinfo.h index b0e5e59..5324f1a 100644 --- a/lib/fileinfo.h +++ b/lib/fileinfo.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/formdata.c b/lib/formdata.c index 9e8ce4e..673759d 100644 --- a/lib/formdata.c +++ b/lib/formdata.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -30,15 +30,14 @@ #include #endif -#include "urldata.h" /* for struct SessionHandle */ +#include "urldata.h" /* for struct Curl_easy */ #include "formdata.h" #include "vtls/vtls.h" #include "strequal.h" #include "sendf.h" #include "strdup.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -48,7 +47,7 @@ static char *Curl_basename(char *path); #endif static size_t readfromfile(struct Form *form, char *buffer, size_t size); -static char *formboundary(struct SessionHandle *data); +static char *formboundary(struct Curl_easy *data); /* What kind of Content-Type to use on un-specified files with unrecognized extensions. */ @@ -57,6 +56,14 @@ static char *formboundary(struct SessionHandle *data); #define FORM_FILE_SEPARATOR ',' #define FORM_TYPE_SEPARATOR ';' +#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME +#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME +#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS +#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE +#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER +#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK +#define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER + /*************************************************************************** * * AddHttpPost() @@ -69,7 +76,7 @@ static char *formboundary(struct SessionHandle *data); ***************************************************************************/ static struct curl_httppost * AddHttpPost(char *name, size_t namelength, - char *value, size_t contentslength, + char *value, curl_off_t contentslength, char *buffer, size_t bufferlength, char *contenttype, long flags, @@ -85,14 +92,14 @@ AddHttpPost(char *name, size_t namelength, post->name = name; post->namelength = (long)(name?(namelength?namelength:strlen(name)):0); post->contents = value; - post->contentslength = (long)contentslength; + post->contentlen = contentslength; post->buffer = buffer; post->bufferlength = (long)bufferlength; post->contenttype = contenttype; post->contentheader = contentHeader; post->showfilename = showfilename; post->userp = userp, - post->flags = flags; + post->flags = flags | CURL_HTTPPOST_LARGE; } else return NULL; @@ -372,11 +379,14 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, } break; case CURLFORM_CONTENTSLENGTH: - if(current_form->contentslength) - return_value = CURL_FORMADD_OPTION_TWICE; - else - current_form->contentslength = - array_state?(size_t)array_value:(size_t)va_arg(params, long); + current_form->contentslength = + array_state?(size_t)array_value:(size_t)va_arg(params, long); + break; + + case CURLFORM_CONTENTLEN: + current_form->flags |= CURL_HTTPPOST_LARGE; + current_form->contentslength = + array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t); break; /* Get contents from a given file name */ @@ -538,7 +548,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, /* this "cast increases required alignment of target type" but we consider it OK anyway */ struct curl_slist* list = array_state? - (struct curl_slist*)array_value: + (struct curl_slist*)(void*)array_value: va_arg(params, struct curl_slist*); if(current_form->contentheader) @@ -621,7 +631,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, else { if(((form->flags & HTTPPOST_FILENAME) || (form->flags & HTTPPOST_BUFFER)) && - !form->contenttype ) { + !form->contenttype) { char *f = form->flags & HTTPPOST_BUFFER? form->showfilename : form->value; @@ -653,9 +663,12 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER | HTTPPOST_CALLBACK)) && form->value) { /* copy value (without strdup; possibly contains null characters) */ - form->value = Curl_memdup(form->value, form->contentslength? - form->contentslength: - strlen(form->value)+1); + size_t clen = (size_t) form->contentslength; + if(!clen) + clen = strlen(form->value)+1; + + form->value = Curl_memdup(form->value, clen); + if(!form->value) { return_value = CURL_FORMADD_MEMORY; break; @@ -756,7 +769,7 @@ curl_off_t VmsRealFileSize(const char * name, int ret_stat; FILE * file; - file = fopen(name, "r"); /* VMS */ + file = fopen(name, FOPEN_READTEXT); /* VMS */ if(file == NULL) return 0; @@ -808,10 +821,16 @@ static curl_off_t VmsSpecialSize(const char * name, static CURLcode AddFormData(struct FormData **formp, enum formtype type, const void *line, - size_t length, + curl_off_t length, curl_off_t *size) { - struct FormData *newform = malloc(sizeof(struct FormData)); + struct FormData *newform; + char *alloc2 = NULL; + CURLcode result = CURLE_OK; + if(length < 0 || (size && *size < 0)) + return CURLE_BAD_FUNCTION_ARGUMENT; + + newform = malloc(sizeof(struct FormData)); if(!newform) return CURLE_OUT_OF_MEMORY; newform->next = NULL; @@ -820,15 +839,22 @@ static CURLcode AddFormData(struct FormData **formp, /* we make it easier for plain strings: */ if(!length) length = strlen((char *)line); +#if (SIZEOF_SIZE_T < CURL_SIZEOF_CURL_OFF_T) + else if(length >= (curl_off_t)(size_t)-1) { + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto error; + } +#endif - newform->line = malloc(length+1); + newform->line = malloc((size_t)length+1); if(!newform->line) { - free(newform); - return CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; + goto error; } - memcpy(newform->line, line, length); - newform->length = length; - newform->line[length]=0; /* zero terminate for easier debugging */ + alloc2 = newform->line; + memcpy(newform->line, line, (size_t)length); + newform->length = (size_t)length; + newform->line[(size_t)length]=0; /* zero terminate for easier debugging */ } else /* For callbacks and files we don't have any actual data so we just keep a @@ -856,12 +882,20 @@ static CURLcode AddFormData(struct FormData **formp, struct_stat file; if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode)) *size += filesize(newform->line, file); - else - return CURLE_BAD_FUNCTION_ARGUMENT; + else { + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto error; + } } } } return CURLE_OK; + error: + if(newform) + free(newform); + if(alloc2) + free(alloc2); + return result; } /* @@ -1102,7 +1136,7 @@ static CURLcode formdata_add_filename(const struct curl_httppost *file, * a NULL pointer in the 'data' argument. */ -CURLcode Curl_getformdata(struct SessionHandle *data, +CURLcode Curl_getformdata(struct Curl_easy *data, struct FormData **finalform, struct curl_httppost *post, const char *custom_content_type, @@ -1238,7 +1272,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data, curList = file->contentheader; while(curList) { /* Process the additional headers specified for this form */ - result = AddFormDataf( &form, &size, "\r\n%s", curList->data ); + result = AddFormDataf(&form, &size, "\r\n%s", curList->data); if(result) break; curList = curList->next; @@ -1298,15 +1332,16 @@ CURLcode Curl_getformdata(struct SessionHandle *data, result = AddFormData(&form, FORM_CONTENT, post->buffer, post->bufferlength, &size); else if(post->flags & HTTPPOST_CALLBACK) - /* the contents should be read with the callback and the size - is set with the contentslength */ + /* the contents should be read with the callback and the size is set + with the contentslength */ result = AddFormData(&form, FORM_CALLBACK, post->userp, - post->contentslength, &size); + post->flags&CURL_HTTPPOST_LARGE? + post->contentlen:post->contentslength, &size); else /* include the contents we got */ result = AddFormData(&form, FORM_CONTENT, post->contents, - post->contentslength, &size); - + post->flags&CURL_HTTPPOST_LARGE? + post->contentlen:post->contentslength, &size); file = file->more; } while(file && !result); /* for each specified file for this field */ @@ -1350,7 +1385,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data, * Curl_FormInit() inits the struct 'form' points to with the 'formdata' * and resets the 'sent' counter. */ -int Curl_FormInit(struct Form *form, struct FormData *formdata ) +int Curl_FormInit(struct Form *form, struct FormData *formdata) { if(!formdata) return 1; /* error */ @@ -1385,10 +1420,10 @@ static FILE * vmsfopenread(const char *file, const char *mode) { case FAB$C_VAR: case FAB$C_VFC: case FAB$C_STMCR: - return fopen(file, "r"); /* VMS */ + return fopen(file, FOPEN_READTEXT); /* VMS */ break; default: - return fopen(file, "r", "rfm=stmlf", "ctx=stm"); + return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm"); } } #endif @@ -1463,9 +1498,9 @@ size_t Curl_FormReader(char *buffer, } do { - if((form->data->length - form->sent ) > wantedsize - gotsize) { + if((form->data->length - form->sent) > wantedsize - gotsize) { - memcpy(buffer + gotsize , form->data->line + form->sent, + memcpy(buffer + gotsize, form->data->line + form->sent, wantedsize - gotsize); form->sent += wantedsize-gotsize; @@ -1514,7 +1549,7 @@ char *Curl_formpostheader(void *formp, size_t *len) * formboundary() creates a suitable boundary string and returns an allocated * one. */ -static char *formboundary(struct SessionHandle *data) +static char *formboundary(struct Curl_easy *data) { /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615) combinations */ diff --git a/lib/formdata.h b/lib/formdata.h index 22f504b..6eb7c6c 100644 --- a/lib/formdata.h +++ b/lib/formdata.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -54,7 +54,7 @@ typedef struct FormInfo { size_t namelength; char *value; bool value_alloc; - size_t contentslength; + curl_off_t contentslength; char *contenttype; bool contenttype_alloc; long flags; @@ -68,9 +68,9 @@ typedef struct FormInfo { struct FormInfo *more; } FormInfo; -int Curl_FormInit(struct Form *form, struct FormData *formdata ); +int Curl_FormInit(struct Form *form, struct FormData *formdata); -CURLcode Curl_getformdata(struct SessionHandle *data, +CURLcode Curl_getformdata(struct Curl_easy *data, struct FormData **, struct curl_httppost *post, const char *custom_contenttype, @@ -93,6 +93,6 @@ char *Curl_FormBoundary(void); void Curl_formclean(struct FormData **); -CURLcode Curl_formconvert(struct SessionHandle *, struct FormData *); +CURLcode Curl_formconvert(struct Curl_easy *, struct FormData *); #endif /* HEADER_CURL_FORMDATA_H */ diff --git a/lib/ftp.c b/lib/ftp.c index fade092..8af6531 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -77,10 +77,9 @@ #include "warnless.h" #include "http_proxy.h" #include "non-ascii.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" #ifndef NI_MAXHOST @@ -155,8 +154,9 @@ static CURLcode ftp_dophase_done(struct connectdata *conn, bool connected); /* easy-to-use macro: */ -#define PPSENDF(x,y,z) if((result = Curl_pp_sendf(x,y,z))) \ - return result +#define PPSENDF(x,y,z) result = Curl_pp_sendf(x,y,z); \ + if(result) \ + return result /* @@ -265,6 +265,15 @@ static const struct Curl_handler Curl_handler_ftps_proxy = { #endif #endif +static void close_secondarysocket(struct connectdata *conn) +{ + if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) { + Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); + conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; + } + conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; + conn->tunnel_state[SECONDARYSOCKET] = TUNNEL_INIT; +} /* * NOTE: back in the old days, we added code in the FTP code that made NOBODY @@ -318,7 +327,7 @@ static bool isBadFtpString(const char *string) */ static CURLcode AcceptServerConnect(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_socket_t sock = conn->sock[SECONDARYSOCKET]; curl_socket_t s = CURL_SOCKET_BAD; #ifdef ENABLE_IPV6 @@ -340,6 +349,9 @@ static CURLcode AcceptServerConnect(struct connectdata *conn) return CURLE_FTP_PORT_FAILED; } infof(data, "Connection accepted from server\n"); + /* when this happens within the DO state it is important that we mark us as + not needing DO_MORE anymore */ + conn->bits.do_more = FALSE; conn->sock[SECONDARYSOCKET] = s; (void)curlx_nonblock(s, TRUE); /* enable non-blocking */ @@ -354,8 +366,7 @@ static CURLcode AcceptServerConnect(struct connectdata *conn) CURLSOCKTYPE_ACCEPT); if(error) { - Curl_closesocket(conn, s); /* close the socket and bail out */ - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; + close_secondarysocket(conn); return CURLE_ABORTED_BY_CALLBACK; } } @@ -373,7 +384,7 @@ static CURLcode AcceptServerConnect(struct connectdata *conn) * Curl_pgrsTime(..., TIMER_STARTACCEPT); * */ -static long ftp_timeleft_accept(struct SessionHandle *data) +static long ftp_timeleft_accept(struct Curl_easy *data) { long timeout_ms = DEFAULT_ACCEPT_TIMEOUT; long other; @@ -413,7 +424,7 @@ static long ftp_timeleft_accept(struct SessionHandle *data) */ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET]; curl_socket_t data_sock = conn->sock[SECONDARYSOCKET]; struct ftp_conn *ftpc = &conn->proto.ftpc; @@ -484,7 +495,7 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received) */ static CURLcode InitiateTransfer(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; CURLcode result = CURLE_OK; @@ -535,7 +546,7 @@ static CURLcode InitiateTransfer(struct connectdata *conn) */ static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; long timeout_ms; CURLcode result = CURLE_OK; @@ -606,7 +617,7 @@ static CURLcode ftp_readresp(curl_socket_t sockfd, size_t *size) /* size of the response */ { struct connectdata *conn = pp->conn; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; #ifdef HAVE_GSSAPI char * const buf = data->state.buffer; #endif @@ -678,7 +689,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; long timeout; /* timeout in milliseconds */ long interval_ms; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; @@ -698,7 +709,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ /* check and reset timeout value every lap */ timeout = Curl_pp_state_timeout(pp); - if(timeout <=0 ) { + if(timeout <=0) { failf(data, "FTP response timeout"); return CURLE_OPERATION_TIMEDOUT; /* already too little time */ } @@ -969,7 +980,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, { CURLcode result = CURLE_OK; struct ftp_conn *ftpc = &conn->proto.ftpc; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; curl_socket_t portsock= CURL_SOCKET_BAD; char myhost[256] = ""; @@ -1024,7 +1035,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(*string_ftpport == '[') { /* [ipv6]:port(-range) */ ip_start = string_ftpport + 1; - if((ip_end = strchr(string_ftpport, ']')) != NULL ) + if((ip_end = strchr(string_ftpport, ']')) != NULL) strncpy(addr, ip_start, ip_end - ip_start); } else @@ -1045,7 +1056,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, else #endif /* (ipv4|domain|interface):port(-range) */ - strncpy(addr, string_ftpport, ip_end - ip_start ); + strncpy(addr, string_ftpport, ip_end - ip_start); } else /* ipv4|interface */ @@ -1065,11 +1076,11 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, /* correct errors like: * :1234-1230 - * :-4711 , in this case port_min is (unsigned)-1, + * :-4711, in this case port_min is (unsigned)-1, * therefore port_min > port_max for all cases * but port_max = (unsigned)-1 */ - if(port_min > port_max ) + if(port_min > port_max) port_min = port_max = 0; @@ -1322,11 +1333,11 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, /* store which command was sent */ ftpc->count1 = fcmd; + close_secondarysocket(conn); + /* we set the secondary socket variable to this for now, it is only so that the cleanup function will close it in case we fail before the true secondary stuff is made */ - if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) - Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); conn->sock[SECONDARYSOCKET] = portsock; /* this tcpconnect assignment below is a hackish work-around to make the @@ -1392,7 +1403,7 @@ static CURLcode ftp_state_prepare_transfer(struct connectdata *conn) { CURLcode result = CURLE_OK; struct FTP *ftp = conn->data->req.protop; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(ftp->transfer != FTPTRANSFER_BODY) { /* doesn't transfer any data */ @@ -1475,7 +1486,7 @@ static CURLcode ftp_state_size(struct connectdata *conn) static CURLcode ftp_state_list(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* If this output is to be machine-parsed, the NLST command might be better to use, since the LIST command output is not specified or standard in any @@ -1513,12 +1524,12 @@ static CURLcode ftp_state_list(struct connectdata *conn) } } - cmd = aprintf( "%s%s%s", - data->set.str[STRING_CUSTOMREQUEST]? - data->set.str[STRING_CUSTOMREQUEST]: - (data->set.ftp_list_only?"NLST":"LIST"), - lstArg? " ": "", - lstArg? lstArg: "" ); + cmd = aprintf("%s%s%s", + data->set.str[STRING_CUSTOMREQUEST]? + data->set.str[STRING_CUSTOMREQUEST]: + (data->set.ftp_list_only?"NLST":"LIST"), + lstArg? " ": "", + lstArg? lstArg: ""); if(!cmd) { free(lstArg); @@ -1564,7 +1575,7 @@ static CURLcode ftp_state_type(struct connectdata *conn) { CURLcode result = CURLE_OK; struct FTP *ftp = conn->data->req.protop; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; /* If we have selected NOBODY and HEADER, it means that we only want file @@ -1596,7 +1607,7 @@ static CURLcode ftp_state_type(struct connectdata *conn) static CURLcode ftp_state_mdtm(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; /* Requested time of file or time-depended transfer? */ @@ -1621,7 +1632,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn, { CURLcode result = CURLE_OK; struct FTP *ftp = conn->data->req.protop; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; int seekerr = CURL_SEEKFUNC_OK; @@ -1640,7 +1651,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn, /* 4. lower the infilesize counter */ /* => transfer as usual */ - if(data->state.resume_from < 0 ) { + if(data->state.resume_from < 0) { /* Got no given size to start from, figure it out */ PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); state(conn, FTP_STOR_SIZE); @@ -1670,8 +1681,8 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn, BUFSIZE : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread = - data->set.fread_func(data->state.buffer, 1, readthisamountnow, - data->set.in); + data->state.fread_func(data->state.buffer, 1, readthisamountnow, + data->state.in); passed += actuallyread; if((actuallyread == 0) || (actuallyread > readthisamountnow)) { @@ -1717,7 +1728,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn, ftpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; bool quote=FALSE; @@ -1787,8 +1798,20 @@ static CURLcode ftp_state_quote(struct connectdata *conn, result = ftp_state_retr(conn, ftpc->known_filesize); } else { - PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); - state(conn, FTP_RETR_SIZE); + if(data->set.ignorecl) { + /* This code is to support download of growing files. It prevents + the state machine from requesting the file size from the + server. With an unknown file size the download continues until + the server terminates it, otherwise the client stops if the + received byte count exceeds the reported file size. Set option + CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/ + PPSENDF(&ftpc->pp, "RETR %s", ftpc->file); + state(conn, FTP_RETR); + } + else { + PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); + state(conn, FTP_RETR_SIZE); + } } } break; @@ -1836,7 +1859,7 @@ static CURLcode proxy_magic(struct connectdata *conn, bool *magicdone) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; #if defined(CURL_DISABLE_PROXY) (void) newhost; @@ -1927,7 +1950,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, { struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; struct Curl_dns_entry *addr=NULL; int rc; unsigned short connectport; /* the local port connect() should use! */ @@ -2102,7 +2125,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, static CURLcode ftp_state_port_resp(struct connectdata *conn, int ftpcode) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; ftpport fcmd = (ftpport)ftpc->count1; CURLcode result = CURLE_OK; @@ -2139,7 +2162,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, int ftpcode) { CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; @@ -2244,7 +2267,7 @@ static CURLcode ftp_state_type_resp(struct connectdata *conn, ftpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; if(ftpcode/100 != 2) { /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a @@ -2273,7 +2296,7 @@ static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize) { CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; @@ -2356,7 +2379,7 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn, ftpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; curl_off_t filesize; char *buf = data->state.buffer; @@ -2428,7 +2451,7 @@ static CURLcode ftp_state_stor_resp(struct connectdata *conn, int ftpcode, ftpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(ftpcode>=400) { failf(data, "Failed FTP upload: %0d", ftpcode); @@ -2467,7 +2490,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn, ftpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; char *buf = data->state.buffer; @@ -2624,7 +2647,7 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn, ftpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; (void)instate; /* no use for this yet */ @@ -2679,7 +2702,7 @@ static CURLcode ftp_state_acct_resp(struct connectdata *conn, int ftpcode) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(ftpcode != 230) { failf(data, "ACCT rejected by server: %03d", ftpcode); result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */ @@ -2695,7 +2718,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) { CURLcode result; curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; int ftpcode; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; @@ -3218,9 +3241,9 @@ static CURLcode ftp_connect(struct connectdata *conn, * Input argument is already checked for validity. */ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, - bool premature) + bool premature) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; @@ -3232,11 +3255,6 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, const char *path_to_use = data->state.path; if(!ftp) - /* When the easy handle is removed from the multi while libcurl is still - * trying to resolve the host name, it seems that the ftp struct is not - * yet initialized, but the removal action calls Curl_done() which calls - * this function. So we simply return success if no ftp pointer is set. - */ return CURLE_OK; switch(status) { @@ -3345,11 +3363,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, /* Note that we keep "use" set to TRUE since that (next) connection is still requested to use SSL */ } - if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) { - Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; - conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; - } + close_secondarysocket(conn); } if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid && @@ -3573,7 +3587,7 @@ static CURLcode ftp_range(struct connectdata *conn) curl_off_t from, to; char *ptr; char *ptr2; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; if(data->state.use_range && data->state.range) { @@ -3631,7 +3645,7 @@ static CURLcode ftp_range(struct connectdata *conn) static CURLcode ftp_do_more(struct connectdata *conn, int *completep) { - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result = CURLE_OK; bool connected = FALSE; @@ -3720,7 +3734,13 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep) return result; result = ftp_multi_statemach(conn, &complete); - *completep = (int)complete; + if(ftpc->wait_data_conn) + /* if we reach the end of the FTP state machine here, *complete will be + TRUE but so is ftpc->wait_data_conn, which says we need to wait for + the data connection and therefore we're not actually complete */ + *completep = 0; + else + *completep = (int)complete; } else { /* download */ @@ -4189,7 +4209,7 @@ static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection) (void)ftp_quit(conn); /* ignore errors on the QUIT */ if(ftpc->entrypath) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) { data->state.most_recent_ftp_entrypath = NULL; } @@ -4222,7 +4242,7 @@ static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection) static CURLcode ftp_parse_url_path(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* the ftp struct is already inited in ftp_connect() */ struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; @@ -4248,16 +4268,17 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) the first condition in the if() right here, is there just in case someone decides to set path to NULL one day */ - if(data->state.path && - data->state.path[0] && - (data->state.path[strlen(data->state.path) - 1] != '/') ) - filename = data->state.path; /* this is a full file path */ - /* + if(path_to_use[0] && + (path_to_use[strlen(path_to_use) - 1] != '/') ) + filename = path_to_use; /* this is a full file path */ + /* + else { ftpc->file is not used anywhere other than for operations on a file. In other words, never for directory operations. So we can safely leave filename as NULL here and use it as a argument in dir/file decisions. - */ + } + */ break; case FTPFILE_SINGLECWD: @@ -4422,11 +4443,7 @@ static CURLcode ftp_dophase_done(struct connectdata *conn, CURLcode result = ftp_do_more(conn, &completed); if(result) { - if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) { - /* close the second socket if it was created already */ - Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; - } + close_secondarysocket(conn); return result; } } @@ -4477,7 +4494,7 @@ CURLcode ftp_regular_transfer(struct connectdata *conn, { CURLcode result=CURLE_OK; bool connected=FALSE; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; data->req.size = -1; /* make sure this is unknown at this point */ @@ -4511,7 +4528,7 @@ CURLcode ftp_regular_transfer(struct connectdata *conn, static CURLcode ftp_setup_connection(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char *type; char command; struct FTP *ftp; diff --git a/lib/ftp.h b/lib/ftp.h index 833447b..2ed5b43 100644 --- a/lib/ftp.h +++ b/lib/ftp.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -97,9 +97,9 @@ typedef enum { file */ } curl_ftpfile; -/* This FTP struct is used in the SessionHandle. All FTP data that is +/* This FTP struct is used in the Curl_easy. All FTP data that is connection-oriented must be in FTP_conn to properly deal with the fact that - perhaps the SessionHandle is changed between the times the connection is + perhaps the Curl_easy is changed between the times the connection is used. */ struct FTP { curl_off_t *bytecountp; diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c index 17e0a66..abbf76e 100644 --- a/lib/ftplistparser.c +++ b/lib/ftplistparser.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -275,26 +275,6 @@ static void PL_ERROR(struct connectdata *conn, CURLcode err) parser->error = err; } -static bool ftp_pl_gettime(struct ftp_parselist_data *parser, char *string) -{ - (void)parser; - (void)string; - /* TODO - * There could be possible parse timestamp from server. Leaving unimplemented - * for now. - * If you want implement this, please add CURLFINFOFLAG_KNOWN_TIME flag to - * parser->file_data->flags - * - * Ftp servers are giving usually these formats: - * Apr 11 1998 (unknown time.. set it to 00:00:00?) - * Apr 11 12:21 (unknown year -> set it to NOW() time?) - * 08-05-09 02:49PM (ms-dos format) - * 20100421092538 -> for MLST/MLSD response - */ - - return FALSE; -} - static CURLcode ftp_pl_insert_finfo(struct connectdata *conn, struct curl_fileinfo *finfo) { @@ -715,9 +695,11 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, if(c == ' ') { finfo->b_data[parser->item_offset + parser->item_length -1] = 0; parser->offsets.time = parser->item_offset; - if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) { - parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME; - } + /* + if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) { + parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME; + } + */ if(finfo->filetype == CURLFILETYPE_SYMLINK) { parser->state.UNIX.main = PL_UNIX_SYMLINK; parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE; @@ -746,7 +728,6 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, case PL_UNIX_FILENAME_NAME: parser->item_length++; if(c == '\r') { - parser->item_length--; parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL; } else if(c == '\n') { @@ -762,7 +743,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, break; case PL_UNIX_FILENAME_WINDOWSEOL: if(c == '\n') { - finfo->b_data[parser->item_offset + parser->item_length] = 0; + finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; parser->offsets.filename = parser->item_offset; parser->state.UNIX.main = PL_UNIX_FILETYPE; result = ftp_pl_insert_finfo(conn, finfo); @@ -853,9 +834,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, } break; case PL_UNIX_SYMLINK_TARGET: - parser->item_length ++; + parser->item_length++; if(c == '\r') { - parser->item_length --; parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL; } else if(c == '\n') { diff --git a/lib/ftplistparser.h b/lib/ftplistparser.h index 96764e2..8128887 100644 --- a/lib/ftplistparser.h +++ b/lib/ftplistparser.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/getenv.c b/lib/getenv.c index 36215aa..50bb79f 100644 --- a/lib/getenv.c +++ b/lib/getenv.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/getinfo.c b/lib/getinfo.c index 910f520..262cd93 100644 --- a/lib/getinfo.c +++ b/lib/getinfo.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -39,7 +39,7 @@ * This is supposed to be called in the beginning of a perform() session * and should reset all session-info variables */ -CURLcode Curl_initinfo(struct SessionHandle *data) +CURLcode Curl_initinfo(struct Curl_easy *data) { struct Progress *pro = &data->progress; struct PureInfo *info = &data->info; @@ -73,7 +73,7 @@ CURLcode Curl_initinfo(struct SessionHandle *data) return CURLE_OK; } -static CURLcode getinfo_char(struct SessionHandle *data, CURLINFO info, +static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info, char **param_charp) { switch(info) { @@ -113,13 +113,13 @@ static CURLcode getinfo_char(struct SessionHandle *data, CURLINFO info, break; default: - return CURLE_BAD_FUNCTION_ARGUMENT; + return CURLE_UNKNOWN_OPTION; } return CURLE_OK; } -static CURLcode getinfo_long(struct SessionHandle *data, CURLINFO info, +static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, long *param_longp) { curl_socket_t sockfd; @@ -198,15 +198,31 @@ static CURLcode getinfo_long(struct SessionHandle *data, CURLINFO info, case CURLINFO_RTSP_CSEQ_RECV: *param_longp = data->state.rtsp_CSeq_recv; break; + case CURLINFO_HTTP_VERSION: + switch (data->info.httpversion) { + case 10: + *param_longp = CURL_HTTP_VERSION_1_0; + break; + case 11: + *param_longp = CURL_HTTP_VERSION_1_1; + break; + case 20: + *param_longp = CURL_HTTP_VERSION_2_0; + break; + default: + *param_longp = CURL_HTTP_VERSION_NONE; + break; + } + break; default: - return CURLE_BAD_FUNCTION_ARGUMENT; + return CURLE_UNKNOWN_OPTION; } return CURLE_OK; } -static CURLcode getinfo_double(struct SessionHandle *data, CURLINFO info, +static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info, double *param_doublep) { switch(info) { @@ -253,13 +269,13 @@ static CURLcode getinfo_double(struct SessionHandle *data, CURLINFO info, break; default: - return CURLE_BAD_FUNCTION_ARGUMENT; + return CURLE_UNKNOWN_OPTION; } return CURLE_OK; } -static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info, +static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info, struct curl_slist **param_slistp) { union { @@ -281,69 +297,84 @@ static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info, *param_slistp = ptr.to_slist; break; case CURLINFO_TLS_SESSION: + case CURLINFO_TLS_SSL_PTR: { struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **) param_slistp; struct curl_tlssessioninfo *tsi = &data->tsi; struct connectdata *conn = data->easy_conn; - unsigned int sockindex = 0; - void *internals = NULL; *tsip = tsi; - tsi->backend = CURLSSLBACKEND_NONE; + tsi->backend = Curl_ssl_backend(); tsi->internals = NULL; - if(!conn) - break; - - /* Find the active ("in use") SSL connection, if any */ - while((sockindex < sizeof(conn->ssl) / sizeof(conn->ssl[0])) && - (!conn->ssl[sockindex].use)) - sockindex++; - - if(sockindex == sizeof(conn->ssl) / sizeof(conn->ssl[0])) - break; /* no SSL session found */ - - /* Return the TLS session information from the relevant backend */ -#ifdef USE_OPENSSL - internals = conn->ssl[sockindex].ctx; + if(conn && tsi->backend != CURLSSLBACKEND_NONE) { + unsigned int i; + for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) { + if(conn->ssl[i].use) { +#if defined(USE_AXTLS) + tsi->internals = (void *)conn->ssl[i].ssl; +#elif defined(USE_CYASSL) + tsi->internals = (void *)conn->ssl[i].handle; +#elif defined(USE_DARWINSSL) + tsi->internals = (void *)conn->ssl[i].ssl_ctx; +#elif defined(USE_GNUTLS) + tsi->internals = (void *)conn->ssl[i].session; +#elif defined(USE_GSKIT) + tsi->internals = (void *)conn->ssl[i].handle; +#elif defined(USE_MBEDTLS) + tsi->internals = (void *)&conn->ssl[i].ssl; +#elif defined(USE_NSS) + tsi->internals = (void *)conn->ssl[i].handle; +#elif defined(USE_OPENSSL) + /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */ + tsi->internals = ((info == CURLINFO_TLS_SESSION) ? + (void *)conn->ssl[i].ctx : + (void *)conn->ssl[i].handle); +#elif defined(USE_POLARSSL) + tsi->internals = (void *)&conn->ssl[i].ssl; +#elif defined(USE_SCHANNEL) + tsi->internals = (void *)&conn->ssl[i].ctxt->ctxt_handle; +#elif defined(USE_SSL) +#error "SSL backend specific information missing for CURLINFO_TLS_SSL_PTR" #endif -#ifdef USE_GNUTLS - internals = conn->ssl[sockindex].session; -#endif -#ifdef USE_NSS - internals = conn->ssl[sockindex].handle; -#endif -#ifdef USE_GSKIT - internals = conn->ssl[sockindex].handle; -#endif - if(internals) { - tsi->backend = Curl_ssl_backend(); - tsi->internals = internals; + break; + } + } } - /* NOTE: For other SSL backends, it is not immediately clear what data - to return from 'struct ssl_connect_data'; thus, for now we keep the - backend as CURLSSLBACKEND_NONE in those cases, which should be - interpreted as "not supported" */ } break; default: - return CURLE_BAD_FUNCTION_ARGUMENT; + return CURLE_UNKNOWN_OPTION; + } + + return CURLE_OK; +} + +static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info, + curl_socket_t *param_socketp) +{ + switch(info) { + case CURLINFO_ACTIVESOCKET: + *param_socketp = Curl_getconnectinfo(data, NULL); + break; + default: + return CURLE_UNKNOWN_OPTION; } return CURLE_OK; } -CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) +CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...) { va_list arg; long *param_longp = NULL; double *param_doublep = NULL; char **param_charp = NULL; struct curl_slist **param_slistp = NULL; + curl_socket_t *param_socketp = NULL; int type; - /* default return code is to error out! */ - CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; + CURLcode result = CURLE_UNKNOWN_OPTION; if(!data) return result; @@ -372,6 +403,11 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) if(param_slistp) result = getinfo_slist(data, info, param_slistp); break; + case CURLINFO_SOCKET: + param_socketp = va_arg(arg, curl_socket_t *); + if(param_socketp) + result = getinfo_socket(data, info, param_socketp); + break; default: break; } diff --git a/lib/getinfo.h b/lib/getinfo.h index 3879ff7..aecf717 100644 --- a/lib/getinfo.h +++ b/lib/getinfo.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,7 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ -CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...); -CURLcode Curl_initinfo(struct SessionHandle *data); +CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...); +CURLcode Curl_initinfo(struct Curl_easy *data); #endif /* HEADER_CURL_GETINFO_H */ diff --git a/lib/gopher.c b/lib/gopher.c index 954cad8..f1efb60 100644 --- a/lib/gopher.c +++ b/lib/gopher.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -75,7 +75,7 @@ const struct Curl_handler Curl_handler_gopher = { static CURLcode gopher_do(struct connectdata *conn, bool *done) { CURLcode result=CURLE_OK; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; curl_off_t *bytecount = &data->req.bytecount; @@ -83,16 +83,18 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) char *sel; char *sel_org = NULL; ssize_t amount, k; + int len; *done = TRUE; /* unconditionally */ /* Create selector. Degenerate cases: / and /1 => convert to "" */ - if(strlen(path) <= 2) + if(strlen(path) <= 2) { sel = (char *)""; + len = (int)strlen(sel); + } else { char *newp; size_t j, i; - int len; /* Otherwise, drop / and the first character (i.e., item type) ... */ newp = path; @@ -113,7 +115,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) /* We use Curl_write instead of Curl_sendf to make sure the entire buffer is sent, which could be sizeable with long selectors. */ - k = curlx_uztosz(strlen(sel)); + k = curlx_uztosz(len); for(;;) { result = Curl_write(conn, sockfd, sel, k, &amount); diff --git a/lib/gopher.h b/lib/gopher.h index 38bbc4b..501c990 100644 --- a/lib/gopher.h +++ b/lib/gopher.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/hash.c b/lib/hash.c index c46760a..937381b 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,9 +22,12 @@ #include "curl_setup.h" +#include + #include "hash.h" #include "llist.h" #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" @@ -46,7 +49,12 @@ hash_element_dtor(void *user, void *element) free(e); } -/* return 1 on error, 0 is fine */ +/* Initializes a hash structure. + * Return 1 on error, 0 is fine. + * + * @unittest: 1602 + * @unittest: 1603 + */ int Curl_hash_init(struct curl_hash *h, int slots, @@ -119,6 +127,8 @@ mk_hash_element(const void *key, size_t key_len, const void *p) * that data is replaced. * * @unittest: 1305 + * @unittest: 1602 + * @unittest: 1603 */ void * Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p) @@ -155,7 +165,11 @@ Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p) return NULL; /* failure */ } -/* remove the identified hash entry, returns non-zero on failure */ +/* Remove the identified hash entry. + * Returns non-zero on failure. + * + * @unittest: 1603 + */ int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len) { struct curl_llist_element *le; @@ -173,6 +187,10 @@ int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len) return 1; } +/* Retrieves a hash element. + * + * @unittest: 1603 + */ void * Curl_hash_pick(struct curl_hash *h, void *key, size_t key_len) { @@ -214,6 +232,10 @@ Curl_hash_apply(curl_hash *h, void *user, /* Destroys all the entries in the given hash and resets its attributes, * prepping the given hash for [static|dynamic] deallocation. + * + * @unittest: 1305 + * @unittest: 1602 + * @unittest: 1603 */ void Curl_hash_destroy(struct curl_hash *h) diff --git a/lib/hash.h b/lib/hash.h index b13a236..57a17f0 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/hmac.c b/lib/hmac.c index 0d2d5f4..3df4715 100644 --- a/lib/hmac.c +++ b/lib/hmac.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,8 +26,11 @@ #ifndef CURL_DISABLE_CRYPTO_AUTH +#include + #include "curl_hmac.h" #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" diff --git a/lib/hostasyn.c b/lib/hostasyn.c index 17b8be0..28bdf7a 100644 --- a/lib/hostasyn.c +++ b/lib/hostasyn.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -77,7 +77,7 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn, if(CURL_ASYNC_SUCCESS == status) { if(ai) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); diff --git a/lib/hostcheck.c b/lib/hostcheck.c index 62a26e4..4db9e6b 100644 --- a/lib/hostcheck.c +++ b/lib/hostcheck.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -43,7 +43,7 @@ * "foo.host.com" matches "*.host.com". * * We use the matching rule described in RFC6125, section 6.4.3. - * http://tools.ietf.org/html/rfc6125#section-6.4.3 + * https://tools.ietf.org/html/rfc6125#section-6.4.3 * * In addition: ignore trailing dots in the host names and wildcards, so that * the names are used normalized. This is what the browsers do. diff --git a/lib/hostcheck.h b/lib/hostcheck.h index f4a517a..86e3b96 100644 --- a/lib/hostcheck.h +++ b/lib/hostcheck.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/hostip.c b/lib/hostip.c index 82f3897..f2d9841 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -56,9 +56,9 @@ #include "url.h" #include "inet_ntop.h" #include "warnless.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" #if defined(CURLRES_SYNCH) && \ @@ -254,7 +254,7 @@ hostcache_prune(struct curl_hash *hostcache, long cache_timeout, time_t now) * Library-wide function for pruning the DNS cache. This function takes and * returns the appropriate locks. */ -void Curl_hostcache_prune(struct SessionHandle *data) +void Curl_hostcache_prune(struct Curl_easy *data) { time_t now; @@ -293,7 +293,7 @@ fetch_addr(struct connectdata *conn, char *entry_id = NULL; struct Curl_dns_entry *dns = NULL; size_t entry_len; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Create an entry id, based upon the hostname and port */ entry_id = create_hostcache_id(hostname, port); @@ -345,7 +345,7 @@ Curl_fetch_addr(struct connectdata *conn, const char *hostname, int port) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct Curl_dns_entry *dns = NULL; if(data->share) @@ -353,7 +353,8 @@ Curl_fetch_addr(struct connectdata *conn, dns = fetch_addr(conn, hostname, port); - if(dns) dns->inuse++; /* we use it! */ + if(dns) + dns->inuse++; /* we use it! */ if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); @@ -371,7 +372,7 @@ Curl_fetch_addr(struct connectdata *conn, * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. */ struct Curl_dns_entry * -Curl_cache_addr(struct SessionHandle *data, +Curl_cache_addr(struct Curl_easy *data, Curl_addrinfo *addr, const char *hostname, int port) @@ -446,7 +447,7 @@ int Curl_resolv(struct connectdata *conn, struct Curl_dns_entry **entry) { struct Curl_dns_entry *dns = NULL; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result; int rc = CURLRESOLV_ERROR; /* default to failure */ @@ -581,7 +582,7 @@ int Curl_resolv_timeout(struct connectdata *conn, #endif /* HAVE_SIGACTION */ volatile long timeout; volatile unsigned int prev_alarm = 0; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; #endif /* USE_ALARM_TIMEOUT */ int rc; @@ -715,7 +716,7 @@ clean_up: * * May be called with 'data' == NULL for global cache. */ -void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns) +void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns) { if(data && data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); @@ -757,7 +758,7 @@ int Curl_mk_dnscache(struct curl_hash *hash) * can be done! */ -void Curl_hostcache_clean(struct SessionHandle *data, +void Curl_hostcache_clean(struct Curl_easy *data, struct curl_hash *hash) { if(data && data->share) @@ -770,14 +771,14 @@ void Curl_hostcache_clean(struct SessionHandle *data, } -CURLcode Curl_loadhostpairs(struct SessionHandle *data) +CURLcode Curl_loadhostpairs(struct Curl_easy *data) { struct curl_slist *hostp; char hostname[256]; char address[256]; int port; - for(hostp = data->change.resolve; hostp; hostp = hostp->next ) { + for(hostp = data->change.resolve; hostp; hostp = hostp->next) { if(!hostp->data) continue; if(hostp->data[0] == '-') { diff --git a/lib/hostip.h b/lib/hostip.h index d5b44bc..9098ee3 100644 --- a/lib/hostip.h +++ b/lib/hostip.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -50,7 +50,7 @@ struct addrinfo; struct hostent; -struct SessionHandle; +struct Curl_easy; struct connectdata; /* @@ -118,7 +118,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, /* unlock a previously resolved dns entry */ -void Curl_resolv_unlock(struct SessionHandle *data, +void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns); /* for debugging purposes only: */ @@ -128,7 +128,7 @@ void Curl_scan_cache_used(void *user, void *ptr); int Curl_mk_dnscache(struct curl_hash *hash); /* prune old entries from the DNS cache */ -void Curl_hostcache_prune(struct SessionHandle *data); +void Curl_hostcache_prune(struct Curl_easy *data); /* Return # of adresses in a Curl_addrinfo struct */ int Curl_num_addresses (const Curl_addrinfo *addr); @@ -188,7 +188,7 @@ Curl_fetch_addr(struct connectdata *conn, * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. */ struct Curl_dns_entry * -Curl_cache_addr(struct SessionHandle *data, Curl_addrinfo *addr, +Curl_cache_addr(struct Curl_easy *data, Curl_addrinfo *addr, const char *hostname, int port); #ifndef INADDR_NONE @@ -209,42 +209,42 @@ extern sigjmp_buf curl_jmpenv; /* * Function provided by the resolver backend to set DNS servers to use. */ -CURLcode Curl_set_dns_servers(struct SessionHandle *data, char *servers); +CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers); /* * Function provided by the resolver backend to set * outgoing interface to use for DNS requests */ -CURLcode Curl_set_dns_interface(struct SessionHandle *data, +CURLcode Curl_set_dns_interface(struct Curl_easy *data, const char *interf); /* * Function provided by the resolver backend to set * local IPv4 address to use as source address for DNS requests */ -CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, const char *local_ip4); /* * Function provided by the resolver backend to set * local IPv6 address to use as source address for DNS requests */ -CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, const char *local_ip6); /* * Clean off entries from the cache */ -void Curl_hostcache_clean(struct SessionHandle *data, struct curl_hash *hash); +void Curl_hostcache_clean(struct Curl_easy *data, struct curl_hash *hash); /* * Destroy the hostcache of this handle. */ -void Curl_hostcache_destroy(struct SessionHandle *data); +void Curl_hostcache_destroy(struct Curl_easy *data); /* * Populate the cache with specified entries from CURLOPT_RESOLVE. */ -CURLcode Curl_loadhostpairs(struct SessionHandle *data); +CURLcode Curl_loadhostpairs(struct Curl_easy *data); #endif /* HEADER_CURL_HOSTIP_H */ diff --git a/lib/hostip4.c b/lib/hostip4.c index 37b0369..15895d7 100644 --- a/lib/hostip4.c +++ b/lib/hostip4.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -48,9 +48,9 @@ #include "strerror.h" #include "url.h" #include "inet_pton.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /*********************************************************************** diff --git a/lib/hostip6.c b/lib/hostip6.c index 6ab131a..4ebfc2d 100644 --- a/lib/hostip6.c +++ b/lib/hostip6.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -49,9 +49,9 @@ #include "url.h" #include "inet_pton.h" #include "connect.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /*********************************************************************** @@ -59,7 +59,6 @@ **********************************************************************/ #ifdef CURLRES_IPV6 - #if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) /* These are strictly for memory tracing and are using the same style as the * family otherwise present in memdebug.c. I put these ones here since they @@ -124,6 +123,7 @@ bool Curl_ipvalid(struct connectdata *conn) { if(conn->ip_version == CURL_IPRESOLVE_V6) return Curl_ipv6works(); + return TRUE; } @@ -167,15 +167,17 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, int error; char sbuf[12]; char *sbufptr = NULL; +#ifndef USE_RESOLVE_ON_IPS char addrbuf[128]; +#endif int pf; - struct SessionHandle *data = conn->data; +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) + struct Curl_easy *data = conn->data; +#endif *waitp = 0; /* synchronous response only */ - /* - * Check if a limited name resolve has been requested. - */ + /* Check if a limited name resolve has been requested */ switch(conn->ip_version) { case CURL_IPRESOLVE_V4: pf = PF_INET; @@ -196,26 +198,37 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, hints.ai_family = pf; hints.ai_socktype = conn->socktype; +#ifndef USE_RESOLVE_ON_IPS + /* + * The AI_NUMERICHOST must not be set to get synthesized IPv6 address from + * an IPv4 address on iOS and Mac OS X. + */ if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) || (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) { /* the given address is numerical only, prevent a reverse lookup */ hints.ai_flags = AI_NUMERICHOST; } +#endif if(port) { snprintf(sbuf, sizeof(sbuf), "%d", port); sbufptr=sbuf; } + error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res); if(error) { infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port); return NULL; } + if(port) { + Curl_addrinfo_set_port(res, port); + } + dump_addrinfo(conn, res); return res; } #endif /* CURLRES_SYNCH */ -#endif /* CURLRES_IPV6 */ +#endif /* CURLRES_IPV6 */ diff --git a/lib/hostsyn.c b/lib/hostsyn.c index fb1de35..1a95263 100644 --- a/lib/hostsyn.c +++ b/lib/hostsyn.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -59,7 +59,7 @@ /* * Function provided by the resolver backend to set DNS servers to use. */ -CURLcode Curl_set_dns_servers(struct SessionHandle *data, +CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers) { (void)data; @@ -72,7 +72,7 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data, * Function provided by the resolver backend to set * outgoing interface to use for DNS requests */ -CURLcode Curl_set_dns_interface(struct SessionHandle *data, +CURLcode Curl_set_dns_interface(struct Curl_easy *data, const char *interf) { (void)data; @@ -84,7 +84,7 @@ CURLcode Curl_set_dns_interface(struct SessionHandle *data, * Function provided by the resolver backend to set * local IPv4 address to use as source address for DNS requests */ -CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, const char *local_ip4) { (void)data; @@ -96,7 +96,7 @@ CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, * Function provided by the resolver backend to set * local IPv6 address to use as source address for DNS requests */ -CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, const char *local_ip6) { (void)data; diff --git a/lib/http.c b/lib/http.c index 9817d72..378d8f7 100644 --- a/lib/http.c +++ b/lib/http.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -54,9 +54,10 @@ #include "curl_base64.h" #include "cookie.h" #include "strequal.h" +#include "vauth/vauth.h" #include "vtls/vtls.h" #include "http_digest.h" -#include "curl_ntlm.h" +#include "http_ntlm.h" #include "curl_ntlm_wb.h" #include "http_negotiate.h" #include "url.h" @@ -76,9 +77,9 @@ #include "pipeline.h" #include "http2.h" #include "connect.h" -#include "curl_printf.h" -/* The last #include files should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" @@ -144,14 +145,13 @@ const struct Curl_handler Curl_handler_https = { ZERO_NULL, /* readwrite */ PORT_HTTPS, /* defport */ CURLPROTO_HTTPS, /* protocol */ - PROTOPT_SSL | PROTOPT_CREDSPERREQUEST /* flags */ + PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN /* flags */ }; #endif - CURLcode Curl_http_setup_conn(struct connectdata *conn) { - /* allocate the HTTP-specific struct for the SessionHandle, only to survive + /* allocate the HTTP-specific struct for the Curl_easy, only to survive during this request */ struct HTTP *http; DEBUGASSERT(conn->data->req.protop == NULL); @@ -179,12 +179,13 @@ char *Curl_checkheaders(const struct connectdata *conn, { struct curl_slist *head; size_t thislen = strlen(thisheader); - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; for(head = data->set.headers;head; head=head->next) { if(Curl_raw_nequal(head->data, thisheader, thislen)) return head->data; } + return NULL; } @@ -193,24 +194,24 @@ char *Curl_checkheaders(const struct connectdata *conn, * if proxy headers are not available, then it will lookup into http header * link list * - * It takes a connectdata struct as input instead of the SessionHandle simply + * It takes a connectdata struct as input instead of the Curl_easy simply * to know if this is a proxy request or not, as it then might check a * different header list. - * */ char *Curl_checkProxyheaders(const struct connectdata *conn, const char *thisheader) { struct curl_slist *head; size_t thislen = strlen(thisheader); - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; - for(head = (conn->bits.proxy && data->set.sep_headers)? - data->set.proxyheaders:data->set.headers; + for(head = (conn->bits.proxy && data->set.sep_headers) ? + data->set.proxyheaders : data->set.headers; head; head=head->next) { if(Curl_raw_nequal(head->data, thisheader, thislen)) return head->data; } + return NULL; } @@ -279,7 +280,7 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) { size_t size = 0; char *authorization = NULL; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char **userp; const char *user; const char *pwd; @@ -309,7 +310,7 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) free(*userp); *userp = aprintf("%sAuthorization: Basic %s\r\n", - proxy?"Proxy-":"", + proxy ? "Proxy-" : "", authorization); free(authorization); if(!*userp) @@ -376,7 +377,7 @@ static bool pickoneauth(struct auth *pick) */ static CURLcode http_perhapsrewind(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct HTTP *http = data->req.protop; curl_off_t bytessent; curl_off_t expectsend = -1; /* default is unknown */ @@ -484,7 +485,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) CURLcode Curl_http_auth_act(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; bool pickhost = FALSE; bool pickproxy = FALSE; CURLcode result = CURLE_OK; @@ -528,7 +529,6 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) return result; } } - else if((data->req.httpcode < 300) && (!data->state.authhost.done) && conn->bits.authneg) { @@ -553,7 +553,6 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) return result; } - /* * Output the correct authentication header depending on the auth type * and whether or not it is to a proxy. @@ -567,12 +566,12 @@ output_auth_headers(struct connectdata *conn, { const char *auth = NULL; CURLcode result = CURLE_OK; -#if defined(USE_SPNEGO) || !defined(CURL_DISABLE_VERBOSE_STRINGS) - struct SessionHandle *data = conn->data; +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_SPNEGO) + struct Curl_easy *data = conn->data; #endif #ifdef USE_SPNEGO - struct negotiatedata *negdata = proxy? - &data->state.proxyneg:&data->state.negotiate; + struct negotiatedata *negdata = proxy ? + &data->state.proxyneg : &data->state.negotiate; #endif #ifdef CURL_DISABLE_CRYPTO_AUTH @@ -584,7 +583,7 @@ output_auth_headers(struct connectdata *conn, negdata->state = GSS_AUTHNONE; if((authstatus->picked == CURLAUTH_NEGOTIATE) && negdata->context && !GSS_ERROR(negdata->status)) { - auth="Negotiate"; + auth = "Negotiate"; result = Curl_output_negotiate(conn, proxy); if(result) return result; @@ -595,7 +594,7 @@ output_auth_headers(struct connectdata *conn, #endif #ifdef USE_NTLM if(authstatus->picked == CURLAUTH_NTLM) { - auth="NTLM"; + auth = "NTLM"; result = Curl_output_ntlm(conn, proxy); if(result) return result; @@ -613,7 +612,7 @@ output_auth_headers(struct connectdata *conn, #endif #ifndef CURL_DISABLE_CRYPTO_AUTH if(authstatus->picked == CURLAUTH_DIGEST) { - auth="Digest"; + auth = "Digest"; result = Curl_output_digest(conn, proxy, (const unsigned char *)request, @@ -629,11 +628,12 @@ output_auth_headers(struct connectdata *conn, !Curl_checkProxyheaders(conn, "Proxy-authorization:")) || (!proxy && conn->bits.user_passwd && !Curl_checkheaders(conn, "Authorization:"))) { - auth="Basic"; + auth = "Basic"; result = http_output_basic(conn, proxy); if(result) return result; } + /* NOTE: this function should set 'done' TRUE, as the other auth functions work that way */ authstatus->done = TRUE; @@ -641,9 +641,9 @@ output_auth_headers(struct connectdata *conn, if(auth) { infof(data, "%s auth using %s with user '%s'\n", - proxy?"Proxy":"Server", auth, - proxy?(conn->proxyuser?conn->proxyuser:""): - (conn->user?conn->user:"")); + proxy ? "Proxy" : "Server", auth, + proxy ? (conn->proxyuser ? conn->proxyuser : "") : + (conn->user ? conn->user : "")); authstatus->multi = (!authstatus->done) ? TRUE : FALSE; } else @@ -674,7 +674,7 @@ Curl_http_output_auth(struct connectdata *conn, up the proxy tunnel */ { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct auth *authhost; struct auth *authproxy; @@ -735,7 +735,6 @@ Curl_http_output_auth(struct connectdata *conn, return result; } - /* * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate: * headers. They are dealt with both in the transfer.c main loop and in the @@ -748,7 +747,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, /* * This resource requires authentication */ - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; #ifdef USE_SPNEGO struct negotiatedata *negdata = proxy? @@ -780,7 +779,6 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, * request is sent, and then it is again set _after_ all response 401/407 * headers have been received but then only to a single preferred method * (bit). - * */ while(*auth) { @@ -893,6 +891,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, while(*auth && ISSPACE(*auth)) auth++; } + return CURLE_OK; } @@ -908,7 +907,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, */ static int http_should_fail(struct connectdata *conn) { - struct SessionHandle *data; + struct Curl_easy *data; int httpcode; DEBUGASSERT(conn); @@ -934,8 +933,7 @@ static int http_should_fail(struct connectdata *conn) ** Any code >= 400 that's not 401 or 407 is always ** a terminal error */ - if((httpcode != 401) && - (httpcode != 407)) + if((httpcode != 401) && (httpcode != 407)) return 1; /* @@ -986,7 +984,7 @@ static size_t readmoredata(char *buffer, struct HTTP *http = conn->data->req.protop; size_t fullsize = size * nitems; - if(0 == http->postsize) + if(!http->postsize) /* nothing to return */ return 0; @@ -1001,8 +999,8 @@ static size_t readmoredata(char *buffer, /* move backup data into focus and continue on that */ http->postdata = http->backup.postdata; http->postsize = http->backup.postsize; - conn->data->set.fread_func = http->backup.fread_func; - conn->data->set.in = http->backup.fread_in; + conn->data->state.fread_func = http->backup.fread_func; + conn->data->state.in = http->backup.fread_in; http->sending++; /* move one step up */ @@ -1092,15 +1090,14 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, return result; } - - if(conn->handler->flags & PROTOPT_SSL) { + if((conn->handler->flags & PROTOPT_SSL) && conn->httpversion != 20) { /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk when we speak HTTPS, as if only a fraction of it is sent now, this data needs to fit into the normal read-callback buffer later on and that buffer is using this size. */ - sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:size; + sendsize = (size > CURL_MAX_WRITE_SIZE) ? CURL_MAX_WRITE_SIZE : size; /* OpenSSL is very picky and we must send the SAME buffer pointer to the library when we attempt to re-send this buffer. Sending the same data @@ -1123,7 +1120,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, * only send away a part). */ /* how much of the header that was sent */ - size_t headlen = (size_t)amount>headersize?headersize:(size_t)amount; + size_t headlen = (size_t)amount>headersize ? headersize : (size_t)amount; size_t bodylen = amount - headlen; if(conn->data->set.verbose) { @@ -1136,10 +1133,6 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, ptr+headlen, bodylen, conn); } } - if(bodylen) - /* since we sent a piece of the body here, up the byte counter for it - accordingly */ - http->writebytecount += bodylen; /* 'amount' can never be a very large value here so typecasting it so a signed 31 bit value should not cause problems even if ssize_t is @@ -1147,6 +1140,10 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, *bytes_written += (long)amount; if(http) { + /* if we sent a piece of the body here, up the byte counter for it + accordingly */ + http->writebytecount += bodylen; + if((size_t)amount != size) { /* The whole request could not be sent in one system call. We must queue it up and send it later when we get the chance. We must not @@ -1157,14 +1154,14 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, ptr = in->buffer + amount; /* backup the currently set pointers */ - http->backup.fread_func = conn->data->set.fread_func; - http->backup.fread_in = conn->data->set.in; + http->backup.fread_func = conn->data->state.fread_func; + http->backup.fread_in = conn->data->state.in; http->backup.postdata = http->postdata; http->backup.postsize = http->postsize; /* set the new pointers for the request-sending */ - conn->data->set.fread_func = (curl_read_callback)readmoredata; - conn->data->set.in = (void *)conn; + conn->data->state.fread_func = (curl_read_callback)readmoredata; + conn->data->state.in = (void *)conn; http->postdata = ptr; http->postsize = (curl_off_t)size; @@ -1242,11 +1239,11 @@ CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size) buffer size that doubles the required size. If this new size would wrap size_t, then just use the largest possible one */ - if((size > (size_t)-1/2) || (in->size_used > (size_t)-1/2) || - (~(size*2) < (in->size_used*2))) + if((size > (size_t)-1 / 2) || (in->size_used > (size_t)-1 / 2) || + (~(size * 2) < (in->size_used * 2))) new_size = (size_t)-1; else - new_size = (in->size_used+size)*2; + new_size = (in->size_used+size) * 2; if(in->buffer) /* we have a buffer, enlarge the existing one */ @@ -1394,7 +1391,8 @@ static CURLcode https_connecting(struct connectdata *conn, bool *done) #endif #if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ - defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS) + defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS) || \ + defined(USE_MBEDTLS) /* This function is for OpenSSL, GnuTLS, darwinssl, schannel and polarssl only. It should be made to query the generic SSL layer instead. */ static int https_getsock(struct connectdata *conn, @@ -1418,6 +1416,7 @@ static int https_getsock(struct connectdata *conn, return GETSOCK_READSOCK(0); } } + return CURLE_OK; } #else @@ -1435,14 +1434,14 @@ static int https_getsock(struct connectdata *conn, #endif /* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL */ /* - * Curl_http_done() gets called from Curl_done() after a single HTTP request - * has been performed. + * Curl_http_done() gets called after a single HTTP request has been + * performed. */ CURLcode Curl_http_done(struct connectdata *conn, CURLcode status, bool premature) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct HTTP *http = data->req.protop; #ifdef USE_NGHTTP2 struct http_conn *httpc = &conn->proto.httpc; @@ -1455,8 +1454,10 @@ CURLcode Curl_http_done(struct connectdata *conn, data->state.negotiate.state == GSS_AUTHSENT) { /* add forbid re-use if http-code != 401/407 as a WA only needed for * 401/407 that signal auth failure (empty) otherwise state will be RECV - * with current code */ - if((data->req.httpcode != 401) && (data->req.httpcode != 407)) + * with current code. + * Do not close CONNECT_ONLY connections. */ + if((data->req.httpcode != 401) && (data->req.httpcode != 407) && + !data->set.connect_only) connclose(conn, "Negotiate transfer completed"); Curl_cleanup_negotiate(data); } @@ -1466,7 +1467,7 @@ CURLcode Curl_http_done(struct connectdata *conn, conn->seek_func = data->set.seek_func; /* restore */ conn->seek_client = data->set.seek_client; /* restore */ - if(http == NULL) + if(!http) return CURLE_OK; if(http->send_buffer) { @@ -1479,11 +1480,16 @@ CURLcode Curl_http_done(struct connectdata *conn, DEBUGF(infof(data, "free header_recvbuf!!\n")); Curl_add_buffer_free(http->header_recvbuf); http->header_recvbuf = NULL; /* clear the pointer */ - for(; http->push_headers_used > 0; --http->push_headers_used) { - free(http->push_headers[http->push_headers_used - 1]); + Curl_add_buffer_free(http->trailer_recvbuf); + http->trailer_recvbuf = NULL; /* clear the pointer */ + if(http->push_headers) { + /* if they weren't used and then freed before */ + for(; http->push_headers_used > 0; --http->push_headers_used) { + free(http->push_headers[http->push_headers_used - 1]); + } + free(http->push_headers); + http->push_headers = NULL; } - free(http->push_headers); - http->push_headers = NULL; } if(http->stream_id) { nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0); @@ -1511,9 +1517,9 @@ CURLcode Curl_http_done(struct connectdata *conn, entire operation is complete */ !conn->bits.retry && !data->set.connect_only && - ((http->readbytecount + - data->req.headerbytecount - - data->req.deductheadercount)) <= 0) { + (http->readbytecount + + data->req.headerbytecount - + data->req.deductheadercount) <= 0) { /* If this connection isn't simply closed to be retried, AND nothing was read from the HTTP server (that counts), this can't be right so we return an error here */ @@ -1524,7 +1530,6 @@ CURLcode Curl_http_done(struct connectdata *conn, return CURLE_OK; } - /* * Determine if we should use HTTP 1.1 (OR BETTER) for this request. Reasons * to avoid it include: @@ -1534,18 +1539,20 @@ CURLcode Curl_http_done(struct connectdata *conn, * - if any server previously contacted to handle this request only supports * 1.0. */ -static bool use_http_1_1plus(const struct SessionHandle *data, +static bool use_http_1_1plus(const struct Curl_easy *data, const struct connectdata *conn) { - return ((data->set.httpversion >= CURL_HTTP_VERSION_1_1) || - ((data->set.httpversion != CURL_HTTP_VERSION_1_0) && - ((conn->httpversion == 11) || - ((conn->httpversion != 10) && - (data->state.httpversion != 10))))) ? TRUE : FALSE; + if((data->state.httpversion == 10) || (conn->httpversion == 10)) + return FALSE; + if((data->set.httpversion == CURL_HTTP_VERSION_1_0) && + (conn->httpversion <= 10)) + return FALSE; + return ((data->set.httpversion == CURL_HTTP_VERSION_NONE) || + (data->set.httpversion >= CURL_HTTP_VERSION_1_1)); } /* check and possibly add an Expect: header */ -static CURLcode expect100(struct SessionHandle *data, +static CURLcode expect100(struct Curl_easy *data, struct connectdata *conn, Curl_send_buffer *req_buffer) { @@ -1570,6 +1577,7 @@ static CURLcode expect100(struct SessionHandle *data, data->state.expect100header = TRUE; } } + return result; } @@ -1587,7 +1595,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, struct curl_slist *h[2]; struct curl_slist *headers; int numlists=1; /* by default */ - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int i; enum proxy_use proxy; @@ -1688,16 +1696,23 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, headers = headers->next; } } + return CURLE_OK; } -CURLcode Curl_add_timecondition(struct SessionHandle *data, +CURLcode Curl_add_timecondition(struct Curl_easy *data, Curl_send_buffer *req_buffer) { const struct tm *tm; char *buf = data->state.buffer; struct tm keeptime; - CURLcode result = Curl_gmtime(data->set.timevalue, &keeptime); + CURLcode result; + + if(data->set.timecondition == CURL_TIMECOND_NONE) + /* no condition was asked for */ + return CURLE_OK; + + result = Curl_gmtime(data->set.timevalue, &keeptime); if(result) { failf(data, "Invalid TIMEVALUE"); return result; @@ -1723,8 +1738,9 @@ CURLcode Curl_add_timecondition(struct SessionHandle *data, tm->tm_sec); switch(data->set.timecondition) { - case CURL_TIMECOND_IFMODSINCE: default: + break; + case CURL_TIMECOND_IFMODSINCE: result = Curl_add_bufferf(req_buffer, "If-Modified-Since: %s\r\n", buf); break; @@ -1742,13 +1758,13 @@ CURLcode Curl_add_timecondition(struct SessionHandle *data, } /* - * Curl_http() gets called from the generic Curl_do() function when a HTTP + * Curl_http() gets called from the generic multi_do() function when a HTTP * request is to be performed. This creates and sends a properly constructed * HTTP request. */ CURLcode Curl_http(struct connectdata *conn, bool *done) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; struct HTTP *http; const char *ppath = data->state.path; @@ -1776,15 +1792,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(conn->httpversion < 20) { /* unless the connection is re-used and already http2 */ switch(conn->negnpn) { - case CURL_HTTP_VERSION_2_0: + case CURL_HTTP_VERSION_2: conn->httpversion = 20; /* we know we're on HTTP/2 now */ - result = Curl_http2_init(conn); - if(result) - return result; - - result = Curl_http2_setup(conn); - if(result) - return result; result = Curl_http2_switched(conn, NULL, 0); if(result) @@ -1794,7 +1803,18 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* continue with HTTP/1.1 when explicitly requested */ break; default: - /* and as fallback */ + /* Check if user wants to use HTTP/2 with clear TCP*/ +#ifdef USE_NGHTTP2 + if(conn->data->set.httpversion == + CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) { + DEBUGF(infof(data, "HTTP/2 over clean TCP\n")); + conn->httpversion = 20; + + result = Curl_http2_switched(conn, NULL, 0); + if(result) + return result; + } +#endif break; } } @@ -1814,6 +1834,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) data->state.first_host = strdup(conn->host.name); if(!data->state.first_host) return CURLE_OUT_OF_MEMORY; + + data->state.first_remote_port = conn->remote_port; } http->writebytecount = http->readbytecount = 0; @@ -1895,6 +1917,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(!conn->allocptr.accept_encoding) return CURLE_OUT_OF_MEMORY; } + else { + Curl_safefree(conn->allocptr.accept_encoding); + conn->allocptr.accept_encoding = NULL; + } #ifdef HAVE_LIBZ /* we only consider transfer-encoding magic if libz support is built-in */ @@ -2130,7 +2156,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) * file size before we continue this venture in the dark lands of HTTP. *********************************************************************/ - if(data->state.resume_from < 0 ) { + if(data->state.resume_from < 0) { /* * This is meant to get the size of the present remote-file by itself. * We don't support this now. Bail out! @@ -2162,8 +2188,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) BUFSIZE : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread = - data->set.fread_func(data->state.buffer, 1, readthisamountnow, - data->set.in); + data->state.fread_func(data->state.buffer, 1, readthisamountnow, + data->state.in); passed += actuallyread; if((actuallyread == 0) || (actuallyread > readthisamountnow)) { @@ -2279,7 +2305,6 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) "%s" /* TE: */ "%s" /* accept-encoding */ "%s" /* referer */ - "%s" /* Proxy-Connection */ "%s",/* transfer-encoding */ ftp_typecode, @@ -2302,10 +2327,6 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->allocptr.accept_encoding:"", (data->change.referer && conn->allocptr.ref)? conn->allocptr.ref:"" /* Referer: */, - (conn->bits.httpproxy && - !conn->bits.tunnel_proxy && - !Curl_checkProxyheaders(conn, "Proxy-Connection:"))? - "Proxy-Connection: Keep-Alive\r\n":"", te ); @@ -2329,7 +2350,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(!(conn->handler->flags&PROTOPT_SSL) && conn->httpversion != 20 && - (data->set.httpversion == CURL_HTTP_VERSION_2_0)) { + (data->set.httpversion == CURL_HTTP_VERSION_2)) { /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done over SSL */ result = Curl_http2_request_upgrade(req_buffer, conn); @@ -2390,11 +2411,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } #endif - if(data->set.timecondition) { - result = Curl_add_timecondition(data, req_buffer); - if(result) - return result; - } + result = Curl_add_timecondition(data, req_buffer); + if(result) + return result; result = Curl_add_custom_headers(conn, FALSE, req_buffer); if(result) @@ -2437,11 +2456,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) on. The data->set.fread_func pointer itself will be changed for the multipart case to the function that returns a multipart formatted stream. */ - http->form.fread_func = data->set.fread_func; + http->form.fread_func = data->state.fread_func; /* Set the read function to read from the generated form data */ - data->set.fread_func = (curl_read_callback)Curl_FormReader; - data->set.in = &http->form; + data->state.fread_func = (curl_read_callback)Curl_FormReader; + data->state.in = &http->form; http->sending = HTTPSEND_BODY; @@ -2659,8 +2678,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) http->sending = HTTPSEND_BODY; - data->set.fread_func = (curl_read_callback)readmoredata; - data->set.in = (void *)conn; + data->state.fread_func = (curl_read_callback)readmoredata; + data->state.in = (void *)conn; /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, http->postsize); @@ -2758,7 +2777,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) * Returns TRUE if member of the list matches prefix of string */ static bool -checkhttpprefix(struct SessionHandle *data, +checkhttpprefix(struct Curl_easy *data, const char *s) { struct curl_slist *head = data->set.http200aliases; @@ -2797,7 +2816,7 @@ checkhttpprefix(struct SessionHandle *data, #ifndef CURL_DISABLE_RTSP static bool -checkrtspprefix(struct SessionHandle *data, +checkrtspprefix(struct Curl_easy *data, const char *s) { @@ -2825,7 +2844,7 @@ checkrtspprefix(struct SessionHandle *data, #endif /* CURL_DISABLE_RTSP */ static bool -checkprotoprefix(struct SessionHandle *data, struct connectdata *conn, +checkprotoprefix(struct Curl_easy *data, struct connectdata *conn, const char *s) { #ifndef CURL_DISABLE_RTSP @@ -2843,7 +2862,7 @@ checkprotoprefix(struct SessionHandle *data, struct connectdata *conn, * header. We make sure that the full string fit in the allocated header * buffer, or else we enlarge it. */ -static CURLcode header_append(struct SessionHandle *data, +static CURLcode header_append(struct Curl_easy *data, struct SingleRequest *k, size_t length) { @@ -2881,7 +2900,7 @@ static CURLcode header_append(struct SessionHandle *data, return CURLE_OK; } -static void print_http_error(struct SessionHandle *data) +static void print_http_error(struct Curl_easy *data) { struct SingleRequest *k = &data->req; char *beg = k->p; @@ -2921,7 +2940,7 @@ static void print_http_error(struct SessionHandle *data) /* * Read any HTTP header lines from the server and pass them to the client app. */ -CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, +CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *stop_reading) @@ -3035,7 +3054,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, switch(k->httpcode) { case 100: /* if we did wait for this do enable write now! */ - if(k->exp100) { + if(k->exp100 > EXP100_SEND_DATA) { k->exp100 = EXP100_SEND_DATA; k->keepon |= KEEP_SEND; } @@ -3119,52 +3138,50 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, data->req.deductheadercount = (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0; - if(!*stop_reading) { - /* Curl_http_auth_act() checks what authentication methods - * that are available and decides which one (if any) to - * use. It will set 'newurl' if an auth method was picked. */ - result = Curl_http_auth_act(conn); + /* Curl_http_auth_act() checks what authentication methods + * that are available and decides which one (if any) to + * use. It will set 'newurl' if an auth method was picked. */ + result = Curl_http_auth_act(conn); - if(result) - return result; + if(result) + return result; - if(k->httpcode >= 300) { - if((!conn->bits.authneg) && !conn->bits.close && - !conn->bits.rewindaftersend) { - /* - * General treatment of errors when about to send data. Including : - * "417 Expectation Failed", while waiting for 100-continue. - * - * The check for close above is done simply because of something - * else has already deemed the connection to get closed then - * something else should've considered the big picture and we - * avoid this check. - * - * rewindaftersend indicates that something has told libcurl to - * continue sending even if it gets discarded + if(k->httpcode >= 300) { + if((!conn->bits.authneg) && !conn->bits.close && + !conn->bits.rewindaftersend) { + /* + * General treatment of errors when about to send data. Including : + * "417 Expectation Failed", while waiting for 100-continue. + * + * The check for close above is done simply because of something + * else has already deemed the connection to get closed then + * something else should've considered the big picture and we + * avoid this check. + * + * rewindaftersend indicates that something has told libcurl to + * continue sending even if it gets discarded + */ + + switch(data->set.httpreq) { + case HTTPREQ_PUT: + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + /* We got an error response. If this happened before the whole + * request body has been sent we stop sending and mark the + * connection for closure after we've read the entire response. */ - - switch(data->set.httpreq) { - case HTTPREQ_PUT: - case HTTPREQ_POST: - case HTTPREQ_POST_FORM: - /* We got an error response. If this happened before the whole - * request body has been sent we stop sending and mark the - * connection for closure after we've read the entire response. - */ - if(!k->upload_done) { - infof(data, "HTTP error before end of send, stop sending\n"); - connclose(conn, "Stop sending data before everything sent"); - k->upload_done = TRUE; - k->keepon &= ~KEEP_SEND; /* don't send */ - if(data->state.expect100header) - k->exp100 = EXP100_FAILED; - } - break; - - default: /* default label present to avoid compiler warnings */ - break; + if(!k->upload_done) { + infof(data, "HTTP error before end of send, stop sending\n"); + connclose(conn, "Stop sending data before everything sent"); + k->upload_done = TRUE; + k->keepon &= ~KEEP_SEND; /* don't send */ + if(data->state.expect100header) + k->exp100 = EXP100_FAILED; } + break; + + default: /* default label present to avoid compiler warnings */ + break; } } @@ -3185,6 +3202,16 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, */ if(data->set.opt_no_body) *stop_reading = TRUE; +#ifndef CURL_DISABLE_RTSP + else if((conn->handler->protocol & CURLPROTO_RTSP) && + (data->set.rtspreq == RTSPREQ_DESCRIBE) && + (k->size <= -1)) + /* Respect section 4.4 of rfc2326: If the Content-Length header is + absent, a length 0 must be assumed. It will prevent libcurl from + hanging on DESCRIBE request that got refused for whatever + reason */ + *stop_reading = TRUE; +#endif else { /* If we know the expected size of this document, we set the maximum download size to the size of the expected @@ -3279,6 +3306,13 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, &httpversion_major, &conn->httpversion, &k->httpcode); + + if(nc == 1 && httpversion_major == 2 && + 1 == sscanf(HEADER1, " HTTP/2 %d", &k->httpcode)) { + conn->httpversion = 0; + nc = 3; + } + if(nc==3) { conn->httpversion += 10 * httpversion_major; @@ -3576,8 +3610,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, } else if(checkprefix("Content-Encoding:", k->p) && - (data->set.str[STRING_ENCODING] || - conn->httpversion == 20)) { + data->set.str[STRING_ENCODING]) { /* * Process Content-Encoding. Look for the values: identity, * gzip, deflate, compress, x-gzip and x-compress. x-gzip and @@ -3726,7 +3759,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, k->hbufp = data->state.headerbuff; k->hbuflen = 0; } - while(!*stop_reading && *k->str); /* header line within buffer */ + while(*k->str); /* header line within buffer */ /* We might have reached the end of the header part here, but there might be a non-header part left in the end of the read diff --git a/lib/http.h b/lib/http.h index fe4f39b..6529005 100644 --- a/lib/http.h +++ b/lib/http.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -69,7 +69,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, size_t included_body_bytes, int socketindex); -CURLcode Curl_add_timecondition(struct SessionHandle *data, +CURLcode Curl_add_timecondition(struct Curl_easy *data, Curl_send_buffer *buf); CURLcode Curl_add_custom_headers(struct connectdata *conn, bool is_connect, @@ -87,7 +87,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap, ssize_t length, ssize_t *wrote); /* These functions are in http.c */ -void Curl_http_auth_stage(struct SessionHandle *data, int stage); +void Curl_http_auth_stage(struct Curl_easy *data, int stage); CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, const char *auth); CURLcode Curl_http_auth_act(struct connectdata *conn); @@ -163,6 +163,7 @@ struct HTTP { Curl_send_buffer *header_recvbuf; size_t nread_header_recvbuf; /* number of bytes in header_recvbuf fed into upper layer */ + Curl_send_buffer *trailer_recvbuf; int status_code; /* HTTP status code */ const uint8_t *pausedata; /* pointer to data received in on_data_chunk */ size_t pauselen; /* the number of bytes left in data */ @@ -213,15 +214,16 @@ struct http_conn { them for both cases. */ int32_t pause_stream_id; /* stream ID which paused nghttp2_session_mem_recv */ + size_t drain_total; /* sum of all stream's UrlState.drain */ - /* this is a hash of all individual streams (SessionHandle structs) */ + /* this is a hash of all individual streams (Curl_easy structs) */ struct h2settings settings; #else int unused; /* prevent a compiler warning */ #endif }; -CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, +CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *stop_reading); diff --git a/lib/http2.c b/lib/http2.c index 0024add..efc082d 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -23,7 +23,6 @@ #include "curl_setup.h" #ifdef USE_NGHTTP2 -#include "curl_printf.h" #include #include "urldata.h" #include "http2.h" @@ -34,17 +33,50 @@ #include "multiif.h" #include "conncache.h" #include "url.h" +#include "connect.h" +#include "strtoofft.h" -/* The last #include files should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #define MIN(x,y) ((x)<(y)?(x):(y)) -#if (NGHTTP2_VERSION_NUM < 0x000600) +#if (NGHTTP2_VERSION_NUM < 0x010000) #error too old nghttp2 version, upgrade! #endif +#if (NGHTTP2_VERSION_NUM > 0x010800) +#define NGHTTP2_HAS_HTTP2_STRERROR 1 +#endif + +#if (NGHTTP2_VERSION_NUM >= 0x010900) +/* nghttp2_session_callbacks_set_error_callback is present in nghttp2 1.9.0 or + later */ +#define NGHTTP2_HAS_ERROR_CALLBACK 1 +#else +#define nghttp2_session_callbacks_set_error_callback(x,y) +#endif + +/* + * Curl_http2_init_state() is called when the easy handle is created and + * allows for HTTP/2 specific init of state. + */ +void Curl_http2_init_state(struct UrlState *state) +{ + state->stream_weight = NGHTTP2_DEFAULT_WEIGHT; +} + +/* + * Curl_http2_init_userset() is called when the easy handle is created and + * allows for HTTP/2 specific user-set fields. + */ +void Curl_http2_init_userset(struct UserDefined *set) +{ + set->stream_weight = NGHTTP2_DEFAULT_WEIGHT; +} + static int http2_perform_getsock(const struct connectdata *conn, curl_socket_t *sock, /* points to numsocks @@ -92,6 +124,8 @@ static CURLcode http2_disconnect(struct connectdata *conn, if(http) { Curl_add_buffer_free(http->header_recvbuf); http->header_recvbuf = NULL; /* clear the pointer */ + Curl_add_buffer_free(http->trailer_recvbuf); + http->trailer_recvbuf = NULL; /* clear the pointer */ for(; http->push_headers_used > 0; --http->push_headers_used) { free(http->push_headers[http->push_headers_used - 1]); } @@ -105,7 +139,7 @@ static CURLcode http2_disconnect(struct connectdata *conn, } /* called from Curl_http_setup_conn */ -void Curl_http2_setup_req(struct SessionHandle *data) +void Curl_http2_setup_req(struct Curl_easy *data) { struct HTTP *http = data->req.protop; @@ -134,7 +168,7 @@ void Curl_http2_setup_conn(struct connectdata *conn) * HTTP to HTTP2. */ const struct Curl_handler Curl_handler_http2 = { - "HTTP2", /* scheme */ + "HTTP", /* scheme */ ZERO_NULL, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ @@ -154,7 +188,7 @@ const struct Curl_handler Curl_handler_http2 = { }; const struct Curl_handler Curl_handler_http2_ssl = { - "HTTP2", /* scheme */ + "HTTPS", /* scheme */ ZERO_NULL, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ @@ -183,6 +217,34 @@ int Curl_http2_ver(char *p, size_t len) return snprintf(p, len, " nghttp2/%s", h2->version_str); } +/* HTTP/2 error code to name based on the Error Code Registry. +https://tools.ietf.org/html/rfc7540#page-77 +nghttp2_error_code enums are identical. +*/ +const char *Curl_http2_strerror(uint32_t err) { +#ifndef NGHTTP2_HAS_HTTP2_STRERROR + const char *str[] = { + "NO_ERROR", /* 0x0 */ + "PROTOCOL_ERROR", /* 0x1 */ + "INTERNAL_ERROR", /* 0x2 */ + "FLOW_CONTROL_ERROR", /* 0x3 */ + "SETTINGS_TIMEOUT", /* 0x4 */ + "STREAM_CLOSED", /* 0x5 */ + "FRAME_SIZE_ERROR", /* 0x6 */ + "REFUSED_STREAM", /* 0x7 */ + "CANCEL", /* 0x8 */ + "COMPRESSION_ERROR", /* 0x9 */ + "CONNECT_ERROR", /* 0xA */ + "ENHANCE_YOUR_CALM", /* 0xB */ + "INADEQUATE_SECURITY", /* 0xC */ + "HTTP_1_1_REQUIRED" /* 0xD */ + }; + return (err < sizeof str / sizeof str[0]) ? str[err] : "unknown"; +#else + return nghttp2_http2_strerror(err); +#endif +} + /* * The implementation of nghttp2_send_callback type. Here we write |data| with * size |length| to the network and return the number of bytes actually @@ -222,7 +284,7 @@ static ssize_t send_callback(nghttp2_session *h2, /* We pass a pointer to this struct in the push callback, but the contents of the struct are hidden from the user. */ struct curl_pushheaders { - struct SessionHandle *data; + struct Curl_easy *data; const nghttp2_push_promise *frame; }; @@ -263,7 +325,7 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) size_t i; for(i=0; ipush_headers_used; i++) { if(!strncmp(header, stream->push_headers[i], len)) { - /* sub-match, make sure that it us followed by a colon */ + /* sub-match, make sure that it is followed by a colon */ if(stream->push_headers[i][len] != ':') continue; return &stream->push_headers[i][len+1]; @@ -273,9 +335,9 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) return NULL; } -static CURL *duphandle(struct SessionHandle *data) +static struct Curl_easy *duphandle(struct Curl_easy *data) { - struct SessionHandle *second = curl_easy_duphandle(data); + struct Curl_easy *second = curl_easy_duphandle(data); if(second) { /* setup the request struct */ struct HTTP *http = calloc(1, sizeof(struct HTTP)); @@ -291,15 +353,17 @@ static CURL *duphandle(struct SessionHandle *data) (void)Curl_close(second); second = NULL; } - else + else { Curl_http2_setup_req(second); + second->state.stream_weight = data->state.stream_weight; + } } } return second; } -static int push_promise(struct SessionHandle *data, +static int push_promise(struct Curl_easy *data, struct connectdata *conn, const nghttp2_push_promise *frame) { @@ -308,12 +372,13 @@ static int push_promise(struct SessionHandle *data, frame->promised_stream_id)); if(data->multi->push_cb) { struct HTTP *stream; + struct HTTP *newstream; struct curl_pushheaders heads; CURLMcode rc; struct http_conn *httpc; size_t i; /* clone the parent */ - CURL *newhandle = duphandle(data); + struct Curl_easy *newhandle = duphandle(data); if(!newhandle) { infof(data, "failed to duplicate handle\n"); rv = 1; /* FAIL HARD */ @@ -348,6 +413,11 @@ static int push_promise(struct SessionHandle *data, goto fail; } + newstream = newhandle->req.protop; + newstream->stream_id = frame->promised_stream_id; + newhandle->req.maxdownload = -1; + newhandle->req.size = -1; + /* approved, add to the multi handle and immediately switch to PERFORM state with the given connection !*/ rc = Curl_multi_add_perform(data->multi, newhandle, conn); @@ -373,29 +443,46 @@ static int push_promise(struct SessionHandle *data, static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { - struct connectdata *conn = NULL; - struct http_conn *httpc = NULL; - struct SessionHandle *data_s = NULL; + struct connectdata *conn = (struct connectdata *)userp; + struct http_conn *httpc = &conn->proto.httpc; + struct Curl_easy *data_s = NULL; struct HTTP *stream = NULL; static int lastStream = -1; int rv; size_t left, ncopy; int32_t stream_id = frame->hd.stream_id; - (void)userp; - if(!stream_id) { /* stream ID zero is for connection-oriented stuff */ + if(frame->hd.type == NGHTTP2_SETTINGS) { + uint32_t max_conn = httpc->settings.max_concurrent_streams; + DEBUGF(infof(conn->data, "Got SETTINGS\n")); + httpc->settings.max_concurrent_streams = + nghttp2_session_get_remote_settings( + session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS); + httpc->settings.enable_push = + nghttp2_session_get_remote_settings( + session, NGHTTP2_SETTINGS_ENABLE_PUSH); + DEBUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n", + httpc->settings.max_concurrent_streams)); + DEBUGF(infof(conn->data, "ENABLE_PUSH == %s\n", + httpc->settings.enable_push?"TRUE":"false")); + if(max_conn != httpc->settings.max_concurrent_streams) { + /* only signal change if the value actually changed */ + infof(conn->data, + "Connection state changed (MAX_CONCURRENT_STREAMS updated)!\n"); + Curl_multi_connchanged(conn->data->multi); + } + } return 0; } - data_s = nghttp2_session_get_stream_user_data(session, - frame->hd.stream_id); - if(lastStream != frame->hd.stream_id) { - lastStream = frame->hd.stream_id; + data_s = nghttp2_session_get_stream_user_data(session, stream_id); + if(lastStream != stream_id) { + lastStream = stream_id; } if(!data_s) { DEBUGF(infof(conn->data, - "No SessionHandle associated with stream: %x\n", + "No Curl_easy associated with stream: %x\n", stream_id)); return 0; } @@ -407,10 +494,6 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, DEBUGF(infof(data_s, "on_frame_recv() header %x stream %x\n", frame->hd.type, stream_id)); - conn = data_s->easy_conn; - assert(conn); - assert(conn->data == data_s); - httpc = &conn->proto.httpc; switch(frame->hd.type) { case NGHTTP2_DATA: /* If body started on this stream, then receiving DATA is illegal. */ @@ -424,13 +507,9 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, } break; case NGHTTP2_HEADERS: - if(frame->headers.cat == NGHTTP2_HCAT_REQUEST) - break; - if(stream->bodystarted) { /* Only valid HEADERS after body started is trailer HEADERS. We - ignores trailer HEADERS for now. nghttp2 guarantees that it - has END_STREAM flag set. */ + buffer them in on_header callback. */ break; } @@ -461,7 +540,15 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, stream->memlen += ncopy; data_s->state.drain++; - Curl_expire(data_s, 1); + httpc->drain_total++; + { + /* get the pointer from userp again since it was re-assigned above */ + struct connectdata *conn_s = (struct connectdata *)userp; + + /* if we receive data for another handle, wake that up */ + if(conn_s->data != data_s) + Curl_expire(data_s, 1); + } break; case NGHTTP2_PUSH_PROMISE: rv = push_promise(data_s, conn, &frame->push_promise); @@ -474,28 +561,6 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, } } break; - case NGHTTP2_SETTINGS: - { - uint32_t max_conn = httpc->settings.max_concurrent_streams; - DEBUGF(infof(conn->data, "Got SETTINGS for stream %u!\n", stream_id)); - httpc->settings.max_concurrent_streams = - nghttp2_session_get_remote_settings( - session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS); - httpc->settings.enable_push = - nghttp2_session_get_remote_settings( - session, NGHTTP2_SETTINGS_ENABLE_PUSH); - DEBUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n", - httpc->settings.max_concurrent_streams)); - DEBUGF(infof(conn->data, "ENABLE_PUSH == %s\n", - httpc->settings.enable_push?"TRUE":"false")); - if(max_conn != httpc->settings.max_concurrent_streams) { - /* only signal change if the value actually changed */ - infof(conn->data, - "Connection state changed (MAX_CONCURRENT_STREAMS updated)!\n"); - Curl_multi_connchanged(conn->data->multi); - } - } - break; default: DEBUGF(infof(conn->data, "Got frame type %x for stream %u!\n", frame->hd.type, stream_id)); @@ -508,7 +573,7 @@ static int on_invalid_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, int lib_error_code, void *userp) { - struct SessionHandle *data_s = NULL; + struct Curl_easy *data_s = NULL; (void)userp; data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); @@ -525,12 +590,12 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, const uint8_t *data, size_t len, void *userp) { struct HTTP *stream; - struct SessionHandle *data_s; + struct Curl_easy *data_s; size_t nread; + struct connectdata *conn = (struct connectdata *)userp; (void)session; (void)flags; (void)data; - (void)userp; DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ @@ -552,8 +617,12 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, stream->memlen += nread; data_s->state.drain++; - Curl_expire(data_s, 1); /* TODO: fix so that this can be set to 0 for - immediately? */ + conn->proto.httpc.drain_total++; + + /* if we receive data for another handle, wake that up */ + if(conn->data != data_s) + Curl_expire(data_s, 1); /* TODO: fix so that this can be set to 0 for + immediately? */ DEBUGF(infof(data_s, "%zu data received for stream %u " "(%zu left in buffer %p, total %zu)\n", @@ -568,8 +637,18 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, ", stream %u\n", len - nread, stream_id)); data_s->easy_conn->proto.httpc.pause_stream_id = stream_id; + return NGHTTP2_ERR_PAUSE; } + + /* pause execution of nghttp2 if we received data for another handle + in order to process them first. */ + if(conn->data != data_s) { + data_s->easy_conn->proto.httpc.pause_stream_id = stream_id; + + return NGHTTP2_ERR_PAUSE; + } + return 0; } @@ -577,7 +656,7 @@ static int before_frame_send(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { - struct SessionHandle *data_s; + struct Curl_easy *data_s; (void)userp; data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); @@ -591,7 +670,7 @@ static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { - struct SessionHandle *data_s; + struct Curl_easy *data_s; (void)userp; data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); @@ -605,7 +684,7 @@ static int on_frame_not_send(nghttp2_session *session, const nghttp2_frame *frame, int lib_error_code, void *userp) { - struct SessionHandle *data_s; + struct Curl_easy *data_s; (void)userp; data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); @@ -619,11 +698,11 @@ static int on_frame_not_send(nghttp2_session *session, static int on_stream_close(nghttp2_session *session, int32_t stream_id, uint32_t error_code, void *userp) { - struct SessionHandle *data_s; + struct Curl_easy *data_s; struct HTTP *stream; + struct connectdata *conn = (struct connectdata *)userp; (void)session; (void)stream_id; - (void)userp; if(stream_id) { /* get the stream from the hash based on Stream ID, stream ID zero is for @@ -634,14 +713,16 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id, decided to reject stream (e.g., PUSH_PROMISE). */ return 0; } - DEBUGF(infof(data_s, "on_stream_close(), error_code = %d, stream %u\n", - error_code, stream_id)); + DEBUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n", + Curl_http2_strerror(error_code), error_code, stream_id)); stream = data_s->req.protop; if(!stream) return NGHTTP2_ERR_CALLBACK_FAILURE; stream->error_code = error_code; stream->closed = TRUE; + data_s->state.drain++; + conn->proto.httpc.drain_total++; /* remove the entry from the hash as the stream is now gone */ nghttp2_session_set_stream_user_data(session, stream_id, 0); @@ -653,13 +734,36 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id, static int on_begin_headers(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { - struct SessionHandle *data_s = NULL; + struct HTTP *stream; + struct Curl_easy *data_s = NULL; (void)userp; data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); - if(data_s) { - DEBUGF(infof(data_s, "on_begin_headers() was called\n")); + if(!data_s) { + return 0; + } + + DEBUGF(infof(data_s, "on_begin_headers() was called\n")); + + if(frame->hd.type != NGHTTP2_HEADERS) { + return 0; + } + + stream = data_s->req.protop; + if(!stream || !stream->bodystarted) { + return 0; } + + /* This is trailer HEADERS started. Allocate buffer for them. */ + DEBUGF(infof(data_s, "trailer field started\n")); + + assert(stream->trailer_recvbuf == NULL); + + stream->trailer_recvbuf = Curl_add_buffer_init(); + if(!stream->trailer_recvbuf) { + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; + } + return 0; } @@ -698,11 +802,10 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { struct HTTP *stream; - struct SessionHandle *data_s; + struct Curl_easy *data_s; int32_t stream_id = frame->hd.stream_id; - + struct connectdata *conn = (struct connectdata *)userp; (void)flags; - (void)userp; DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ @@ -719,11 +822,6 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, return NGHTTP2_ERR_CALLBACK_FAILURE; } - if(stream->bodystarted) - /* Ignore trailer or HEADERS not mapped to HTTP semantics. The - consequence is handled in on_frame_recv(). */ - return 0; - /* Store received PUSH_PROMISE headers to be used when the subsequent PUSH_PROMISE callback comes */ if(frame->hd.type == NGHTTP2_PUSH_PROMISE) { @@ -754,6 +852,23 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, return 0; } + if(stream->bodystarted) { + /* This is trailer fields. */ + /* 3 is for ":" and "\r\n". */ + uint32_t n = (uint32_t)(namelen + valuelen + 3); + + DEBUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen, + value)); + + Curl_add_buffer(stream->trailer_recvbuf, &n, sizeof(n)); + Curl_add_buffer(stream->trailer_recvbuf, name, namelen); + Curl_add_buffer(stream->trailer_recvbuf, ": ", 2); + Curl_add_buffer(stream->trailer_recvbuf, value, valuelen); + Curl_add_buffer(stream->trailer_recvbuf, "\r\n\0", 3); + + return 0; + } + if(namelen == sizeof(":status") - 1 && memcmp(":status", name, namelen) == 0) { /* nghttp2 guarantees :status is received first and only once, and @@ -762,14 +877,16 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, stream->status_code = decode_status_code(value, valuelen); DEBUGASSERT(stream->status_code != -1); - Curl_add_buffer(stream->header_recvbuf, "HTTP/2.0 ", 9); + Curl_add_buffer(stream->header_recvbuf, "HTTP/2 ", 7); Curl_add_buffer(stream->header_recvbuf, value, valuelen); - Curl_add_buffer(stream->header_recvbuf, "\r\n", 2); - data_s->state.drain++; - Curl_expire(data_s, 1); - - DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d\n", - stream->status_code)); + /* the space character after the status code is mandatory */ + Curl_add_buffer(stream->header_recvbuf, " \r\n", 3); + /* if we receive data for another handle, wake that up */ + if(conn->data != data_s) + Curl_expire(data_s, 1); + + DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n", + stream->status_code, data_s)); return 0; } @@ -777,11 +894,12 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, received, and this is not pseudo-header field . */ /* convert to a HTTP1-style header */ Curl_add_buffer(stream->header_recvbuf, name, namelen); - Curl_add_buffer(stream->header_recvbuf, ":", 1); + Curl_add_buffer(stream->header_recvbuf, ": ", 2); Curl_add_buffer(stream->header_recvbuf, value, valuelen); Curl_add_buffer(stream->header_recvbuf, "\r\n", 2); - data_s->state.drain++; - Curl_expire(data_s, 1); + /* if we receive data for another handle, wake that up */ + if(conn->data != data_s) + Curl_expire(data_s, 1); DEBUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen, value)); @@ -796,7 +914,7 @@ static ssize_t data_source_read_callback(nghttp2_session *session, nghttp2_data_source *source, void *userp) { - struct SessionHandle *data_s; + struct Curl_easy *data_s; struct HTTP *stream = NULL; size_t nread; (void)source; @@ -848,6 +966,19 @@ static nghttp2_settings_entry settings[] = { #define H2_BUFSIZE 32768 +#ifdef NGHTTP2_HAS_ERROR_CALLBACK +static int error_callback(nghttp2_session *session, + const char *msg, + size_t len, + void *userp) +{ + struct connectdata *conn = (struct connectdata *)userp; + (void)session; + infof(conn->data, "http2 error: %.*s\n", len, msg); + return 0; +} +#endif + /* * Initialize nghttp2 for a Curl connection */ @@ -897,6 +1028,8 @@ CURLcode Curl_http2_init(struct connectdata *conn) /* nghttp2_on_header_callback */ nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header); + nghttp2_session_callbacks_set_error_callback(callbacks, error_callback); + /* The nghttp2 session is not yet setup, do it */ rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn); @@ -906,25 +1039,11 @@ CURLcode Curl_http2_init(struct connectdata *conn) failf(conn->data, "Couldn't initialize nghttp2!"); return CURLE_OUT_OF_MEMORY; /* most likely at least */ } - - if(rc) { - failf(conn->data, "Couldn't init stream hash!"); - return CURLE_OUT_OF_MEMORY; /* most likely at least */ - } } return CURLE_OK; } /* - * Send a request using http2 - */ -CURLcode Curl_http2_send_request(struct connectdata *conn) -{ - (void)conn; - return CURLE_OK; -} - -/* * Append headers to ask for a HTTP1.1 to HTTP2 upgrade. */ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, @@ -969,26 +1088,187 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, return result; } -static ssize_t http2_handle_stream_close(struct http_conn *httpc, - struct SessionHandle *data, +/* + * Returns nonzero if current HTTP/2 session should be closed. + */ +static int should_close_session(struct http_conn *httpc) { + return httpc->drain_total == 0 && !nghttp2_session_want_read(httpc->h2) && + !nghttp2_session_want_write(httpc->h2); +} + +static int h2_session_send(struct Curl_easy *data, + nghttp2_session *h2); + +/* + * h2_process_pending_input() processes pending input left in + * httpc->inbuf. Then, call h2_session_send() to send pending data. + * This function returns 0 if it succeeds, or -1 and error code will + * be assigned to *err. + */ +static int h2_process_pending_input(struct Curl_easy *data, + struct http_conn *httpc, + CURLcode *err) { + ssize_t nread; + char *inbuf; + ssize_t rv; + + nread = httpc->inbuflen - httpc->nread_inbuf; + inbuf = httpc->inbuf + httpc->nread_inbuf; + + rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread); + if(rv < 0) { + failf(data, + "h2_process_pending_input: nghttp2_session_mem_recv() returned " + "%d:%s\n", rv, nghttp2_strerror((int)rv)); + *err = CURLE_RECV_ERROR; + return -1; + } + + if(nread == rv) { + DEBUGF(infof(data, + "h2_process_pending_input: All data in connection buffer " + "processed\n")); + httpc->inbuflen = 0; + httpc->nread_inbuf = 0; + } + else { + httpc->nread_inbuf += rv; + DEBUGF(infof(data, + "h2_process_pending_input: %zu bytes left in connection " + "buffer\n", + httpc->inbuflen - httpc->nread_inbuf)); + } + + rv = h2_session_send(data, httpc->h2); + if(rv != 0) { + *err = CURLE_SEND_ERROR; + return -1; + } + + if(should_close_session(httpc)) { + DEBUGF(infof(data, + "h2_process_pending_input: nothing to do in this session\n")); + *err = CURLE_HTTP2; + return -1; + } + + return 0; +} + +static ssize_t http2_handle_stream_close(struct connectdata *conn, + struct Curl_easy *data, struct HTTP *stream, CURLcode *err) { + char *trailer_pos, *trailer_end; + CURLcode result; + struct http_conn *httpc = &conn->proto.httpc; + if(httpc->pause_stream_id == stream->stream_id) { httpc->pause_stream_id = 0; } + + DEBUGASSERT(httpc->drain_total >= data->state.drain); + httpc->drain_total -= data->state.drain; + data->state.drain = 0; + + if(httpc->pause_stream_id == 0) { + if(h2_process_pending_input(data, httpc, err) != 0) { + return -1; + } + } + + DEBUGASSERT(data->state.drain == 0); + /* Reset to FALSE to prevent infinite loop in readwrite_data function. */ stream->closed = FALSE; if(stream->error_code != NGHTTP2_NO_ERROR) { - failf(data, "HTTP/2 stream %u was not closed cleanly: error_code = %d", - stream->stream_id, stream->error_code); - *err = CURLE_HTTP2; + failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %d)", + stream->stream_id, Curl_http2_strerror(stream->error_code), + stream->error_code); + *err = CURLE_HTTP2_STREAM; + return -1; + } + + if(!stream->bodystarted) { + failf(data, "HTTP/2 stream %u was closed cleanly, but before getting " + " all response header fields, teated as error", + stream->stream_id); + *err = CURLE_HTTP2_STREAM; return -1; } + + if(stream->trailer_recvbuf && stream->trailer_recvbuf->buffer) { + trailer_pos = stream->trailer_recvbuf->buffer; + trailer_end = trailer_pos + stream->trailer_recvbuf->size_used; + + for(; trailer_pos < trailer_end;) { + uint32_t n; + memcpy(&n, trailer_pos, sizeof(n)); + trailer_pos += sizeof(n); + + result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailer_pos, n); + if(result) { + *err = result; + return -1; + } + + trailer_pos += n + 1; + } + } + DEBUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n")); return 0; } /* + * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight + * and dependency to the peer. It also stores the updated values in the state + * struct. + */ + +static void h2_pri_spec(struct Curl_easy *data, + nghttp2_priority_spec *pri_spec) +{ + struct HTTP *depstream = (data->set.stream_depends_on? + data->set.stream_depends_on->req.protop:NULL); + int32_t depstream_id = depstream? depstream->stream_id:0; + nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight, + data->set.stream_depends_e); + data->state.stream_weight = data->set.stream_weight; + data->state.stream_depends_e = data->set.stream_depends_e; + data->state.stream_depends_on = data->set.stream_depends_on; +} + +/* + * h2_session_send() checks if there's been an update in the priority / + * dependency settings and if so it submits a PRIORITY frame with the updated + * info. + */ +static int h2_session_send(struct Curl_easy *data, + nghttp2_session *h2) +{ + struct HTTP *stream = data->req.protop; + if((data->set.stream_weight != data->state.stream_weight) || + (data->set.stream_depends_e != data->state.stream_depends_e) || + (data->set.stream_depends_on != data->state.stream_depends_on) ) { + /* send new weight and/or dependency */ + nghttp2_priority_spec pri_spec; + int rv; + + h2_pri_spec(data, &pri_spec); + + DEBUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)\n", + stream->stream_id, data)); + rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id, + &pri_spec); + if(rv) + return rv; + } + + return nghttp2_session_send(h2); +} + +/* * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return * a regular CURLcode value. */ @@ -999,17 +1279,16 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, ssize_t rv; ssize_t nread; struct http_conn *httpc = &conn->proto.httpc; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct HTTP *stream = data->req.protop; (void)sockindex; /* we always do HTTP2 on sockindex 0 */ - /* If stream is closed, return 0 to signal the http routine to close - the connection. We need to handle stream closure here, - otherwise, we may be going to read from underlying connection, - and gets EAGAIN, and we will get stuck there. */ - if(stream->memlen == 0 && stream->closed) { - return http2_handle_stream_close(httpc, data, stream, err); + if(should_close_session(httpc)) { + DEBUGF(infof(data, + "http2_recv: nothing to do in this session\n")); + *err = CURLE_HTTP2; + return -1; } /* Nullify here because we call nghttp2_session_send() and they @@ -1018,7 +1297,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, stream->upload_len = 0; /* - * At this point 'stream' is just in the SessionHandle the connection + * At this point 'stream' is just in the Curl_easy the connection * identifies as its owner at this time. */ @@ -1032,13 +1311,13 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, ncopy); stream->nread_header_recvbuf += ncopy; - infof(data, "http2_recv: Got %d bytes from header_recvbuf\n", - (int)ncopy); + DEBUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n", + (int)ncopy)); return ncopy; } - infof(data, "http2_recv: %d bytes buffer at %p (stream %u)\n", - len, mem, stream->stream_id); + DEBUGF(infof(data, "http2_recv: easy %p (stream %u)\n", + data, stream->stream_id)); if((data->state.drain) && stream->memlen) { DEBUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n", @@ -1051,8 +1330,18 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, stream->len = len - stream->memlen; stream->mem = mem; } + if(httpc->pause_stream_id == stream->stream_id && !stream->pausedata) { + /* We have paused nghttp2, but we have no pause data (see + on_data_chunk_recv). */ + httpc->pause_stream_id = 0; + if(h2_process_pending_input(data, httpc, &result) != 0) { + *err = result; + return -1; + } + } } else if(stream->pausedata) { + DEBUGASSERT(httpc->pause_stream_id == stream->stream_id); nread = MIN(len, stream->pauselen); memcpy(mem, stream->pausedata, nread); @@ -1067,9 +1356,21 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, stream->pausedata = NULL; stream->pauselen = 0; + + /* When NGHTTP2_ERR_PAUSE is returned from + data_source_read_callback, we might not process DATA frame + fully. Calling nghttp2_session_mem_recv() again will + continue to process DATA frame, but if there is no incoming + frames, then we have to call it again with 0-length data. + Without this, on_stream_close callback will not be called, + and stream could be hanged. */ + if(h2_process_pending_input(data, httpc, &result) != 0) { + *err = result; + return -1; + } } - infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n", - nread, stream->stream_id); + DEBUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n", + nread, stream->stream_id)); return nread; } else if(httpc->pause_stream_id) { @@ -1096,15 +1397,15 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, nread = ((Curl_recv *)httpc->recv_underlying)( conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result); - if(result == CURLE_AGAIN) { - *err = result; - return -1; - } - if(nread == -1) { - failf(data, "Failed receiving HTTP2 data"); + if(result != CURLE_AGAIN) + failf(data, "Failed receiving HTTP2 data"); + else if(stream->closed) + /* received when the stream was already closed! */ + return http2_handle_stream_close(conn, data, stream, err); + *err = result; - return 0; + return -1; } if(nread == 0) { @@ -1146,16 +1447,22 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, } /* Always send pending frames in nghttp2 session, because nghttp2_session_mem_recv() may queue new frame */ - rv = nghttp2_session_send(httpc->h2); + rv = h2_session_send(data, httpc->h2); if(rv != 0) { *err = CURLE_SEND_ERROR; return 0; } + + if(should_close_session(httpc)) { + DEBUGF(infof(data, "http2_recv: nothing to do in this session\n")); + *err = CURLE_HTTP2; + return -1; + } } if(stream->memlen) { ssize_t retlen = stream->memlen; - infof(data, "http2_recv: returns %zd for stream %u\n", - retlen, stream->stream_id); + DEBUGF(infof(data, "http2_recv: returns %zd for stream %u\n", + retlen, stream->stream_id)); stream->memlen = 0; if(httpc->pause_stream_id == stream->stream_id) { @@ -1164,15 +1471,18 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, DEBUGF(infof(data, "Data returned for PAUSED stream %u\n", stream->stream_id)); } - else + else if(!stream->closed) { + DEBUGASSERT(httpc->drain_total >= data->state.drain); + httpc->drain_total -= data->state.drain; data->state.drain = 0; /* this stream is hereby drained */ + } return retlen; } /* If stream is closed, return 0 to signal the http routine to close the connection */ if(stream->closed) { - return http2_handle_stream_close(httpc, data, stream, err); + return http2_handle_stream_close(conn, data, stream, err); } *err = CURLE_AGAIN; DEBUGF(infof(data, "http2_recv returns AGAIN for stream %u\n", @@ -1184,6 +1494,9 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, field list. */ #define AUTHORITY_DST_IDX 3 +#define HEADER_OVERFLOW(x) \ + (x.namelen > (uint16_t)-1 || x.valuelen > (uint16_t)-1 - x.namelen) + /* return number of received (decrypted) bytes */ static ssize_t http2_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *err) @@ -1196,15 +1509,16 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, int rv; struct http_conn *httpc = &conn->proto.httpc; struct HTTP *stream = conn->data->req.protop; - nghttp2_nv *nva; + nghttp2_nv *nva = NULL; size_t nheader; size_t i; size_t authority_idx; char *hdbuf = (char*)mem; - char *end; + char *end, *line_end; nghttp2_data_provider data_prd; int32_t stream_id; nghttp2_session *h2 = httpc->h2; + nghttp2_priority_spec pri_spec; (void)sockindex; @@ -1216,7 +1530,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, stream->upload_mem = mem; stream->upload_len = len; nghttp2_session_resume_data(h2, stream->stream_id); - rv = nghttp2_session_send(h2); + rv = h2_session_send(conn->data, h2); if(nghttp2_is_fatal(rv)) { *err = CURLE_SEND_ERROR; return -1; @@ -1228,6 +1542,12 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, stream->upload_mem = NULL; stream->upload_len = 0; + if(should_close_session(httpc)) { + DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n")); + *err = CURLE_HTTP2; + return -1; + } + if(stream->upload_left) { /* we are sure that we have more data to send here. Calling the following API will make nghttp2_session_want_write() return @@ -1245,12 +1565,16 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, /* Here, we assume the curl http code generate *correct* HTTP header field block */ nheader = 0; - for(i = 0; i < len; ++i) { - if(hdbuf[i] == 0x0a) { + for(i = 1; i < len; ++i) { + if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') { ++nheader; + ++i; } } - /* We counted additional 2 \n in the first and last line. We need 3 + if(nheader < 2) + goto fail; + + /* We counted additional 2 \r\n in the first and last line. We need 3 new headers: :method, :path and :scheme. Therefore we need one more space. */ nheader += 1; @@ -1259,81 +1583,133 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, *err = CURLE_OUT_OF_MEMORY; return -1; } + /* Extract :method, :path from request line */ - end = strchr(hdbuf, ' '); - if(!end) + line_end = strstr(hdbuf, "\r\n"); + + /* Method does not contain spaces */ + end = memchr(hdbuf, ' ', line_end - hdbuf); + if(!end || end == hdbuf) goto fail; nva[0].name = (unsigned char *)":method"; - nva[0].namelen = (uint16_t)strlen((char *)nva[0].name); + nva[0].namelen = strlen((char *)nva[0].name); nva[0].value = (unsigned char *)hdbuf; - nva[0].valuelen = (uint16_t)(end - hdbuf); + nva[0].valuelen = (size_t)(end - hdbuf); nva[0].flags = NGHTTP2_NV_FLAG_NONE; + if(HEADER_OVERFLOW(nva[0])) { + failf(conn->data, "Failed sending HTTP request: Header overflow"); + goto fail; + } hdbuf = end + 1; - end = strchr(hdbuf, ' '); - if(!end) + /* Path may contain spaces so scan backwards */ + end = NULL; + for(i = (size_t)(line_end - hdbuf); i; --i) { + if(hdbuf[i - 1] == ' ') { + end = &hdbuf[i - 1]; + break; + } + } + if(!end || end == hdbuf) goto fail; nva[1].name = (unsigned char *)":path"; - nva[1].namelen = (uint16_t)strlen((char *)nva[1].name); + nva[1].namelen = strlen((char *)nva[1].name); nva[1].value = (unsigned char *)hdbuf; - nva[1].valuelen = (uint16_t)(end - hdbuf); + nva[1].valuelen = (size_t)(end - hdbuf); nva[1].flags = NGHTTP2_NV_FLAG_NONE; + if(HEADER_OVERFLOW(nva[1])) { + failf(conn->data, "Failed sending HTTP request: Header overflow"); + goto fail; + } + + hdbuf = end + 1; + end = line_end; nva[2].name = (unsigned char *)":scheme"; - nva[2].namelen = (uint16_t)strlen((char *)nva[2].name); + nva[2].namelen = strlen((char *)nva[2].name); if(conn->handler->flags & PROTOPT_SSL) nva[2].value = (unsigned char *)"https"; else nva[2].value = (unsigned char *)"http"; - nva[2].valuelen = (uint16_t)strlen((char *)nva[2].value); + nva[2].valuelen = strlen((char *)nva[2].value); nva[2].flags = NGHTTP2_NV_FLAG_NONE; - - hdbuf = strchr(hdbuf, 0x0a); - if(!hdbuf) + if(HEADER_OVERFLOW(nva[2])) { + failf(conn->data, "Failed sending HTTP request: Header overflow"); goto fail; - ++hdbuf; + } authority_idx = 0; + i = 3; + while(i < nheader) { + size_t hlen; + int skip = 0; + + hdbuf = line_end + 2; + + line_end = strstr(hdbuf, "\r\n"); + if(line_end == hdbuf) + goto fail; + + /* header continuation lines are not supported */ + if(*hdbuf == ' ' || *hdbuf == '\t') + goto fail; - for(i = 3; i < nheader; ++i) { - end = strchr(hdbuf, ':'); - if(!end) + for(end = hdbuf; end < line_end && *end != ':'; ++end) + ; + if(end == hdbuf || end == line_end) goto fail; - if(end - hdbuf == 4 && Curl_raw_nequal("host", hdbuf, 4)) { + hlen = end - hdbuf; + + if(hlen == 10 && Curl_raw_nequal("connection", hdbuf, 10)) { + /* skip Connection: headers! */ + skip = 1; + --nheader; + } + else if(hlen == 4 && Curl_raw_nequal("host", hdbuf, 4)) { authority_idx = i; nva[i].name = (unsigned char *)":authority"; - nva[i].namelen = (uint16_t)strlen((char *)nva[i].name); + nva[i].namelen = strlen((char *)nva[i].name); } else { nva[i].name = (unsigned char *)hdbuf; - nva[i].namelen = (uint16_t)(end - hdbuf); + nva[i].namelen = (size_t)(end - hdbuf); } hdbuf = end + 1; - for(; *hdbuf == ' '; ++hdbuf); - end = strchr(hdbuf, 0x0d); - if(!end) - goto fail; - nva[i].value = (unsigned char *)hdbuf; - nva[i].valuelen = (uint16_t)(end - hdbuf); - nva[i].flags = NGHTTP2_NV_FLAG_NONE; - - hdbuf = end + 2; - /* Inspect Content-Length header field and retrieve the request - entity length so that we can set END_STREAM to the last DATA - frame. */ - if(nva[i].namelen == 14 && - Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) { - size_t j; - stream->upload_left = 0; - for(j = 0; j < nva[i].valuelen; ++j) { - stream->upload_left *= 10; - stream->upload_left += nva[i].value[j] - '0'; + while(*hdbuf == ' ' || *hdbuf == '\t') + ++hdbuf; + end = line_end; + if(!skip) { + nva[i].value = (unsigned char *)hdbuf; + nva[i].valuelen = (size_t)(end - hdbuf); + nva[i].flags = NGHTTP2_NV_FLAG_NONE; + if(HEADER_OVERFLOW(nva[i])) { + failf(conn->data, "Failed sending HTTP request: Header overflow"); + goto fail; } - DEBUGF(infof(conn->data, - "request content-length=%" - CURL_FORMAT_CURL_OFF_T - "\n", stream->upload_left)); + /* Inspect Content-Length header field and retrieve the request + entity length so that we can set END_STREAM to the last DATA + frame. */ + if(nva[i].namelen == 14 && + Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) { + size_t j; + stream->upload_left = 0; + if(!nva[i].valuelen) + goto fail; + for(j = 0; j < nva[i].valuelen; ++j) { + if(nva[i].value[j] < '0' || nva[i].value[j] > '9') + goto fail; + if(stream->upload_left >= CURL_OFF_T_MAX / 10) + goto fail; + stream->upload_left *= 10; + stream->upload_left += nva[i].value[j] - '0'; + } + DEBUGF(infof(conn->data, + "request content-length=%" + CURL_FORMAT_CURL_OFF_T + "\n", stream->upload_left)); + } + ++i; } } @@ -1346,17 +1722,42 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, nva[i] = authority; } + /* Warn stream may be rejected if cumulative length of headers is too large. + It appears nghttp2 will not send a header frame larger than 64KB. */ + { + size_t acc = 0; + const size_t max_acc = 60000; /* <64KB to account for some overhead */ + + for(i = 0; i < nheader; ++i) { + if(nva[i].namelen > max_acc - acc) + break; + acc += nva[i].namelen; + + if(nva[i].valuelen > max_acc - acc) + break; + acc += nva[i].valuelen; + } + + if(i != nheader) { + infof(conn->data, "http2_send: Warning: The cumulative length of all " + "headers exceeds %zu bytes and that could cause the " + "stream to be rejected.\n", max_acc); + } + } + + h2_pri_spec(conn->data, &pri_spec); + switch(conn->data->set.httpreq) { case HTTPREQ_POST: case HTTPREQ_POST_FORM: case HTTPREQ_PUT: data_prd.read_callback = data_source_read_callback; data_prd.source.ptr = NULL; - stream_id = nghttp2_submit_request(h2, NULL, nva, nheader, + stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader, &data_prd, conn->data); break; default: - stream_id = nghttp2_submit_request(h2, NULL, nva, nheader, + stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader, NULL, conn->data); } @@ -1372,6 +1773,8 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, stream_id, conn->data); stream->stream_id = stream_id; + /* this does not call h2_session_send() since there can not have been any + * priority upodate since the nghttp2_submit_request() call above */ rv = nghttp2_session_send(h2); if(rv != 0) { @@ -1379,6 +1782,12 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, return -1; } + if(should_close_session(httpc)) { + DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n")); + *err = CURLE_HTTP2; + return -1; + } + if(stream->stream_id != -1) { /* If whole HEADERS frame was sent off to the underlying socket, the nghttp2 library calls data_source_read_callback. But only @@ -1393,7 +1802,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, return len; - fail: +fail: free(nva); *err = CURLE_SEND_ERROR; return -1; @@ -1432,6 +1841,7 @@ CURLcode Curl_http2_setup(struct connectdata *conn) httpc->nread_inbuf = 0; httpc->pause_stream_id = 0; + httpc->drain_total = 0; conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ conn->httpversion = 20; @@ -1440,6 +1850,10 @@ CURLcode Curl_http2_setup(struct connectdata *conn) infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n"); Curl_multi_connchanged(conn->data->multi); + /* switch on TCP_NODELAY as we need to send off packets without delay for + maximum throughput */ + Curl_tcpnodelay(conn, conn->sock[FIRSTSOCKET]); + return CURLE_OK; } @@ -1450,7 +1864,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn, struct http_conn *httpc = &conn->proto.httpc; int rv; ssize_t nproc; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct HTTP *stream = conn->data->req.protop; result = Curl_http2_setup(conn); @@ -1527,7 +1941,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn, } /* Try to send some frames since we may read SETTINGS already. */ - rv = nghttp2_session_send(httpc->h2); + rv = h2_session_send(data, httpc->h2); if(rv != 0) { failf(data, "nghttp2_session_send() failed: %s(%d)", @@ -1535,6 +1949,12 @@ CURLcode Curl_http2_switched(struct connectdata *conn, return CURLE_HTTP2; } + if(should_close_session(httpc)) { + DEBUGF(infof(data, + "nghttp2_session_send(): nothing to do in this session\n")); + return CURLE_HTTP2; + } + return CURLE_OK; } diff --git a/lib/http2.h b/lib/http2.h index bb7ad9c..bedbebf 100644 --- a/lib/http2.h +++ b/lib/http2.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -37,7 +37,11 @@ */ int Curl_http2_ver(char *p, size_t len); +const char *Curl_http2_strerror(uint32_t err); + CURLcode Curl_http2_init(struct connectdata *conn); +void Curl_http2_init_state(struct UrlState *state); +void Curl_http2_init_userset(struct UserDefined *set); CURLcode Curl_http2_send_request(struct connectdata *conn); CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, struct connectdata *conn); @@ -46,7 +50,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn, const char *data, size_t nread); /* called from Curl_http_setup_conn */ void Curl_http2_setup_conn(struct connectdata *conn); -void Curl_http2_setup_req(struct SessionHandle *data); +void Curl_http2_setup_req(struct Curl_easy *data); #else /* USE_NGHTTP2 */ #define Curl_http2_init(x) CURLE_UNSUPPORTED_PROTOCOL #define Curl_http2_send_request(x) CURLE_UNSUPPORTED_PROTOCOL @@ -55,6 +59,8 @@ void Curl_http2_setup_req(struct SessionHandle *data); #define Curl_http2_switched(x,y,z) CURLE_UNSUPPORTED_PROTOCOL #define Curl_http2_setup_conn(x) #define Curl_http2_setup_req(x) +#define Curl_http2_init_state(x) +#define Curl_http2_init_userset(x) #endif #endif /* HEADER_CURL_HTTP2_H */ diff --git a/lib/http_chunks.c b/lib/http_chunks.c index 7e91b37..ea17109 100644 --- a/lib/http_chunks.c +++ b/lib/http_chunks.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -80,7 +80,7 @@ static bool Curl_isxdigit(char digit) { return ( (digit >= 0x30 && digit <= 0x39) /* 0-9 */ || (digit >= 0x41 && digit <= 0x46) /* A-F */ - || (digit >= 0x61 && digit <= 0x66) /* a-f */ ) ? TRUE : FALSE; + || (digit >= 0x61 && digit <= 0x66) /* a-f */) ? TRUE : FALSE; } void Curl_httpchunk_init(struct connectdata *conn) @@ -108,7 +108,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, ssize_t *wrotep) { CURLcode result=CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct Curl_chunker *ch = &conn->chunk; struct SingleRequest *k = &data->req; size_t piece; diff --git a/lib/http_chunks.h b/lib/http_chunks.h index 0489eb8..3a8b4dd 100644 --- a/lib/http_chunks.h +++ b/lib/http_chunks.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/http_digest.c b/lib/http_digest.c index 929e2c6..97230e7 100644 --- a/lib/http_digest.c +++ b/lib/http_digest.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,11 +26,10 @@ #include "urldata.h" #include "rawstr.h" -#include "curl_sasl.h" +#include "vauth/vauth.h" #include "http_digest.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -46,7 +45,7 @@ CURLcode Curl_input_digest(struct connectdata *conn, const char *header) /* rest of the *-authenticate: header */ { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Point to the correct struct with this */ struct digestdata *digest; @@ -65,7 +64,7 @@ CURLcode Curl_input_digest(struct connectdata *conn, while(*header && ISSPACE(*header)) header++; - return Curl_sasl_decode_digest_http_message(header, digest); + return Curl_auth_decode_digest_http_message(header, digest); } CURLcode Curl_output_digest(struct connectdata *conn, @@ -74,7 +73,7 @@ CURLcode Curl_output_digest(struct connectdata *conn, const unsigned char *uripath) { CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; unsigned char *path; char *tmp; char *response; @@ -135,7 +134,7 @@ CURLcode Curl_output_digest(struct connectdata *conn, Apache servers can be set to do the Digest IE-style automatically using the BrowserMatch feature: - http://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie + https://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie Further details on Digest implementation differences: http://www.fngtps.com/2006/09/http-authentication @@ -152,7 +151,7 @@ CURLcode Curl_output_digest(struct connectdata *conn, if(!path) return CURLE_OUT_OF_MEMORY; - result = Curl_sasl_create_digest_http_message(data, userp, passwdp, request, + result = Curl_auth_create_digest_http_message(data, userp, passwdp, request, path, digest, &response, &len); free(path); if(result) @@ -170,10 +169,10 @@ CURLcode Curl_output_digest(struct connectdata *conn, return CURLE_OK; } -void Curl_digest_cleanup(struct SessionHandle *data) +void Curl_digest_cleanup(struct Curl_easy *data) { - Curl_sasl_digest_cleanup(&data->state.digest); - Curl_sasl_digest_cleanup(&data->state.proxydigest); + Curl_auth_digest_cleanup(&data->state.digest); + Curl_auth_digest_cleanup(&data->state.proxydigest); } #endif diff --git a/lib/http_digest.h b/lib/http_digest.h index d13d563..fd225c7 100644 --- a/lib/http_digest.h +++ b/lib/http_digest.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -34,7 +34,7 @@ CURLcode Curl_output_digest(struct connectdata *conn, const unsigned char *uripath); #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) -void Curl_digest_cleanup(struct SessionHandle *data); +void Curl_digest_cleanup(struct Curl_easy *data); #else #define Curl_digest_cleanup(x) Curl_nop_stmt #endif diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c index a1baf29..c39d6f3 100644 --- a/lib/http_negotiate.c +++ b/lib/http_negotiate.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,156 +22,94 @@ #include "curl_setup.h" -#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) +#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) #include "urldata.h" #include "sendf.h" -#include "curl_gssapi.h" #include "rawstr.h" -#include "curl_base64.h" #include "http_negotiate.h" -#include "curl_sasl.h" -#include "url.h" -#include "curl_printf.h" +#include "vauth/vauth.h" -/* The last #include files should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, const char *header) { - struct SessionHandle *data = conn->data; - struct negotiatedata *neg_ctx = proxy?&data->state.proxyneg: - &data->state.negotiate; - OM_uint32 major_status, minor_status, discard_st; - gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; - gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; - gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + struct Curl_easy *data = conn->data; size_t len; - size_t rawlen = 0; - CURLcode result; - if(neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) { - /* We finished successfully our part of authentication, but server - * rejected it (since we're again here). Exit with an error since we - * can't invent anything better */ - Curl_cleanup_negotiate(data); - return CURLE_LOGIN_DENIED; - } + /* Point to the username, password, service and host */ + const char *userp; + const char *passwdp; + const char *service; + const char *host; - if(!neg_ctx->server_name) { - /* Generate our SPN */ - char *spn = Curl_sasl_build_gssapi_spn( - proxy ? data->set.str[STRING_PROXY_SERVICE_NAME] : - data->set.str[STRING_SERVICE_NAME], - proxy ? conn->proxy.name : conn->host.name); - if(!spn) - return CURLE_OUT_OF_MEMORY; - - /* Populate the SPN structure */ - spn_token.value = spn; - spn_token.length = strlen(spn); - - /* Import the SPN */ - major_status = gss_import_name(&minor_status, &spn_token, - GSS_C_NT_HOSTBASED_SERVICE, - &neg_ctx->server_name); - if(GSS_ERROR(major_status)) { - Curl_gss_log_error(data, minor_status, "gss_import_name() failed: "); - - free(spn); - - return CURLE_OUT_OF_MEMORY; - } + /* Point to the correct struct with this */ + struct negotiatedata *neg_ctx; - free(spn); + if(proxy) { + userp = conn->proxyuser; + passwdp = conn->proxypasswd; + service = data->set.str[STRING_PROXY_SERVICE_NAME] ? + data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; + host = conn->proxy.name; + neg_ctx = &data->state.proxyneg; + } + else { + userp = conn->user; + passwdp = conn->passwd; + service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : "HTTP"; + host = conn->host.name; + neg_ctx = &data->state.negotiate; } + /* Not set means empty */ + if(!userp) + userp = ""; + + if(!passwdp) + passwdp = ""; + + /* Obtain the input token, if any */ header += strlen("Negotiate"); while(*header && ISSPACE(*header)) header++; len = strlen(header); - if(len > 0) { - result = Curl_base64_decode(header, (unsigned char **)&input_token.value, - &rawlen); - if(result) - return result; - - if(!rawlen) { - infof(data, "Negotiate handshake failure (empty challenge message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; + if(!len) { + /* Is this the first call in a new negotiation? */ + if(neg_ctx->context) { + /* The server rejected our authentication and hasn't suppled any more + negotiation mechanisms */ + return CURLE_LOGIN_DENIED; } - - input_token.length = rawlen; - - DEBUGASSERT(input_token.value != NULL); - } - - major_status = Curl_gss_init_sec_context(data, - &minor_status, - &neg_ctx->context, - neg_ctx->server_name, - &Curl_spnego_mech_oid, - GSS_C_NO_CHANNEL_BINDINGS, - &input_token, - &output_token, - TRUE, - NULL); - Curl_safefree(input_token.value); - - neg_ctx->status = major_status; - if(GSS_ERROR(major_status)) { - if(output_token.value) - gss_release_buffer(&discard_st, &output_token); - Curl_gss_log_error(conn->data, minor_status, - "gss_init_sec_context() failed: "); - return CURLE_OUT_OF_MEMORY; - } - - if(!output_token.value || !output_token.length) { - if(output_token.value) - gss_release_buffer(&discard_st, &output_token); - return CURLE_OUT_OF_MEMORY; } - neg_ctx->output_token = output_token; - - return CURLE_OK; + /* Initilise the security context and decode our challenge */ + return Curl_auth_decode_spnego_message(data, userp, passwdp, service, host, + header, neg_ctx); } CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) { - struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: + struct negotiatedata *neg_ctx = proxy ? &conn->data->state.proxyneg : &conn->data->state.negotiate; - char *encoded = NULL; + char *base64 = NULL; size_t len = 0; char *userp; CURLcode result; - OM_uint32 discard_st; - - result = Curl_base64_encode(conn->data, - neg_ctx->output_token.value, - neg_ctx->output_token.length, - &encoded, &len); - if(result) { - gss_release_buffer(&discard_st, &neg_ctx->output_token); - neg_ctx->output_token.value = NULL; - neg_ctx->output_token.length = 0; - return result; - } - if(!encoded || !len) { - gss_release_buffer(&discard_st, &neg_ctx->output_token); - neg_ctx->output_token.value = NULL; - neg_ctx->output_token.length = 0; - return CURLE_REMOTE_ACCESS_DENIED; - } + result = Curl_auth_create_spnego_message(conn->data, neg_ctx, &base64, &len); + if(result) + return result; userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "", - encoded); + base64); + if(proxy) { Curl_safefree(conn->allocptr.proxyuserpwd); conn->allocptr.proxyuserpwd = userp; @@ -181,30 +119,15 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) conn->allocptr.userpwd = userp; } - free(encoded); + free(base64); return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK; } -static void cleanup(struct negotiatedata *neg_ctx) -{ - OM_uint32 minor_status; - if(neg_ctx->context != GSS_C_NO_CONTEXT) - gss_delete_sec_context(&minor_status, &neg_ctx->context, GSS_C_NO_BUFFER); - - if(neg_ctx->output_token.value) - gss_release_buffer(&minor_status, &neg_ctx->output_token); - - if(neg_ctx->server_name != GSS_C_NO_NAME) - gss_release_name(&minor_status, &neg_ctx->server_name); - - memset(neg_ctx, 0, sizeof(*neg_ctx)); -} - -void Curl_cleanup_negotiate(struct SessionHandle *data) +void Curl_cleanup_negotiate(struct Curl_easy *data) { - cleanup(&data->state.negotiate); - cleanup(&data->state.proxyneg); + Curl_auth_spnego_cleanup(&data->state.negotiate); + Curl_auth_spnego_cleanup(&data->state.proxyneg); } -#endif /* HAVE_GSSAPI && !CURL_DISABLE_HTTP && USE_SPNEGO */ +#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */ diff --git a/lib/http_negotiate.h b/lib/http_negotiate.h index a8eb980..c64e548 100644 --- a/lib/http_negotiate.h +++ b/lib/http_negotiate.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -31,11 +31,7 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, /* this is for creating Negotiate header output */ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy); -void Curl_cleanup_negotiate(struct SessionHandle *data); - -#ifdef USE_WINDOWS_SSPI -#define GSS_ERROR(status) (status & 0x80000000) -#endif +void Curl_cleanup_negotiate(struct Curl_easy *data); #endif /* USE_SPNEGO */ diff --git a/lib/http_negotiate_sspi.c b/lib/http_negotiate_sspi.c deleted file mode 100644 index a50ea96..0000000 --- a/lib/http_negotiate_sspi.c +++ /dev/null @@ -1,300 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef USE_WINDOWS_SSPI - -#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) - -#include "urldata.h" -#include "sendf.h" -#include "rawstr.h" -#include "warnless.h" -#include "curl_base64.h" -#include "curl_sasl.h" -#include "http_negotiate.h" -#include "curl_multibyte.h" -#include "curl_printf.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, - const char *header) -{ - struct SessionHandle *data = conn->data; - BYTE *input_token = NULL; - SecBufferDesc out_buff_desc; - SecBuffer out_sec_buff; - SecBufferDesc in_buff_desc; - SecBuffer in_sec_buff; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - size_t len = 0, input_token_len = 0; - CURLcode result; - - /* Point to the username and password */ - const char *userp; - const char *passwdp; - - /* Point to the correct struct with this */ - struct negotiatedata *neg_ctx; - - if(proxy) { - userp = conn->proxyuser; - passwdp = conn->proxypasswd; - neg_ctx = &data->state.proxyneg; - } - else { - userp = conn->user; - passwdp = conn->passwd; - neg_ctx = &data->state.negotiate; - } - - /* Not set means empty */ - if(!userp) - userp = ""; - - if(!passwdp) - passwdp = ""; - - if(neg_ctx->context && neg_ctx->status == SEC_E_OK) { - /* We finished successfully our part of authentication, but server - * rejected it (since we're again here). Exit with an error since we - * can't invent anything better */ - Curl_cleanup_negotiate(data); - return CURLE_LOGIN_DENIED; - } - - if(!neg_ctx->server_name) { - /* Check proxy auth requested but no given proxy name */ - if(proxy && !conn->proxy.name) - return CURLE_BAD_FUNCTION_ARGUMENT; - - /* Generate our SPN */ - neg_ctx->server_name = Curl_sasl_build_spn( - proxy ? data->set.str[STRING_PROXY_SERVICE_NAME] : - data->set.str[STRING_SERVICE_NAME], - proxy ? conn->proxy.name : conn->host.name); - if(!neg_ctx->server_name) - return CURLE_OUT_OF_MEMORY; - } - - if(!neg_ctx->output_token) { - PSecPkgInfo SecurityPackage; - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) - TEXT(SP_NAME_NEGOTIATE), - &SecurityPackage); - if(status != SEC_E_OK) - return CURLE_NOT_BUILT_IN; - - /* Allocate input and output buffers according to the max token size - as indicated by the security package */ - neg_ctx->token_max = SecurityPackage->cbMaxToken; - neg_ctx->output_token = malloc(neg_ctx->token_max); - s_pSecFn->FreeContextBuffer(SecurityPackage); - } - - /* Obtain the input token, if any */ - header += strlen("Negotiate"); - while(*header && ISSPACE(*header)) - header++; - - len = strlen(header); - if(!len) { - /* Is this the first call in a new negotiation? */ - if(neg_ctx->context) { - /* The server rejected our authentication and hasn't suppled any more - negotiation mechanisms */ - return CURLE_LOGIN_DENIED; - } - - /* We have to acquire credentials and allocate memory for the context */ - neg_ctx->credentials = malloc(sizeof(CredHandle)); - neg_ctx->context = malloc(sizeof(CtxtHandle)); - - if(!neg_ctx->credentials || !neg_ctx->context) - return CURLE_OUT_OF_MEMORY; - - if(userp && *userp) { - /* Populate our identity structure */ - result = Curl_create_sspi_identity(userp, passwdp, &neg_ctx->identity); - if(result) - return result; - - /* Allow proper cleanup of the identity structure */ - neg_ctx->p_identity = &neg_ctx->identity; - } - else - /* Use the current Windows user */ - neg_ctx->p_identity = NULL; - - /* Acquire our credientials handle */ - neg_ctx->status = - s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT(SP_NAME_NEGOTIATE), - SECPKG_CRED_OUTBOUND, NULL, - neg_ctx->p_identity, NULL, NULL, - neg_ctx->credentials, &expiry); - if(neg_ctx->status != SEC_E_OK) - return CURLE_LOGIN_DENIED; - } - else { - result = Curl_base64_decode(header, - (unsigned char **)&input_token, - &input_token_len); - if(result) - return result; - - if(!input_token_len) { - infof(data, - "Negotiate handshake failure (empty challenge message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - } - - /* Setup the "output" security buffer */ - out_buff_desc.ulVersion = SECBUFFER_VERSION; - out_buff_desc.cBuffers = 1; - out_buff_desc.pBuffers = &out_sec_buff; - out_sec_buff.BufferType = SECBUFFER_TOKEN; - out_sec_buff.pvBuffer = neg_ctx->output_token; - out_sec_buff.cbBuffer = curlx_uztoul(neg_ctx->token_max); - - /* Setup the "input" security buffer if present */ - if(input_token) { - in_buff_desc.ulVersion = SECBUFFER_VERSION; - in_buff_desc.cBuffers = 1; - in_buff_desc.pBuffers = &in_sec_buff; - in_sec_buff.BufferType = SECBUFFER_TOKEN; - in_sec_buff.pvBuffer = input_token; - in_sec_buff.cbBuffer = curlx_uztoul(input_token_len); - } - - /* Generate our message */ - neg_ctx->status = s_pSecFn->InitializeSecurityContext( - neg_ctx->credentials, - input_token ? neg_ctx->context : NULL, - neg_ctx->server_name, - ISC_REQ_CONFIDENTIALITY, - 0, - SECURITY_NATIVE_DREP, - input_token ? &in_buff_desc : NULL, - 0, - neg_ctx->context, - &out_buff_desc, - &attrs, - &expiry); - - free(input_token); - - if(GSS_ERROR(neg_ctx->status)) - return CURLE_OUT_OF_MEMORY; - - if(neg_ctx->status == SEC_I_COMPLETE_NEEDED || - neg_ctx->status == SEC_I_COMPLETE_AND_CONTINUE) { - neg_ctx->status = s_pSecFn->CompleteAuthToken(neg_ctx->context, - &out_buff_desc); - if(GSS_ERROR(neg_ctx->status)) - return CURLE_RECV_ERROR; - } - - neg_ctx->output_token_length = out_sec_buff.cbBuffer; - - return CURLE_OK; -} - -CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) -{ - struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: - &conn->data->state.negotiate; - char *encoded = NULL; - size_t len = 0; - char *userp; - CURLcode error; - - error = Curl_base64_encode(conn->data, - (const char*)neg_ctx->output_token, - neg_ctx->output_token_length, - &encoded, &len); - if(error) - return error; - - if(!len) - return CURLE_REMOTE_ACCESS_DENIED; - - userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "", - encoded); - - if(proxy) { - Curl_safefree(conn->allocptr.proxyuserpwd); - conn->allocptr.proxyuserpwd = userp; - } - else { - Curl_safefree(conn->allocptr.userpwd); - conn->allocptr.userpwd = userp; - } - free(encoded); - return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK; -} - -static void cleanup(struct negotiatedata *neg_ctx) -{ - /* Free our security context */ - if(neg_ctx->context) { - s_pSecFn->DeleteSecurityContext(neg_ctx->context); - free(neg_ctx->context); - neg_ctx->context = NULL; - } - - /* Free our credentials handle */ - if(neg_ctx->credentials) { - s_pSecFn->FreeCredentialsHandle(neg_ctx->credentials); - free(neg_ctx->credentials); - neg_ctx->credentials = NULL; - } - - /* Free our identity */ - Curl_sspi_free_identity(neg_ctx->p_identity); - neg_ctx->p_identity = NULL; - - /* Free the SPN and output token */ - Curl_safefree(neg_ctx->server_name); - Curl_safefree(neg_ctx->output_token); - - /* Reset any variables */ - neg_ctx->token_max = 0; -} - -void Curl_cleanup_negotiate(struct SessionHandle *data) -{ - cleanup(&data->state.negotiate); - cleanup(&data->state.proxyneg); -} - -#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */ - -#endif /* USE_WINDOWS_SSPI */ diff --git a/lib/curl_ntlm.c b/lib/http_ntlm.c similarity index 91% rename from lib/curl_ntlm.c rename to lib/http_ntlm.c index f9ddf50..935df25 100644 --- a/lib/curl_ntlm.c +++ b/lib/http_ntlm.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -28,7 +28,7 @@ * NTLM details: * * http://davenport.sourceforge.net/ntlm.html - * http://www.innovation.ch/java/ntlm.html + * https://www.innovation.ch/java/ntlm.html */ #define DEBUG_ME 0 @@ -36,12 +36,10 @@ #include "urldata.h" #include "sendf.h" #include "rawstr.h" -#include "curl_ntlm.h" -#include "curl_ntlm_msgs.h" +#include "http_ntlm.h" #include "curl_ntlm_wb.h" -#include "curl_sasl.h" +#include "vauth/vauth.h" #include "url.h" -#include "curl_printf.h" #if defined(USE_NSS) #include "vtls/nssg.h" @@ -49,7 +47,8 @@ #include "curl_sspi.h" #endif -/* The last #include files should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" @@ -77,7 +76,7 @@ CURLcode Curl_input_ntlm(struct connectdata *conn, header++; if(*header) { - result = Curl_sasl_decode_ntlm_type2_message(conn->data, header, ntlm); + result = Curl_auth_decode_ntlm_type2_message(conn->data, header, ntlm); if(result) return result; @@ -171,7 +170,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) case NTLMSTATE_TYPE1: default: /* for the weird cases we (re)start here */ /* Create a type-1 message */ - result = Curl_sasl_create_ntlm_type1_message(userp, passwdp, ntlm, &base64, + result = Curl_auth_create_ntlm_type1_message(userp, passwdp, ntlm, &base64, &len); if(result) return result; @@ -191,7 +190,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) case NTLMSTATE_TYPE2: /* We already received the type-2 message, create a type-3 message */ - result = Curl_sasl_create_ntlm_type3_message(conn->data, userp, passwdp, + result = Curl_auth_create_ntlm_type3_message(conn->data, userp, passwdp, ntlm, &base64, &len); if(result) return result; @@ -216,7 +215,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) /* connection is already authenticated, * don't send a header in future requests */ ntlm->state = NTLMSTATE_LAST; - + /* fall-through */ case NTLMSTATE_LAST: Curl_safefree(*allocuserpwd); authp->done = TRUE; @@ -228,8 +227,8 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) void Curl_http_ntlm_cleanup(struct connectdata *conn) { - Curl_sasl_ntlm_cleanup(&conn->ntlm); - Curl_sasl_ntlm_cleanup(&conn->proxyntlm); + Curl_auth_ntlm_cleanup(&conn->ntlm); + Curl_auth_ntlm_cleanup(&conn->proxyntlm); #if defined(NTLM_WB_ENABLED) Curl_ntlm_wb_cleanup(conn); diff --git a/lib/curl_ntlm.h b/lib/http_ntlm.h similarity index 95% rename from lib/curl_ntlm.h rename to lib/http_ntlm.h index 947eac2..d186bbe 100644 --- a/lib/curl_ntlm.h +++ b/lib/http_ntlm.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/http_proxy.c b/lib/http_proxy.c index 4373d62..c6b05e3 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -35,11 +35,11 @@ #include "progress.h" #include "non-ascii.h" #include "connect.h" -#include "curl_printf.h" #include "curlx.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" CURLcode Curl_proxy_connect(struct connectdata *conn) @@ -49,6 +49,8 @@ CURLcode Curl_proxy_connect(struct connectdata *conn) /* for [protocol] tunneled through HTTP proxy */ struct HTTP http_proxy; void *prot_save; + const char *hostname; + int remote_port; CURLcode result; /* BLOCKING */ @@ -67,8 +69,16 @@ CURLcode Curl_proxy_connect(struct connectdata *conn) memset(&http_proxy, 0, sizeof(http_proxy)); conn->data->req.protop = &http_proxy; connkeep(conn, "HTTP proxy CONNECT"); - result = Curl_proxyCONNECT(conn, FIRSTSOCKET, - conn->host.name, conn->remote_port, FALSE); + if(conn->bits.conn_to_host) + hostname = conn->conn_to_host.name; + else + hostname = conn->host.name; + if(conn->bits.conn_to_port) + remote_port = conn->conn_to_port; + else + remote_port = conn->remote_port; + result = Curl_proxyCONNECT(conn, FIRSTSOCKET, hostname, + remote_port, FALSE); conn->data->req.protop = prot_save; if(CURLE_OK != result) return result; @@ -97,7 +107,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, bool blocking) { int subversion=0; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; struct SingleRequest *k = &data->req; CURLcode result; curl_socket_t tunnelsocket = conn->sock[sockindex]; @@ -150,13 +160,17 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(!result) { char *host=(char *)""; - const char *proxyconn=""; const char *useragent=""; const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1"; - char *hostheader= /* host:port with IPv6 support */ - aprintf("%s%s%s:%hu", conn->bits.ipv6_ip?"[":"", - hostname, conn->bits.ipv6_ip?"]":"", + bool ipv6_ip = conn->bits.ipv6_ip; + char *hostheader; + + /* the hostname may be different */ + if(hostname != conn->host.name) + ipv6_ip = (strchr(hostname, ':') != NULL); + hostheader= /* host:port with IPv6 support */ + aprintf("%s%s%s:%hu", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"", remote_port); if(!hostheader) { Curl_add_buffer_free(req_buffer); @@ -171,9 +185,6 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } } - if(!Curl_checkProxyheaders(conn, "Proxy-Connection:")) - proxyconn = "Proxy-Connection: Keep-Alive\r\n"; - if(!Curl_checkProxyheaders(conn, "User-Agent:") && data->set.str[STRING_USERAGENT]) useragent = conn->allocptr.uagent; @@ -183,15 +194,13 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, "CONNECT %s HTTP/%s\r\n" "%s" /* Host: */ "%s" /* Proxy-Authorization */ - "%s" /* User-Agent */ - "%s", /* Proxy-Connection */ + "%s", /* User-Agent */ hostheader, http, host, conn->allocptr.proxyuserpwd? conn->allocptr.proxyuserpwd:"", - useragent, - proxyconn); + useragent); if(host && *host) free(host); diff --git a/lib/http_proxy.h b/lib/http_proxy.h index 9c4f020..fd04330 100644 --- a/lib/http_proxy.h +++ b/lib/http_proxy.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/idn_win32.c b/lib/idn_win32.c index b369723..8dc300b 100644 --- a/lib/idn_win32.c +++ b/lib/idn_win32.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -29,9 +29,10 @@ #ifdef USE_WIN32_IDN #include "curl_multibyte.h" - #include "curl_memory.h" -/* The last #include file should be: */ +#include "warnless.h" + + /* The last #include file should be: */ #include "memdebug.h" #ifdef WANT_IDN_PROTOTYPES @@ -64,45 +65,47 @@ WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags, #define IDN_MAX_LENGTH 255 -int curl_win32_idn_to_ascii(const char *in, char **out); -int curl_win32_ascii_to_idn(const char *in, size_t in_len, char **out_utf8); +bool curl_win32_idn_to_ascii(const char *in, char **out); +bool curl_win32_ascii_to_idn(const char *in, char **out); -int curl_win32_idn_to_ascii(const char *in, char **out) +bool curl_win32_idn_to_ascii(const char *in, char **out) { + bool success = FALSE; + wchar_t *in_w = Curl_convert_UTF8_to_wchar(in); if(in_w) { wchar_t punycode[IDN_MAX_LENGTH]; - if(IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH) == 0) { - wprintf(L"ERROR %d converting to Punycode\n", GetLastError()); - free(in_w); - return 0; - } + int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH); free(in_w); - - *out = Curl_convert_wchar_to_UTF8(punycode); - if(!*out) - return 0; + if(chars) { + *out = Curl_convert_wchar_to_UTF8(punycode); + if(*out) + success = TRUE; + } } - return 1; + + return success; } -int curl_win32_ascii_to_idn(const char *in, size_t in_len, char **out_utf8) +bool curl_win32_ascii_to_idn(const char *in, char **out) { - (void)in_len; /* unused */ - if(in) { - WCHAR unicode[IDN_MAX_LENGTH]; + bool success = FALSE; - if(IdnToUnicode(0, (wchar_t *)in, -1, unicode, IDN_MAX_LENGTH) == 0) { - wprintf(L"ERROR %d converting to Punycode\n", GetLastError()); - return 0; - } - else { - *out_utf8 = Curl_convert_wchar_to_UTF8(unicode); - if(!*out_utf8) - return 0; + wchar_t *in_w = Curl_convert_UTF8_to_wchar(in); + if(in_w) { + size_t in_len = wcslen(in_w) + 1; + wchar_t unicode[IDN_MAX_LENGTH]; + int chars = IdnToUnicode(0, in_w, curlx_uztosi(in_len), + unicode, IDN_MAX_LENGTH); + free(in_w); + if(chars) { + *out = Curl_convert_wchar_to_UTF8(unicode); + if(*out) + success = TRUE; } } - return 1; + + return success; } #endif /* USE_WIN32_IDN */ diff --git a/lib/if2ip.c b/lib/if2ip.c index 6e6f969..2f92b2d 100644 --- a/lib/if2ip.c +++ b/lib/if2ip.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -53,10 +53,9 @@ #include "inet_ntop.h" #include "strequal.h" #include "if2ip.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* ------------------------------------------------------------------ */ @@ -68,7 +67,7 @@ unsigned int Curl_ipv6_scope(const struct sockaddr *sa) (void) sa; #else if(sa->sa_family == AF_INET6) { - const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *) sa; + const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *)(void *) sa; const unsigned char * b = sa6->sin6_addr.s6_addr; unsigned short w = (unsigned short) ((b[0] << 8) | b[1]); @@ -152,11 +151,12 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, continue; } - addr = &((struct sockaddr_in6 *)iface->ifa_addr)->sin6_addr; + addr = + &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr; #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID /* Include the scope of this interface as part of the address */ - scopeid = - ((struct sockaddr_in6 *)iface->ifa_addr)->sin6_scope_id; + scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr) + ->sin6_scope_id; /* If given, scope id should match. */ if(remote_scope_id && scopeid != remote_scope_id) { @@ -171,7 +171,8 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, } else #endif - addr = &((struct sockaddr_in *)iface->ifa_addr)->sin_addr; + addr = + &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr; res = IF2IP_FOUND; ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr)); snprintf(buf, buf_size, "%s%s", ip, scope); diff --git a/lib/if2ip.h b/lib/if2ip.h index 78bb0bd..f3a7ff0 100644 --- a/lib/if2ip.h +++ b/lib/if2ip.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/imap.c b/lib/imap.c index e6d83f2..123ea3b 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -80,10 +80,10 @@ #include "rawstr.h" #include "curl_sasl.h" #include "warnless.h" -#include "curl_printf.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* Local API functions */ @@ -98,7 +98,7 @@ static int imap_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks); static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done); static CURLcode imap_setup_connection(struct connectdata *conn); -static char *imap_atom(const char *str); +static char *imap_atom(const char *str, bool escape_only); static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...); static CURLcode imap_parse_url_options(struct connectdata *conn); static CURLcode imap_parse_url_path(struct connectdata *conn); @@ -227,7 +227,11 @@ static const struct SASLproto saslimap = { #ifdef USE_SSL static void imap_to_imaps(struct connectdata *conn) { + /* Change the connection handler */ conn->handler = &Curl_handler_imaps; + + /* Set the connection's upgraded to TLS flag */ + conn->tls_upgraded = TRUE; } #else #define imap_to_imaps(x) Curl_nop_stmt @@ -360,8 +364,8 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len, a space and optionally some text as per RFC-3501 for the AUTHENTICATE and APPEND commands and as outlined in Section 4. Examples of RFC-4959 but some e-mail servers ignore this and only send a single + instead. */ - if((len == 3 && !memcmp("+", line, 1)) || - (len >= 2 && !memcmp("+ ", line, 2))) { + if(imap && !imap->custom && ((len == 3 && !memcmp("+", line, 1)) || + (len >= 2 && !memcmp("+ ", line, 2)))) { switch(imapc->state) { /* States which are interested in continuation responses */ case IMAP_AUTHENTICATE: @@ -540,8 +544,8 @@ static CURLcode imap_perform_login(struct connectdata *conn) } /* Make sure the username and password are in the correct atom format */ - user = imap_atom(conn->user); - passwd = imap_atom(conn->passwd); + user = imap_atom(conn->user, false); + passwd = imap_atom(conn->passwd, false); /* Send the LOGIN command */ result = imap_sendf(conn, "LOGIN %s %s", user ? user : "", @@ -644,7 +648,7 @@ static CURLcode imap_perform_authentication(struct connectdata *conn) static CURLcode imap_perform_list(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; char *mailbox; @@ -653,8 +657,8 @@ static CURLcode imap_perform_list(struct connectdata *conn) result = imap_sendf(conn, "%s%s", imap->custom, imap->custom_params ? imap->custom_params : ""); else { - /* Make sure the mailbox is in the correct atom format */ - mailbox = imap_atom(imap->mailbox ? imap->mailbox : ""); + /* Make sure the mailbox is in the correct atom format if necessary */ + mailbox = imap->mailbox ? imap_atom(imap->mailbox, true) : strdup(""); if(!mailbox) return CURLE_OUT_OF_MEMORY; @@ -679,7 +683,7 @@ static CURLcode imap_perform_list(struct connectdata *conn) static CURLcode imap_perform_select(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; struct imap_conn *imapc = &conn->proto.imapc; char *mailbox; @@ -695,7 +699,7 @@ static CURLcode imap_perform_select(struct connectdata *conn) } /* Make sure the mailbox is in the correct atom format */ - mailbox = imap_atom(imap->mailbox); + mailbox = imap_atom(imap->mailbox, false); if(!mailbox) return CURLE_OUT_OF_MEMORY; @@ -769,7 +773,7 @@ static CURLcode imap_perform_append(struct connectdata *conn) } /* Make sure the mailbox is in the correct atom format */ - mailbox = imap_atom(imap->mailbox); + mailbox = imap_atom(imap->mailbox, false); if(!mailbox) return CURLE_OUT_OF_MEMORY; @@ -836,7 +840,7 @@ static CURLcode imap_state_servergreet_resp(struct connectdata *conn, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -856,7 +860,7 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct imap_conn *imapc = &conn->proto.imapc; const char *line = data->state.buffer; size_t wordlen; @@ -906,8 +910,8 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn, wordlen -= 5; /* Test the word for a matching authentication mechanism */ - if((mechbit = Curl_sasl_decode_mech(line, wordlen, &llen)) && - llen == wordlen) + mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); + if(mechbit && llen == wordlen) imapc->sasl.authmechs |= mechbit; } @@ -943,7 +947,7 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -967,7 +971,7 @@ static CURLcode imap_state_auth_resp(struct connectdata *conn, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct imap_conn *imapc = &conn->proto.imapc; saslprogress progress; @@ -1001,7 +1005,7 @@ static CURLcode imap_state_login_resp(struct connectdata *conn, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -1016,9 +1020,10 @@ static CURLcode imap_state_login_resp(struct connectdata *conn, return result; } -/* For LIST responses */ -static CURLcode imap_state_list_resp(struct connectdata *conn, int imapcode, - imapstate instate) +/* For LIST and SEARCH responses */ +static CURLcode imap_state_listsearch_resp(struct connectdata *conn, + int imapcode, + imapstate instate) { CURLcode result = CURLE_OK; char *line = conn->data->state.buffer; @@ -1046,7 +1051,7 @@ static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap = conn->data->req.protop; struct imap_conn *imapc = &conn->proto.imapc; const char *line = data->state.buffer; @@ -1093,12 +1098,12 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct imap_conn *imapc = &conn->proto.imapc; struct pingpong *pp = &imapc->pp; const char *ptr = data->state.buffer; bool parsed = FALSE; - curl_off_t size; + curl_off_t size = 0; (void)instate; /* no use for this yet */ @@ -1206,7 +1211,7 @@ static CURLcode imap_state_append_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* No use for this yet */ @@ -1245,31 +1250,6 @@ static CURLcode imap_state_append_final_resp(struct connectdata *conn, return result; } -/* For SEARCH responses */ -static CURLcode imap_state_search_resp(struct connectdata *conn, int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - char *line = conn->data->state.buffer; - size_t len = strlen(line); - - (void)instate; /* No use for this yet */ - - if(imapcode == '*') { - /* Temporarily add the LF character back and send as body to the client */ - line[len] = '\n'; - result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1); - line[len] = '\0'; - } - else if(imapcode != 'O') - result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */ - else - /* End of DO phase */ - state(conn, IMAP_STOP); - - return result; -} - static CURLcode imap_statemach_act(struct connectdata *conn) { CURLcode result = CURLE_OK; @@ -1323,7 +1303,7 @@ static CURLcode imap_statemach_act(struct connectdata *conn) break; case IMAP_LIST: - result = imap_state_list_resp(conn, imapcode, imapc->state); + result = imap_state_listsearch_resp(conn, imapcode, imapc->state); break; case IMAP_SELECT: @@ -1347,7 +1327,7 @@ static CURLcode imap_statemach_act(struct connectdata *conn) break; case IMAP_SEARCH: - result = imap_state_search_resp(conn, imapcode, imapc->state); + result = imap_state_listsearch_resp(conn, imapcode, imapc->state); break; case IMAP_LOGOUT: @@ -1391,12 +1371,12 @@ static CURLcode imap_block_statemach(struct connectdata *conn) return result; } -/* Allocate and initialize the struct IMAP for the current SessionHandle if +/* Allocate and initialize the struct IMAP for the current Curl_easy if required */ static CURLcode imap_init(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap; imap = data->req.protop = calloc(sizeof(struct IMAP), 1); @@ -1476,16 +1456,12 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status, bool premature) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; (void)premature; if(!imap) - /* When the easy handle is removed from the multi interface while libcurl - is still trying to resolve the host name, the IMAP struct is not yet - initialized. However, the removal action calls Curl_done() which in - turn calls this function, so we simply return success. */ return CURLE_OK; if(status) { @@ -1508,8 +1484,7 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status, TODO: when the multi interface is used, this _really_ should be using the imap_multi_statemach function but we have no general support for - non-blocking DONE operations, not in the multi state machine and with - Curl_done() invokes on several places in the code! + non-blocking DONE operations! */ if(!result) result = imap_block_statemach(conn); @@ -1543,7 +1518,7 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected, { /* This is IMAP and no proxy */ CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; struct imap_conn *imapc = &conn->proto.imapc; bool selected = FALSE; @@ -1708,7 +1683,7 @@ static CURLcode imap_regular_transfer(struct connectdata *conn, { CURLcode result = CURLE_OK; bool connected = FALSE; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Make sure size is unknown at this point */ data->req.size = -1; @@ -1731,13 +1706,17 @@ static CURLcode imap_regular_transfer(struct connectdata *conn, static CURLcode imap_setup_connection(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Initialise the IMAP layer */ CURLcode result = imap_init(conn); if(result) return result; + /* Clear the TLS upgraded flag */ + conn->tls_upgraded = FALSE; + + /* Set up the proxy if necessary */ if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { /* Unless we have asked to tunnel IMAP operations through the proxy, we switch and use HTTP operations only */ @@ -1815,38 +1794,49 @@ static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...) * The returned string needs to be freed. * */ -static char *imap_atom(const char *str) +static char *imap_atom(const char *str, bool escape_only) { + /* !checksrc! disable PARENBRACE 1 */ + const char atom_specials[] = "(){ %*]"; const char *p1; char *p2; size_t backsp_count = 0; size_t quote_count = 0; - bool space_exists = FALSE; + bool others_exists = FALSE; size_t newlen = 0; char *newstr = NULL; if(!str) return NULL; - /* Count any unescaped characters */ + /* Look for "atom-specials", counting the backslash and quote characters as + these will need escapping */ p1 = str; while(*p1) { if(*p1 == '\\') backsp_count++; else if(*p1 == '"') quote_count++; - else if(*p1 == ' ') - space_exists = TRUE; + else if(!escape_only) { + const char *p3 = atom_specials; + + while(*p3 && !others_exists) { + if(*p1 == *p3) + others_exists = TRUE; + + p3++; + } + } p1++; } - /* Does the input contain any unescaped characters? */ - if(!backsp_count && !quote_count && !space_exists) + /* Does the input contain any "atom-special" characters? */ + if(!backsp_count && !quote_count && !others_exists) return strdup(str); /* Calculate the new string length */ - newlen = strlen(str) + backsp_count + quote_count + (space_exists ? 2 : 0); + newlen = strlen(str) + backsp_count + quote_count + (others_exists ? 2 : 0); /* Allocate the new string */ newstr = (char *) malloc((newlen + 1) * sizeof(char)); @@ -1855,7 +1845,7 @@ static char *imap_atom(const char *str) /* Surround the string in quotes if necessary */ p2 = newstr; - if(space_exists) { + if(others_exists) { newstr[0] = '"'; newstr[newlen - 1] = '"'; p2++; @@ -1981,7 +1971,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn) { /* The imap struct is already initialised in imap_connect() */ CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; const char *begin = data->state.path; const char *ptr = begin; @@ -2111,7 +2101,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn) static CURLcode imap_parse_custom_request(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; const char *custom = data->set.str[STRING_CUSTOMREQUEST]; diff --git a/lib/imap.h b/lib/imap.h index 3189daa..5e0e228 100644 --- a/lib/imap.h +++ b/lib/imap.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -49,9 +49,9 @@ typedef enum { IMAP_LAST /* never used */ } imapstate; -/* This IMAP struct is used in the SessionHandle. All IMAP data that is +/* This IMAP struct is used in the Curl_easy. All IMAP data that is connection-oriented must be in imap_conn to properly deal with the fact that - perhaps the SessionHandle is changed between the times the connection is + perhaps the Curl_easy is changed between the times the connection is used. */ struct IMAP { curl_pp_transfer transfer; diff --git a/lib/inet_ntop.c b/lib/inet_ntop.c index da9a3ab..416005c 100644 --- a/lib/inet_ntop.c +++ b/lib/inet_ntop.c @@ -32,9 +32,8 @@ #include #endif -#include "curl_printf.h" - #include "inet_ntop.h" +#include "curl_printf.h" #define IN6ADDRSZ 16 #define INADDRSZ 4 @@ -57,10 +56,10 @@ static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size) tmp[0] = '\0'; (void)snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d", - ((int)((unsigned char)src[0])) & 0xff, - ((int)((unsigned char)src[1])) & 0xff, - ((int)((unsigned char)src[2])) & 0xff, - ((int)((unsigned char)src[3])) & 0xff); + ((int)((unsigned char)src[0])) & 0xff, + ((int)((unsigned char)src[1])) & 0xff, + ((int)((unsigned char)src[2])) & 0xff, + ((int)((unsigned char)src[3])) & 0xff); len = strlen(tmp); if(len == 0 || len >= size) { diff --git a/lib/inet_ntop.h b/lib/inet_ntop.h index cc4bdbb..9f44612 100644 --- a/lib/inet_ntop.h +++ b/lib/inet_ntop.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/inet_pton.c b/lib/inet_pton.c index f50b365..cf8b88a 100644 --- a/lib/inet_pton.c +++ b/lib/inet_pton.c @@ -188,8 +188,8 @@ inet_pton6(const char *src, unsigned char *dst) } if(tp + INT16SZ > endp) return (0); - *tp++ = (unsigned char) (val >> 8) & 0xff; - *tp++ = (unsigned char) val & 0xff; + *tp++ = (unsigned char) ((val >> 8) & 0xff); + *tp++ = (unsigned char) (val & 0xff); saw_xdigit = 0; val = 0; continue; @@ -205,8 +205,8 @@ inet_pton6(const char *src, unsigned char *dst) if(saw_xdigit) { if(tp + INT16SZ > endp) return (0); - *tp++ = (unsigned char) (val >> 8) & 0xff; - *tp++ = (unsigned char) val & 0xff; + *tp++ = (unsigned char) ((val >> 8) & 0xff); + *tp++ = (unsigned char) (val & 0xff); } if(colonp != NULL) { /* diff --git a/lib/inet_pton.h b/lib/inet_pton.h index 43c5491..9188d95 100644 --- a/lib/inet_pton.h +++ b/lib/inet_pton.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/krb5.c b/lib/krb5.c index ad7dd67..87ce8ee 100644 --- a/lib/krb5.c +++ b/lib/krb5.c @@ -2,7 +2,7 @@ * * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska H?gskolan * (Royal Institute of Technology, Stockholm, Sweden). - * Copyright (c) 2004 - 2015 Daniel Stenberg + * Copyright (c) 2004 - 2016 Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,15 +47,12 @@ #include "sendf.h" #include "curl_sec.h" #include "warnless.h" -#include "curl_printf.h" -/* The last #include files should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" -#define LOCAL_ADDR (&conn->local_addr) -#define REMOTE_ADDR conn->ip_addr->ai_addr - static int krb5_init(void *app_data) { @@ -153,28 +150,31 @@ krb5_auth(void *app_data, struct connectdata *conn) const char *host = conn->host.name; ssize_t nread; curl_socklen_t l = sizeof(conn->local_addr); - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result; - const char *service = "ftp", *srv_host = "host"; + const char *service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : + "ftp"; + const char *srv_host = "host"; gss_buffer_desc input_buffer, output_buffer, _gssresp, *gssresp; OM_uint32 maj, min; gss_name_t gssname; gss_ctx_id_t *context = app_data; struct gss_channel_bindings_struct chan; size_t base64_sz = 0; + struct sockaddr_in **remote_addr = + (struct sockaddr_in **)&conn->ip_addr->ai_addr; if(getsockname(conn->sock[FIRSTSOCKET], - (struct sockaddr *)LOCAL_ADDR, &l) < 0) + (struct sockaddr *)&conn->local_addr, &l) < 0) perror("getsockname()"); chan.initiator_addrtype = GSS_C_AF_INET; chan.initiator_address.length = l - 4; - chan.initiator_address.value = - &((struct sockaddr_in *)LOCAL_ADDR)->sin_addr.s_addr; + chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr; chan.acceptor_addrtype = GSS_C_AF_INET; chan.acceptor_address.length = l - 4; - chan.acceptor_address.value = - &((struct sockaddr_in *)REMOTE_ADDR)->sin_addr.s_addr; + chan.acceptor_address.value = &(*remote_addr)->sin_addr.s_addr; chan.application_data.length = 0; chan.application_data.value = NULL; @@ -183,9 +183,9 @@ krb5_auth(void *app_data, struct connectdata *conn) /* this really shouldn't be repeated here, but can't help it */ if(service == srv_host) { result = Curl_ftpsendf(conn, "AUTH GSSAPI"); - if(result) return -2; + if(Curl_GetFTPResponse(&nread, conn, NULL)) return -1; diff --git a/lib/ldap.c b/lib/ldap.c index 4d91282..a164627 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -76,9 +76,8 @@ #include "curl_base64.h" #include "rawstr.h" #include "connect.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -193,7 +192,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) LDAPMessage *ldapmsg = NULL; LDAPMessage *entryIterator; int num = 0; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; int ldap_proto = LDAP_VERSION3; int ldap_ssl = 0; char *val_b64 = NULL; @@ -228,7 +227,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) goto quit; } - /* Get the URL scheme ( either ldap or ldaps ) */ + /* Get the URL scheme (either ldap or ldaps) */ if(conn->given->flags & PROTOPT_SSL) ldap_ssl = 1; infof(data, "LDAP local: trying to establish %s connection\n", @@ -717,7 +716,7 @@ static int str2scope (const char *p) return LDAP_SCOPE_BASE; if(strequal(p, "sub")) return LDAP_SCOPE_SUBTREE; - if(strequal( p, "subtree")) + if(strequal(p, "subtree")) return LDAP_SCOPE_SUBTREE; return (-1); } diff --git a/lib/libcurl.rc b/lib/libcurl.rc index 47b944a..50b365d 100644 --- a/lib/libcurl.rc +++ b/lib/libcurl.rc @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -44,7 +44,7 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "CompanyName", "The cURL library, http://curl.haxx.se/\0" + VALUE "CompanyName", "The cURL library, https://curl.haxx.se/\0" VALUE "FileDescription", "libcurl Shared Library\0" VALUE "FileVersion", LIBCURL_VERSION "\0" VALUE "InternalName", "libcurl\0" @@ -52,7 +52,7 @@ BEGIN VALUE "ProductName", "The cURL library\0" VALUE "ProductVersion", LIBCURL_VERSION "\0" VALUE "LegalCopyright", "? " LIBCURL_COPYRIGHT "\0" - VALUE "License", "http://curl.haxx.se/docs/copyright.html\0" + VALUE "License", "https://curl.haxx.se/docs/copyright.html\0" END END diff --git a/lib/llist.c b/lib/llist.c index 40bb628..482aaa0 100644 --- a/lib/llist.c +++ b/lib/llist.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,6 +22,8 @@ #include "curl_setup.h" +#include + #include "llist.h" #include "curl_memory.h" diff --git a/lib/llist.h b/lib/llist.h index 27ddb71..39ff408 100644 --- a/lib/llist.h +++ b/lib/llist.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/md5.c b/lib/md5.c index b604c10..84adb99 100644 --- a/lib/md5.c +++ b/lib/md5.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -24,6 +24,8 @@ #ifndef CURL_DISABLE_CRYPTO_AUTH +#include + #include "curl_md5.h" #include "curl_hmac.h" #include "warnless.h" diff --git a/lib/memdebug.c b/lib/memdebug.c index dd8889b..ccbf461 100644 --- a/lib/memdebug.c +++ b/lib/memdebug.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,10 +26,12 @@ #include -#include "curl_printf.h" #include "urldata.h" #define MEMDEBUG_NODEFINES /* don't redefine the standard functions */ + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" @@ -117,7 +119,7 @@ void curl_memdebug(const char *logname) logfile = stderr; #ifdef MEMDEBUG_LOG_SYNC /* Flush the log file after every line so the log isn't lost in a crash */ - setvbuf(logfile, (char *)NULL, _IOLBF, 0); + setbuf(logfile, (char *)NULL); #endif } } @@ -146,6 +148,7 @@ static bool countcheck(const char *func, int line, const char *source) /* log to stderr also */ fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n", source, line, func); + fflush(logfile); /* because it might crash now */ } SET_ERRNO(ENOMEM); return TRUE; /* RETURN ERROR! */ @@ -153,10 +156,6 @@ static bool countcheck(const char *func, int line, const char *source) else memsize--; /* countdown */ - /* log the countdown */ - if(source) - curl_memlog("LIMIT %s:%d %ld ALLOCS left\n", - source, line, memsize); } diff --git a/lib/memdebug.h b/lib/memdebug.h index cfac1e0..835dab3 100644 --- a/lib/memdebug.h +++ b/lib/memdebug.h @@ -8,11 +8,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -28,10 +28,6 @@ * as well as the library. Do not mix with library internals! */ -#include "curl_setup.h" - -#include - #define CURL_MT_LOGFNAME_BUFSIZE 512 #define logfile curl_debuglogfile @@ -57,17 +53,17 @@ CURL_EXTERN void curl_memlog(const char *format, ...); /* file descriptor manipulators */ CURL_EXTERN curl_socket_t curl_socket(int domain, int type, int protocol, - int line , const char *source); + int line, const char *source); CURL_EXTERN void curl_mark_sclose(curl_socket_t sockfd, - int line , const char *source); + int line, const char *source); CURL_EXTERN int curl_sclose(curl_socket_t sockfd, - int line , const char *source); + int line, const char *source); CURL_EXTERN curl_socket_t curl_accept(curl_socket_t s, void *a, void *alen, int line, const char *source); #ifdef HAVE_SOCKETPAIR CURL_EXTERN int curl_socketpair(int domain, int type, int protocol, curl_socket_t socket_vector[2], - int line , const char *source); + int line, const char *source); #endif /* FILE functions */ @@ -103,6 +99,7 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source); # endif #endif +#undef socket #define socket(domain,type,protocol)\ curl_socket(domain, type, protocol, __LINE__, __FILE__) #undef accept /* for those with accept as a macro */ diff --git a/lib/mprintf.c b/lib/mprintf.c index 23070a7..73f854b 100644 --- a/lib/mprintf.c +++ b/lib/mprintf.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1999 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1999 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -32,15 +32,10 @@ * * If you ever want truly portable and good *printf() clones, the project that * took on from here is named 'Trio' and you find more details on the trio web - * page at http://daniel.haxx.se/trio/ + * page at https://daniel.haxx.se/projects/trio/ */ #include "curl_setup.h" - -#if defined(DJGPP) && (DJGPP_MINOR < 4) -#undef _MPRINTF_REPLACE /* don't use x_was_used() here */ -#endif - #include #include "curl_memory.h" @@ -465,22 +460,24 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, if(flags & FLAGS_WIDTHPARAM) { /* we have the width specified from a parameter, so we make that parameter's info setup properly */ - vto[i].width = width - 1; - i = width - 1; - vto[i].type = FORMAT_WIDTH; - vto[i].flags = FLAGS_NEW; - vto[i].precision = vto[i].width = 0; /* can't use width or precision - of width! */ + long k = width - 1; + vto[i].width = k; + vto[k].type = FORMAT_WIDTH; + vto[k].flags = FLAGS_NEW; + /* can't use width or precision of width! */ + vto[k].width = 0; + vto[k].precision = 0; } if(flags & FLAGS_PRECPARAM) { /* we have the precision specified from a parameter, so we make that parameter's info setup properly */ - vto[i].precision = precision - 1; - i = precision - 1; - vto[i].type = FORMAT_WIDTH; - vto[i].flags = FLAGS_NEW; - vto[i].precision = vto[i].width = 0; /* can't use width or precision - of width! */ + long k = precision - 1; + vto[i].precision = k; + vto[k].type = FORMAT_WIDTH; + vto[k].flags = FLAGS_NEW; + /* can't use width or precision of width! */ + vto[k].width = 0; + vto[k].precision = 0; } *endpos++ = fmt + 1; /* end of this sequence */ } @@ -488,11 +485,15 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, /* Read the arg list parameters into our data list */ for(i=0; iflags & FLAGS_WIDTHPARAM) + if(p->flags & FLAGS_WIDTHPARAM) { width = (long)vto[p->width].data.num.as_signed; + param_num++; /* since the width is extracted from a parameter, we + must skip that to get to the next one properly */ + if(width < 0) { + /* "A negative field width is taken as a '-' flag followed by a + positive field width." */ + width = -width; + p->flags |= FLAGS_LEFT; + p->flags &= ~FLAGS_PAD_NIL; + } + } else width = p->width; /* pick up the specified precision */ if(p->flags & FLAGS_PRECPARAM) { prec = (long)vto[p->precision].data.num.as_signed; - param_num++; /* since the precision is extraced from a parameter, we + param_num++; /* since the precision is extracted from a parameter, we must skip that to get to the next one properly */ + if(prec < 0) + /* "A negative precision is taken as if the precision were + omitted." */ + prec = -1; } else if(p->flags & FLAGS_PREC) prec = p->precision; @@ -715,72 +737,68 @@ static int dprintf_formatf( number: /* Number of base BASE. */ - { - char *workend = &work[sizeof(work) - 1]; - char *w; - - /* Supply a default precision if none was given. */ - if(prec == -1) - prec = 1; - - /* Put the number in WORK. */ - w = workend; - while(num > 0) { - *w-- = digits[num % base]; - num /= base; - } - width -= (long)(workend - w); - prec -= (long)(workend - w); - if(is_alt && base == 8 && prec <= 0) { - *w-- = '0'; - --width; - } + /* Supply a default precision if none was given. */ + if(prec == -1) + prec = 1; - if(prec > 0) { - width -= prec; - while(prec-- > 0) - *w-- = '0'; - } + /* Put the number in WORK. */ + w = workend; + while(num > 0) { + *w-- = digits[num % base]; + num /= base; + } + width -= (long)(workend - w); + prec -= (long)(workend - w); - if(is_alt && base == 16) - width -= 2; + if(is_alt && base == 8 && prec <= 0) { + *w-- = '0'; + --width; + } - if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE)) - --width; + if(prec > 0) { + width -= prec; + while(prec-- > 0) + *w-- = '0'; + } - if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL)) - while(width-- > 0) - OUTCHAR(' '); + if(is_alt && base == 16) + width -= 2; - if(is_neg) - OUTCHAR('-'); - else if(p->flags & FLAGS_SHOWSIGN) - OUTCHAR('+'); - else if(p->flags & FLAGS_SPACE) - OUTCHAR(' '); + if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE)) + --width; - if(is_alt && base == 16) { - OUTCHAR('0'); - if(p->flags & FLAGS_UPPER) - OUTCHAR('X'); - else - OUTCHAR('x'); - } + if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL)) + while(width-- > 0) + OUTCHAR(' '); - if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL)) - while(width-- > 0) - OUTCHAR('0'); + if(is_neg) + OUTCHAR('-'); + else if(p->flags & FLAGS_SHOWSIGN) + OUTCHAR('+'); + else if(p->flags & FLAGS_SPACE) + OUTCHAR(' '); + + if(is_alt && base == 16) { + OUTCHAR('0'); + if(p->flags & FLAGS_UPPER) + OUTCHAR('X'); + else + OUTCHAR('x'); + } - /* Write the number. */ - while(++w <= workend) { - OUTCHAR(*w); - } + if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL)) + while(width-- > 0) + OUTCHAR('0'); - if(p->flags & FLAGS_LEFT) - while(width-- > 0) - OUTCHAR(' '); + /* Write the number. */ + while(++w <= workend) { + OUTCHAR(*w); } + + if(p->flags & FLAGS_LEFT) + while(width-- > 0) + OUTCHAR(' '); break; case FORMAT_STRING: @@ -809,7 +827,7 @@ static int dprintf_formatf( else len = strlen(str); - width -= (long)len; + width -= (len > LONG_MAX) ? LONG_MAX : (long)len; if(p->flags & FLAGS_ALT) OUTCHAR('"'); diff --git a/lib/multi.c b/lib/multi.c index 0052087..8bb9366 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -42,9 +42,9 @@ #include "multihandle.h" #include "pipeline.h" #include "sigpipe.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* @@ -61,15 +61,15 @@ #define CURL_MULTI_HANDLE 0x000bab1e #define GOOD_MULTI_HANDLE(x) \ - ((x) && (((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE)) + ((x) && (x)->type == CURL_MULTI_HANDLE) static void singlesocket(struct Curl_multi *multi, - struct SessionHandle *data); + struct Curl_easy *data); static int update_timer(struct Curl_multi *multi); static CURLMcode add_next_timeout(struct timeval now, struct Curl_multi *multi, - struct SessionHandle *d); + struct Curl_easy *d); static CURLMcode multi_timeout(struct Curl_multi *multi, long *timeout_ms); @@ -99,14 +99,23 @@ static const char * const statename[]={ static void multi_freetimeout(void *a, void *b); +/* function pointer called once when switching TO a state */ +typedef void (*init_multistate_func)(struct Curl_easy *data); + /* always use this function to change state, to make debugging easier */ -static void mstate(struct SessionHandle *data, CURLMstate state +static void mstate(struct Curl_easy *data, CURLMstate state #ifdef DEBUGBUILD , int lineno #endif ) { CURLMstate oldstate = data->mstate; + static const init_multistate_func finit[CURLM_STATE_LAST] = { + NULL, + NULL, + Curl_init_CONNECT, /* CONNECT */ + /* the rest is NULL too */ + }; #if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS) (void) lineno; @@ -127,7 +136,7 @@ static void mstate(struct SessionHandle *data, CURLMstate state connection_id = data->easy_conn->connection_id; infof(data, - "STATE: %s => %s handle %p; line %d (connection #%ld) \n", + "STATE: %s => %s handle %p; line %d (connection #%ld)\n", statename[oldstate], statename[data->mstate], (void *)data, lineno, connection_id); } @@ -136,6 +145,10 @@ static void mstate(struct SessionHandle *data, CURLMstate state if(state == CURLM_STATE_COMPLETED) /* changing to COMPLETED means there's one less easy handle 'alive' */ data->multi->num_alive--; + + /* if this state has an init-function, run it */ + if(finit[state]) + finit[state](data); } #ifndef DEBUGBUILD @@ -149,7 +162,7 @@ static void mstate(struct SessionHandle *data, CURLMstate state */ struct Curl_sh_entry { - struct SessionHandle *easy; + struct Curl_easy *easy; int action; /* what action READ/WRITE this socket waits for */ curl_socket_t socket; /* mainly to ease debugging */ void *socketp; /* settable by users with curl_multi_assign() */ @@ -159,13 +172,22 @@ struct Curl_sh_entry { #define SH_READ 1 #define SH_WRITE 2 +/* look up a given socket in the socket hash, skip invalid sockets */ +static struct Curl_sh_entry *sh_getentry(struct curl_hash *sh, + curl_socket_t s) +{ + if(s != CURL_SOCKET_BAD) + /* only look for proper sockets */ + return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t)); + return NULL; +} + /* make sure this socket is present in the hash for this handle */ static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh, curl_socket_t s, - struct SessionHandle *data) + struct Curl_easy *data) { - struct Curl_sh_entry *there = - Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t)); + struct Curl_sh_entry *there = sh_getentry(sh, s); struct Curl_sh_entry *check; if(there) @@ -193,15 +215,9 @@ static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh, /* delete the given socket + handle from the hash */ static void sh_delentry(struct curl_hash *sh, curl_socket_t s) { - struct Curl_sh_entry *there = - Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t)); - - if(there) { - /* this socket is in the hash */ - /* We remove the hash entry. (This'll end up in a call to - sh_freeentry().) */ - Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t)); - } + /* We remove the hash entry. This will end up in a call to + sh_freeentry(). */ + Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t)); } /* @@ -218,15 +234,15 @@ static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len) { (void) k1_len; (void) k2_len; - return (*((int *) k1)) == (*((int *) k2)); + return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2)); } static size_t hash_fd(void *key, size_t key_length, size_t slots_num) { - int fd = *((int *) key); + curl_socket_t fd = *((curl_socket_t *) key); (void) key_length; - return (fd % (int)slots_num); + return (fd % slots_num); } /* @@ -318,7 +334,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ /* -1 means it not set by user, use the default value */ multi->maxconnects = -1; - return (CURLM *) multi; + return multi; error: @@ -334,25 +350,23 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ return NULL; } -CURLM *curl_multi_init(void) +struct Curl_multi *curl_multi_init(void) { return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE, CURL_CONNECTION_HASH_SIZE); } -CURLMcode curl_multi_add_handle(CURLM *multi_handle, - CURL *easy_handle) +CURLMcode curl_multi_add_handle(struct Curl_multi *multi, + struct Curl_easy *data) { struct curl_llist *timeoutlist; - struct Curl_multi *multi = (struct Curl_multi *)multi_handle; - struct SessionHandle *data = (struct SessionHandle *)easy_handle; /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; /* Verify that we got a somewhat good easy handle too */ - if(!GOOD_EASY_HANDLE(easy_handle)) + if(!GOOD_EASY_HANDLE(data)) return CURLM_BAD_EASY_HANDLE; /* Prevent users from adding same easy handle more than once and prevent @@ -401,14 +415,14 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, data->state.conn_cache = &multi->conn_cache; /* This adds the new entry at the 'end' of the doubly-linked circular - list of SessionHandle structs to try and maintain a FIFO queue so + list of Curl_easy structs to try and maintain a FIFO queue so the pipelined requests are in order. */ /* We add this new entry last in the list. */ data->next = NULL; /* end of the line */ if(multi->easyp) { - struct SessionHandle *last = multi->easylp; + struct Curl_easy *last = multi->easylp; last->next = data; data->prev = last; multi->easylp = data; /* the new last node */ @@ -419,8 +433,8 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, multi->easylp = multi->easyp = data; /* both first and last */ } - /* make the SessionHandle refer back to this multi handle */ - data->multi = multi_handle; + /* make the Curl_easy refer back to this multi handle */ + data->multi = multi; /* Set the timeout for this handle to expire really soon so that it will be taken care of even when this handle is added in the midst of operation @@ -468,12 +482,171 @@ static void debug_print_sock_hash(void *p) } #endif -CURLMcode curl_multi_remove_handle(CURLM *multi_handle, - CURL *curl_handle) +/* Mark the connection as 'idle', or close it if the cache is full. + Returns TRUE if the connection is kept, or FALSE if it was closed. */ +static bool +ConnectionDone(struct Curl_easy *data, struct connectdata *conn) +{ + /* data->multi->maxconnects can be negative, deal with it. */ + size_t maxconnects = + (data->multi->maxconnects < 0) ? data->multi->num_easy * 4: + data->multi->maxconnects; + struct connectdata *conn_candidate = NULL; + + /* Mark the current connection as 'unused' */ + conn->inuse = FALSE; + + if(maxconnects > 0 && + data->state.conn_cache->num_connections > maxconnects) { + infof(data, "Connection cache is full, closing the oldest one.\n"); + + conn_candidate = Curl_oldest_idle_connection(data); + + if(conn_candidate) { + /* Set the connection's owner correctly */ + conn_candidate->data = data; + + /* the winner gets the honour of being disconnected */ + (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE); + } + } + + return (conn_candidate == conn) ? FALSE : TRUE; +} + +static CURLcode multi_done(struct connectdata **connp, + CURLcode status, /* an error if this is called + after an error was detected */ + bool premature) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct SessionHandle *easy = curl_handle; - struct SessionHandle *data = easy; + CURLcode result; + struct connectdata *conn; + struct Curl_easy *data; + + DEBUGASSERT(*connp); + + conn = *connp; + data = conn->data; + + DEBUGF(infof(data, "multi_done\n")); + + if(data->state.done) + /* Stop if multi_done() has already been called */ + return CURLE_OK; + + Curl_getoff_all_pipelines(data, conn); + + /* Cleanup possible redirect junk */ + free(data->req.newurl); + data->req.newurl = NULL; + free(data->req.location); + data->req.location = NULL; + + switch(status) { + case CURLE_ABORTED_BY_CALLBACK: + case CURLE_READ_ERROR: + case CURLE_WRITE_ERROR: + /* When we're aborted due to a callback return code it basically have to + be counted as premature as there is trouble ahead if we don't. We have + many callbacks and protocols work differently, we could potentially do + this more fine-grained in the future. */ + premature = TRUE; + default: + break; + } + + /* this calls the protocol-specific function pointer previously set */ + if(conn->handler->done) + result = conn->handler->done(conn, status, premature); + else + result = status; + + if(CURLE_ABORTED_BY_CALLBACK != result) { + /* avoid this if we already aborted by callback to avoid this calling + another callback */ + CURLcode rc = Curl_pgrsDone(conn); + if(!result && rc) + result = CURLE_ABORTED_BY_CALLBACK; + } + + if((!premature && + conn->send_pipe->size + conn->recv_pipe->size != 0 && + !data->set.reuse_forbid && + !conn->bits.close)) { + /* Stop if pipeline is not empty and we do not have to close + connection. */ + DEBUGF(infof(data, "Connection still in use, no more multi_done now!\n")); + return CURLE_OK; + } + + data->state.done = TRUE; /* called just now! */ + Curl_resolver_cancel(conn); + + if(conn->dns_entry) { + Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ + conn->dns_entry = NULL; + } + + /* if the transfer was completed in a paused state there can be buffered + data left to write and then kill */ + free(data->state.tempwrite); + data->state.tempwrite = NULL; + + /* if data->set.reuse_forbid is TRUE, it means the libcurl client has + forced us to close this connection. This is ignored for requests taking + place in a NTLM authentication handshake + + if conn->bits.close is TRUE, it means that the connection should be + closed in spite of all our efforts to be nice, due to protocol + restrictions in our or the server's end + + if premature is TRUE, it means this connection was said to be DONE before + the entire request operation is complete and thus we can't know in what + state it is for re-using, so we're forced to close it. In a perfect world + we can add code that keep track of if we really must close it here or not, + but currently we have no such detail knowledge. + */ + + if((data->set.reuse_forbid +#if defined(USE_NTLM) + && !(conn->ntlm.state == NTLMSTATE_TYPE2 || + conn->proxyntlm.state == NTLMSTATE_TYPE2) +#endif + ) || conn->bits.close || premature) { + CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */ + + /* If we had an error already, make sure we return that one. But + if we got a new error, return that. */ + if(!result && res2) + result = res2; + } + else { + /* the connection is no longer in use */ + if(ConnectionDone(data, conn)) { + /* remember the most recently used connection */ + data->state.lastconnect = conn; + + infof(data, "Connection #%ld to host %s left intact\n", + conn->connection_id, + conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname); + } + else + data->state.lastconnect = NULL; + } + + *connp = NULL; /* to make the caller of this function better detect that + this was either closed or handed over to the connection + cache here, and therefore cannot be used from this point on + */ + Curl_free_request_state(data); + + return result; +} + +CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, + struct Curl_easy *data) +{ + struct Curl_easy *easy = data; bool premature; bool easy_owns_conn; struct curl_llist_element *e; @@ -483,7 +656,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, return CURLM_BAD_HANDLE; /* Verify that we got a somewhat good easy handle too */ - if(!GOOD_EASY_HANDLE(curl_handle)) + if(!GOOD_EASY_HANDLE(data)) return CURLM_BAD_EASY_HANDLE; /* Prevent users from trying to remove same easy handle more than once */ @@ -513,8 +686,8 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, request but not received its response yet, we need to close connection. */ connclose(data->easy_conn, "Removed with partial response"); - /* Set connection owner so that Curl_done() closes it. - We can safely do this here since connection is killed. */ + /* Set connection owner so that the DONE function closes it. We can + safely do this here since connection is killed. */ data->easy_conn->data = easy; easy_owns_conn = TRUE; } @@ -524,12 +697,6 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, curl_easy_cleanup is called. */ Curl_expire(data, 0); - /* destroy the timeout list that is held in the easy handle */ - if(data->state.timeoutlist) { - Curl_llist_destroy(data->state.timeoutlist, NULL); - data->state.timeoutlist = NULL; - } - if(data->dns.hostcachetype == HCACHE_MULTI) { /* stop using the multi handle's DNS cache */ data->dns.hostcache = NULL; @@ -538,24 +705,31 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, if(data->easy_conn) { - /* we must call Curl_done() here (if we still "own it") so that we don't - leave a half-baked one around */ + /* we must call multi_done() here (if we still own the connection) so that + we don't leave a half-baked one around */ if(easy_owns_conn) { - /* Curl_done() clears the conn->data field to lose the association + /* multi_done() clears the conn->data field to lose the association between the easy handle and the connection Note that this ignores the return code simply because there's nothing really useful to do with it anyway! */ - (void)Curl_done(&data->easy_conn, data->result, premature); + (void)multi_done(&data->easy_conn, data->result, premature); } else - /* Clear connection pipelines, if Curl_done above was not called */ + /* Clear connection pipelines, if multi_done above was not called */ Curl_getoff_all_pipelines(data, data->easy_conn); } Curl_wildcard_dtor(&data->wildcard); + /* destroy the timeout list that is held in the easy handle, do this *after* + multi_done() as that may actually call Curl_expire that uses this */ + if(data->state.timeoutlist) { + Curl_llist_destroy(data->state.timeoutlist, NULL); + data->state.timeoutlist = NULL; + } + /* as this was using a shared connection cache we clear the pointer to that since we're not part of that multi handle anymore */ data->state.conn_cache = NULL; @@ -613,7 +787,7 @@ bool Curl_pipeline_wanted(const struct Curl_multi *multi, int bits) return (multi && (multi->pipelining & bits)) ? TRUE : FALSE; } -void Curl_multi_handlePipeBreak(struct SessionHandle *data) +void Curl_multi_handlePipeBreak(struct Curl_easy *data) { data->easy_conn = NULL; } @@ -666,7 +840,7 @@ static int domore_getsock(struct connectdata *conn, } /* returns bitmapped flags for this handle and its sockets */ -static int multi_getsock(struct SessionHandle *data, +static int multi_getsock(struct Curl_easy *data, curl_socket_t *socks, /* points to numsocks number of sockets */ int numsocks) @@ -732,15 +906,14 @@ static int multi_getsock(struct SessionHandle *data, } -CURLMcode curl_multi_fdset(CURLM *multi_handle, +CURLMcode curl_multi_fdset(struct Curl_multi *multi, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *exc_fd_set, int *max_fd) { /* Scan through all the easy handles to get the file descriptors set. Some easy handles may not have connected to the remote host yet, and then we must make sure that is done. */ - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct SessionHandle *data; + struct Curl_easy *data; int this_max_fd=-1; curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; int bitmap; @@ -782,14 +955,13 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle, return CURLM_OK; } -CURLMcode curl_multi_wait(CURLM *multi_handle, +CURLMcode curl_multi_wait(struct Curl_multi *multi, struct curl_waitfd extra_fds[], unsigned int extra_nfds, int timeout_ms, int *ret) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct SessionHandle *data; + struct Curl_easy *data; curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; int bitmap; unsigned int i; @@ -797,6 +969,7 @@ CURLMcode curl_multi_wait(CURLM *multi_handle, unsigned int curlfds; struct pollfd *ufds = NULL; long timeout_internal; + int retcode = 0; if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; @@ -889,18 +1062,20 @@ CURLMcode curl_multi_wait(CURLM *multi_handle, } if(nfds) { + int pollrc; /* wait... */ - infof(data, "Curl_poll(%d ds, %d ms)\n", nfds, timeout_ms); - i = Curl_poll(ufds, nfds, timeout_ms); + pollrc = Curl_poll(ufds, nfds, timeout_ms); + DEBUGF(infof(data, "Curl_poll(%d ds, %d ms) == %d\n", + nfds, timeout_ms, pollrc)); - if(i) { - unsigned int j; + if(pollrc > 0) { + retcode = pollrc; /* copy revents results from the poll to the curl_multi_wait poll struct, the bit values of the actual underlying poll() implementation may not be the same as the ones in the public libcurl API! */ - for(j = 0; j < extra_nfds; j++) { + for(i = 0; i < extra_nfds; i++) { unsigned short mask = 0; - unsigned r = ufds[curlfds + j].revents; + unsigned r = ufds[curlfds + i].revents; if(r & POLLIN) mask |= CURL_WAIT_POLLIN; @@ -909,16 +1084,14 @@ CURLMcode curl_multi_wait(CURLM *multi_handle, if(r & POLLPRI) mask |= CURL_WAIT_POLLPRI; - extra_fds[j].revents = mask; + extra_fds[i].revents = mask; } } } - else - i = 0; free(ufds); if(ret) - *ret = i; + *ret = retcode; return CURLM_OK; } @@ -951,7 +1124,7 @@ static bool multi_ischanged(struct Curl_multi *multi, bool clear) } CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, - struct SessionHandle *data, + struct Curl_easy *data, struct connectdata *conn) { CURLMcode rc; @@ -972,9 +1145,142 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, return rc; } +static CURLcode multi_reconnect_request(struct connectdata **connp) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = *connp; + struct Curl_easy *data = conn->data; + + /* This was a re-use of a connection and we got a write error in the + * DO-phase. Then we DISCONNECT this connection and have another attempt to + * CONNECT and then DO again! The retry cannot possibly find another + * connection to re-use, since we only keep one possible connection for + * each. */ + + infof(data, "Re-used connection seems dead, get a new one\n"); + + connclose(conn, "Reconnect dead connection"); /* enforce close */ + result = multi_done(&conn, result, FALSE); /* we are so done with this */ + + /* conn may no longer be a good pointer, clear it to avoid mistakes by + parent functions */ + *connp = NULL; + + /* + * We need to check for CURLE_SEND_ERROR here as well. This could happen + * when the request failed on a FTP connection and thus multi_done() itself + * tried to use the connection (again). + */ + if(!result || (CURLE_SEND_ERROR == result)) { + bool async; + bool protocol_done = TRUE; + + /* Now, redo the connect and get a new connection */ + result = Curl_connect(data, connp, &async, &protocol_done); + if(!result) { + /* We have connected or sent away a name resolve query fine */ + + conn = *connp; /* setup conn to again point to something nice */ + if(async) { + /* Now, if async is TRUE here, we need to wait for the name + to resolve */ + result = Curl_resolver_wait_resolv(conn, NULL); + if(result) + return result; + + /* Resolved, continue with the connection */ + result = Curl_async_resolved(conn, &protocol_done); + if(result) + return result; + } + } + } + + return result; +} + +/* + * do_complete is called when the DO actions are complete. + * + * We init chunking and trailer bits to their default values here immediately + * before receiving any header data for the current request in the pipeline. + */ +static void do_complete(struct connectdata *conn) +{ + conn->data->req.chunk=FALSE; + conn->data->req.maxfd = (conn->sockfd>conn->writesockfd? + conn->sockfd:conn->writesockfd)+1; + Curl_pgrsTime(conn->data, TIMER_PRETRANSFER); +} + +static CURLcode multi_do(struct connectdata **connp, bool *done) +{ + CURLcode result=CURLE_OK; + struct connectdata *conn = *connp; + struct Curl_easy *data = conn->data; + + if(conn->handler->do_it) { + /* generic protocol-specific function pointer set in curl_connect() */ + result = conn->handler->do_it(conn, done); + + /* This was formerly done in transfer.c, but we better do it here */ + if((CURLE_SEND_ERROR == result) && conn->bits.reuse) { + /* + * If the connection is using an easy handle, call reconnect + * to re-establish the connection. Otherwise, let the multi logic + * figure out how to re-establish the connection. + */ + if(!data->multi) { + result = multi_reconnect_request(connp); + + if(!result) { + /* ... finally back to actually retry the DO phase */ + conn = *connp; /* re-assign conn since multi_reconnect_request + creates a new connection */ + result = conn->handler->do_it(conn, done); + } + } + else + return result; + } + + if(!result && *done) + /* do_complete must be called after the protocol-specific DO function */ + do_complete(conn); + } + return result; +} + +/* + * multi_do_more() is called during the DO_MORE multi state. It is basically a + * second stage DO state which (wrongly) was introduced to support FTP's + * second connection. + * + * TODO: A future libcurl should be able to work away this state. + * + * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to + * DOING state there's more work to do! + */ + +static CURLcode multi_do_more(struct connectdata *conn, int *complete) +{ + CURLcode result=CURLE_OK; + + *complete = 0; + + if(conn->handler->do_more) + result = conn->handler->do_more(conn, complete); + + if(!result && (*complete == 1)) + /* do_complete must be called after the protocol-specific DO function */ + do_complete(conn); + + return result; +} + static CURLMcode multi_runsingle(struct Curl_multi *multi, struct timeval now, - struct SessionHandle *data) + struct Curl_easy *data) { struct Curl_message *msg = NULL; bool connected; @@ -1057,7 +1363,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, failf(data, "Operation timed out after %ld milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %" CURL_FORMAT_CURL_OFF_T " bytes received", - Curl_tvdiff(k->now, data->progress.t_startsingle), + Curl_tvdiff(now, data->progress.t_startsingle), k->bytecount, k->size); } else { @@ -1074,7 +1380,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, disconnect_conn = TRUE; } result = CURLE_OPERATION_TIMEDOUT; - (void)Curl_done(&data->easy_conn, result, TRUE); + (void)multi_done(&data->easy_conn, result, TRUE); /* Skip the statemachine and go directly to error handling section. */ goto statemachine_end; } @@ -1152,9 +1458,17 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, { struct Curl_dns_entry *dns = NULL; struct connectdata *conn = data->easy_conn; + const char *hostname; + + if(conn->bits.proxy) + hostname = conn->proxy.name; + else if(conn->bits.conn_to_host) + hostname = conn->conn_to_host.name; + else + hostname = conn->host.name; /* check if we have the name resolved by now */ - dns = Curl_fetch_addr(conn, conn->host.name, (int)conn->port); + dns = Curl_fetch_addr(conn, hostname, (int)conn->port); if(dns) { #ifdef CURLRES_ASYNCH @@ -1162,7 +1476,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, conn->async.done = TRUE; #endif result = CURLE_OK; - infof(data, "Hostname was found in DNS cache\n"); + infof(data, "Hostname '%s' was found in DNS cache\n", hostname); } if(!dns) @@ -1215,17 +1529,19 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */ result = Curl_http_connect(data->easy_conn, &protocol_connect); - rc = CURLM_CALL_MULTI_PERFORM; if(data->easy_conn->bits.proxy_connect_closed) { + rc = CURLM_CALL_MULTI_PERFORM; /* connect back to proxy again */ result = CURLE_OK; - Curl_done(&data->easy_conn, CURLE_OK, FALSE); + multi_done(&data->easy_conn, CURLE_OK, FALSE); multistate(data, CURLM_STATE_CONNECT); } else if(!result) { - if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_COMPLETE) + if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_COMPLETE) { + rc = CURLM_CALL_MULTI_PERFORM; /* initiate protocol connect phase */ multistate(data, CURLM_STATE_SENDPROTOCONNECT); + } } break; #endif @@ -1261,7 +1577,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else if(result) { /* failure detected */ Curl_posttransfer(data); - Curl_done(&data->easy_conn, result, TRUE); + multi_done(&data->easy_conn, result, TRUE); disconnect_conn = TRUE; } break; @@ -1278,7 +1594,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else if(result) { /* failure detected */ Curl_posttransfer(data); - Curl_done(&data->easy_conn, result, TRUE); + multi_done(&data->easy_conn, result, TRUE); disconnect_conn = TRUE; } break; @@ -1302,9 +1618,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } else { /* Perform the protocol's DO action */ - result = Curl_do(&data->easy_conn, &dophase_done); + result = multi_do(&data->easy_conn, &dophase_done); - /* When Curl_do() returns failure, data->easy_conn might be NULL! */ + /* When multi_do() returns failure, data->easy_conn might be NULL! */ if(!result) { if(!dophase_done) { @@ -1313,7 +1629,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, struct WildcardData *wc = &data->wildcard; if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) { /* skip some states if it is important */ - Curl_done(&data->easy_conn, CURLE_OK, FALSE); + multi_done(&data->easy_conn, CURLE_OK, FALSE); multistate(data, CURLM_STATE_DONE); rc = CURLM_CALL_MULTI_PERFORM; break; @@ -1360,7 +1676,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, retry = (newurl)?TRUE:FALSE; Curl_posttransfer(data); - drc = Curl_done(&data->easy_conn, result, FALSE); + drc = multi_done(&data->easy_conn, result, FALSE); /* When set to retry the connection, we must to go back to * the CONNECT state */ @@ -1395,7 +1711,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* failure detected */ Curl_posttransfer(data); if(data->easy_conn) - Curl_done(&data->easy_conn, result, FALSE); + multi_done(&data->easy_conn, result, FALSE); disconnect_conn = TRUE; } } @@ -1417,7 +1733,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else { /* failure detected */ Curl_posttransfer(data); - Curl_done(&data->easy_conn, result, FALSE); + multi_done(&data->easy_conn, result, FALSE); disconnect_conn = TRUE; } break; @@ -1426,10 +1742,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* * When we are connected, DO MORE and then go DO_DONE */ - result = Curl_do_more(data->easy_conn, &control); + result = multi_do_more(data->easy_conn, &control); /* No need to remove this handle from the send pipeline here since that - is done in Curl_done() */ + is done in multi_done() */ if(!result) { if(control) { /* if positive, advance to DO_DONE @@ -1446,7 +1762,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else { /* failure detected */ Curl_posttransfer(data); - Curl_done(&data->easy_conn, result, FALSE); + multi_done(&data->easy_conn, result, FALSE); disconnect_conn = TRUE; } break; @@ -1484,7 +1800,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, result = Curl_speedcheck(data, now); if(( (data->set.max_send_speed == 0) || - (data->progress.ulspeed < data->set.max_send_speed )) && + (data->progress.ulspeed < data->set.max_send_speed)) && ( (data->set.max_recv_speed == 0) || (data->progress.dlspeed < data->set.max_recv_speed))) multistate(data, CURLM_STATE_PERFORM); @@ -1566,11 +1882,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, * happened in the data connection. */ - if(!(data->easy_conn->handler->flags & PROTOPT_DUAL)) + if(!(data->easy_conn->handler->flags & PROTOPT_DUAL) && + result != CURLE_HTTP2_STREAM) connclose(data->easy_conn, "Transfer returned error"); Curl_posttransfer(data); - Curl_done(&data->easy_conn, result, FALSE); + multi_done(&data->easy_conn, result, FALSE); } else if(done) { followtype follow=FOLLOW_NONE; @@ -1601,7 +1918,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } else follow = FOLLOW_RETRY; - result = Curl_done(&data->easy_conn, CURLE_OK, FALSE); + result = multi_done(&data->easy_conn, CURLE_OK, FALSE); if(!result) { result = Curl_follow(data, newurl, follow); if(!result) { @@ -1651,14 +1968,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, Curl_multi_process_pending_handles(multi); /* post-transfer command */ - res = Curl_done(&data->easy_conn, result, FALSE); + res = multi_done(&data->easy_conn, result, FALSE); /* allow a previously set error code take precedence */ if(!result) result = res; /* - * If there are other handles on the pipeline, Curl_done won't set + * If there are other handles on the pipeline, multi_done won't set * easy_conn to NULL. In such a case, curl_multi_remove_handle() can * access free'd data, if the connection is free'd and the handle * removed before we perform the processing in CURLM_STATE_COMPLETED @@ -1677,7 +1994,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } /* after we have DONE what we're supposed to do, go COMPLETED, and - it doesn't matter what the Curl_done() returned! */ + it doesn't matter what the multi_done() returned! */ multistate(data, CURLM_STATE_COMPLETED); break; @@ -1779,10 +2096,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } -CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) +CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct SessionHandle *data; + struct Curl_easy *data; CURLMcode returncode=CURLM_OK; struct Curl_tree *t; struct timeval now = Curl_tvnow(); @@ -1793,27 +2109,12 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) data=multi->easyp; while(data) { CURLMcode result; - struct WildcardData *wc = &data->wildcard; SIGPIPE_VARIABLE(pipe_st); - if(data->set.wildcardmatch) { - if(!wc->filelist) { - CURLcode ret = Curl_wildcard_init(wc); /* init wildcard structures */ - if(ret) - return CURLM_OUT_OF_MEMORY; - } - } - sigpipe_ignore(data, &pipe_st); result = multi_runsingle(multi, now, data); sigpipe_restore(&pipe_st); - if(data->set.wildcardmatch) { - /* destruct wildcard structures if it is needed */ - if(wc->state == CURLWC_DONE || result) - Curl_wildcard_dtor(wc); - } - if(result) returncode = result; @@ -1856,6 +2157,8 @@ static void close_all_connections(struct Curl_multi *multi) conn->data = multi->closure_handle; sigpipe_ignore(conn->data, &pipe_st); + conn->data->easy_conn = NULL; /* clear the easy handle's connection + pointer */ /* This will remove the connection from the cache */ (void)Curl_disconnect(conn, FALSE); sigpipe_restore(&pipe_st); @@ -1864,11 +2167,10 @@ static void close_all_connections(struct Curl_multi *multi) } } -CURLMcode curl_multi_cleanup(CURLM *multi_handle) +CURLMcode curl_multi_cleanup(struct Curl_multi *multi) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct SessionHandle *data; - struct SessionHandle *nextdata; + struct Curl_easy *data; + struct Curl_easy *nextdata; if(GOOD_MULTI_HANDLE(multi)) { bool restore_pipe = FALSE; @@ -1939,9 +2241,8 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle) * beyond. The current design is fully O(1). */ -CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue) +CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; struct Curl_message *msg; *msgs_in_queue = 0; /* default to none */ @@ -1972,7 +2273,7 @@ CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue) * call the callback accordingly. */ static void singlesocket(struct Curl_multi *multi, - struct SessionHandle *data) + struct Curl_easy *data) { curl_socket_t socks[MAX_SOCKSPEREASYHANDLE]; int i; @@ -1980,7 +2281,6 @@ static void singlesocket(struct Curl_multi *multi, curl_socket_t s; int num; unsigned int curraction; - bool remove_sock_from_hash; for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) socks[i] = CURL_SOCKET_BAD; @@ -2002,7 +2302,7 @@ static void singlesocket(struct Curl_multi *multi, s = socks[i]; /* get it from the hash */ - entry = Curl_hash_pick(&multi->sockhash, (char *)&s, sizeof(s)); + entry = sh_getentry(&multi->sockhash, s); if(curraction & GETSOCK_READSOCK(i)) action |= CURL_POLL_IN; @@ -2048,57 +2348,50 @@ static void singlesocket(struct Curl_multi *multi, break; } } - if(s != CURL_SOCKET_BAD) { + entry = sh_getentry(&multi->sockhash, s); + if(entry) { /* this socket has been removed. Tell the app to remove it */ - remove_sock_from_hash = TRUE; - - entry = Curl_hash_pick(&multi->sockhash, (char *)&s, sizeof(s)); - if(entry) { - /* check if the socket to be removed serves a connection which has - other easy-s in a pipeline. In this case the socket should not be - removed. */ - struct connectdata *easy_conn = data->easy_conn; - if(easy_conn) { - if(easy_conn->recv_pipe && easy_conn->recv_pipe->size > 1) { - /* the handle should not be removed from the pipe yet */ - remove_sock_from_hash = FALSE; - - /* Update the sockhash entry to instead point to the next in line - for the recv_pipe, or the first (in case this particular easy - isn't already) */ - if(entry->easy == data) { - if(Curl_recvpipe_head(data, easy_conn)) - entry->easy = easy_conn->recv_pipe->head->next->ptr; - else - entry->easy = easy_conn->recv_pipe->head->ptr; - } + bool remove_sock_from_hash = TRUE; + + /* check if the socket to be removed serves a connection which has + other easy-s in a pipeline. In this case the socket should not be + removed. */ + struct connectdata *easy_conn = data->easy_conn; + if(easy_conn) { + if(easy_conn->recv_pipe && easy_conn->recv_pipe->size > 1) { + /* the handle should not be removed from the pipe yet */ + remove_sock_from_hash = FALSE; + + /* Update the sockhash entry to instead point to the next in line + for the recv_pipe, or the first (in case this particular easy + isn't already) */ + if(entry->easy == data) { + if(Curl_recvpipe_head(data, easy_conn)) + entry->easy = easy_conn->recv_pipe->head->next->ptr; + else + entry->easy = easy_conn->recv_pipe->head->ptr; } - if(easy_conn->send_pipe && easy_conn->send_pipe->size > 1) { - /* the handle should not be removed from the pipe yet */ - remove_sock_from_hash = FALSE; - - /* Update the sockhash entry to instead point to the next in line - for the send_pipe, or the first (in case this particular easy - isn't already) */ - if(entry->easy == data) { - if(Curl_sendpipe_head(data, easy_conn)) - entry->easy = easy_conn->send_pipe->head->next->ptr; - else - entry->easy = easy_conn->send_pipe->head->ptr; - } + } + if(easy_conn->send_pipe && easy_conn->send_pipe->size > 1) { + /* the handle should not be removed from the pipe yet */ + remove_sock_from_hash = FALSE; + + /* Update the sockhash entry to instead point to the next in line + for the send_pipe, or the first (in case this particular easy + isn't already) */ + if(entry->easy == data) { + if(Curl_sendpipe_head(data, easy_conn)) + entry->easy = easy_conn->send_pipe->head->next->ptr; + else + entry->easy = easy_conn->send_pipe->head->ptr; } - /* Don't worry about overwriting recv_pipe head with send_pipe_head, - when action will be asked on the socket (see multi_socket()), the - head of the correct pipe will be taken according to the - action. */ } + /* Don't worry about overwriting recv_pipe head with send_pipe_head, + when action will be asked on the socket (see multi_socket()), the + head of the correct pipe will be taken according to the + action. */ } - else - /* just a precaution, this socket really SHOULD be in the hash already - but in case it isn't, we don't have to tell the app to remove it - either since it never got to know about it */ - remove_sock_from_hash = FALSE; if(remove_sock_from_hash) { /* in this case 'entry' is always non-NULL */ @@ -2110,9 +2403,8 @@ static void singlesocket(struct Curl_multi *multi, entry->socketp); sh_delentry(&multi->sockhash, s); } - - } - } + } /* if sockhash entry existed */ + } /* for loop over numsocks */ memcpy(data->sockets, socks, num*sizeof(curl_socket_t)); data->numsocks = num; @@ -2134,8 +2426,7 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s) if(multi) { /* this is set if this connection is part of a handle that is added to a multi handle, and only then this is necessary */ - struct Curl_sh_entry *entry = - Curl_hash_pick(&multi->sockhash, (char *)&s, sizeof(s)); + struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); if(entry) { if(multi->socket_cb) @@ -2154,7 +2445,7 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s) /* * add_next_timeout() * - * Each SessionHandle has a list of timeouts. The add_next_timeout() is called + * Each Curl_easy has a list of timeouts. The add_next_timeout() is called * when it has just been removed from the splay tree because the timeout has * expired. This function is then to advance in the list to pick the next * timeout to use (skip the already expired ones) and add this node back to @@ -2165,7 +2456,7 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s) */ static CURLMcode add_next_timeout(struct timeval now, struct Curl_multi *multi, - struct SessionHandle *d) + struct Curl_easy *d) { struct timeval *tv = &d->state.expiretime; struct curl_llist *list = d->state.timeoutlist; @@ -2174,7 +2465,7 @@ static CURLMcode add_next_timeout(struct timeval now, /* move over the timeout list for this specific handle and remove all timeouts that are now passed tense and store the next pending timeout in *tv */ - for(e = list->head; e; ) { + for(e = list->head; e;) { struct curl_llist_element *n = e->next; long diff = curlx_tvdiff(*(struct timeval *)e->ptr, now); if(diff <= 0) @@ -2213,7 +2504,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, int *running_handles) { CURLMcode result = CURLM_OK; - struct SessionHandle *data = NULL; + struct Curl_easy *data = NULL; struct Curl_tree *t; struct timeval now = Curl_tvnow(); @@ -2236,8 +2527,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, } else if(s != CURL_SOCKET_TIMEOUT) { - struct Curl_sh_entry *entry = - Curl_hash_pick(&multi->sockhash, (char *)&s, sizeof(s)); + struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); if(!entry) /* Unmatched socket, we can't act on it but we ignore this fact. In @@ -2342,10 +2632,9 @@ static CURLMcode multi_socket(struct Curl_multi *multi, } #undef curl_multi_setopt -CURLMcode curl_multi_setopt(CURLM *multi_handle, +CURLMcode curl_multi_setopt(struct Curl_multi *multi, CURLMoption option, ...) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; CURLMcode res = CURLM_OK; va_list param; @@ -2413,33 +2702,32 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle, /* we define curl_multi_socket() in the public multi.h header */ #undef curl_multi_socket -CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, +CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s, int *running_handles) { - CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s, - 0, running_handles); + CURLMcode result = multi_socket(multi, FALSE, s, 0, running_handles); if(CURLM_OK >= result) - update_timer((struct Curl_multi *)multi_handle); + update_timer(multi); return result; } -CURLMcode curl_multi_socket_action(CURLM *multi_handle, curl_socket_t s, +CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s, int ev_bitmask, int *running_handles) { - CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s, + CURLMcode result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles); if(CURLM_OK >= result) - update_timer((struct Curl_multi *)multi_handle); + update_timer(multi); return result; } -CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles) +CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles) { - CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, - TRUE, CURL_SOCKET_BAD, 0, running_handles); + CURLMcode result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, + running_handles); if(CURLM_OK >= result) - update_timer((struct Curl_multi *)multi_handle); + update_timer(multi); return result; } @@ -2478,11 +2766,9 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, return CURLM_OK; } -CURLMcode curl_multi_timeout(CURLM *multi_handle, +CURLMcode curl_multi_timeout(struct Curl_multi *multi, long *timeout_ms) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; @@ -2509,7 +2795,7 @@ static int update_timer(struct Curl_multi *multi) multi->timer_lastcall = none; /* there's no timeout now but there was one previously, tell the app to disable it */ - return multi->timer_cb((CURLM*)multi, -1, multi->timer_userp); + return multi->timer_cb(multi, -1, multi->timer_userp); } return 0; } @@ -2523,7 +2809,7 @@ static int update_timer(struct Curl_multi *multi) multi->timer_lastcall = multi->timetree->key; - return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp); + return multi->timer_cb(multi, timeout_ms, multi->timer_userp); } /* @@ -2595,7 +2881,7 @@ multi_addtimeout(struct curl_llist *timeoutlist, * * Pass zero to clear all timeout values for this handle. */ -void Curl_expire(struct SessionHandle *data, long milli) +void Curl_expire(struct Curl_easy *data, long milli) { struct Curl_multi *multi = data->multi; struct timeval *nowp = &data->state.expiretime; @@ -2689,7 +2975,7 @@ void Curl_expire(struct SessionHandle *data, long milli) * time-out period to expire. * */ -void Curl_expire_latest(struct SessionHandle *data, long milli) +void Curl_expire_latest(struct Curl_easy *data, long milli) { struct timeval *expire = &data->state.expiretime; @@ -2718,15 +3004,12 @@ void Curl_expire_latest(struct SessionHandle *data, long milli) Curl_expire(data, milli); } -CURLMcode curl_multi_assign(CURLM *multi_handle, - curl_socket_t s, void *hashp) +CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s, + void *hashp) { struct Curl_sh_entry *there = NULL; - struct Curl_multi *multi = (struct Curl_multi *)multi_handle; - if(s != CURL_SOCKET_BAD) - there = Curl_hash_pick(&multi->sockhash, (char *)&s, - sizeof(curl_socket_t)); + there = sh_getentry(&multi->sockhash, s); if(!there) return CURLM_BAD_SOCKET; @@ -2771,7 +3054,7 @@ void Curl_multi_process_pending_handles(struct Curl_multi *multi) struct curl_llist_element *e = multi->pending->head; while(e) { - struct SessionHandle *data = e->ptr; + struct Curl_easy *data = e->ptr; struct curl_llist_element *next = e->next; if(data->mstate == CURLM_STATE_CONNECT_PEND) { @@ -2789,10 +3072,9 @@ void Curl_multi_process_pending_handles(struct Curl_multi *multi) } #ifdef DEBUGBUILD -void Curl_multi_dump(const struct Curl_multi *multi_handle) +void Curl_multi_dump(struct Curl_multi *multi) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct SessionHandle *data; + struct Curl_easy *data; int i; fprintf(stderr, "* Multi status: %d handles, %d alive\n", multi->num_easy, multi->num_alive); @@ -2804,8 +3086,7 @@ void Curl_multi_dump(const struct Curl_multi *multi_handle) statename[data->mstate], data->numsocks); for(i=0; i < data->numsocks; i++) { curl_socket_t s = data->sockets[i]; - struct Curl_sh_entry *entry = - Curl_hash_pick(&multi->sockhash, (char *)&s, sizeof(s)); + struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); fprintf(stderr, "%d ", (int)s); if(!entry) { diff --git a/lib/multihandle.h b/lib/multihandle.h index 6c24f50..c56b6ae 100644 --- a/lib/multihandle.h +++ b/lib/multihandle.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -71,8 +71,8 @@ struct Curl_multi { long type; /* We have a doubly-linked circular list with easy handles */ - struct SessionHandle *easyp; - struct SessionHandle *easylp; /* last node */ + struct Curl_easy *easyp; + struct Curl_easy *easylp; /* last node */ int num_easy; /* amount of entries in the linked list above. */ int num_alive; /* amount of easy handles that are added but have not yet @@ -80,7 +80,7 @@ struct Curl_multi { struct curl_llist *msglist; /* a list of messages from completed transfers */ - struct curl_llist *pending; /* SessionHandles that are in the + struct curl_llist *pending; /* Curl_easys that are in the CURLM_STATE_CONNECT_PEND state */ /* callback function and user data pointer for the *socket() API */ @@ -113,7 +113,7 @@ struct Curl_multi { /* This handle will be used for closing the cached connections in curl_multi_cleanup() */ - struct SessionHandle *closure_handle; + struct Curl_easy *closure_handle; long maxconnects; /* if >0, a fixed limit of the maximum number of entries we're allowed to grow the connection cache to */ diff --git a/lib/multiif.h b/lib/multiif.h index e6323ad..fd2df55 100644 --- a/lib/multiif.h +++ b/lib/multiif.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -25,10 +25,10 @@ /* * Prototypes for library-wide functions provided by multi.c */ -void Curl_expire(struct SessionHandle *data, long milli); -void Curl_expire_latest(struct SessionHandle *data, long milli); +void Curl_expire(struct Curl_easy *data, long milli); +void Curl_expire_latest(struct Curl_easy *data, long milli); bool Curl_pipeline_wanted(const struct Curl_multi* multi, int bits); -void Curl_multi_handlePipeBreak(struct SessionHandle *data); +void Curl_multi_handlePipeBreak(struct Curl_easy *data); /* Internal version of curl_multi_init() accepts size parameters for the socket and connection hashes */ @@ -51,7 +51,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize); * allow easier tracking of the internal handle's state and what sockets * they use. Only for research and development DEBUGBUILD enabled builds. */ -void Curl_multi_dump(const struct Curl_multi *multi_handle); +void Curl_multi_dump(struct Curl_multi *multi); #endif void Curl_multi_process_pending_handles(struct Curl_multi *multi); @@ -92,6 +92,6 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s); * Add a handle and move it into PERFORM state at once. For pushed streams. */ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, - struct SessionHandle *data, + struct Curl_easy *data, struct connectdata *conn); #endif /* HEADER_CURL_MULTIIF_H */ diff --git a/lib/netrc.c b/lib/netrc.c index 06f8ea1..46f427a 100644 --- a/lib/netrc.c +++ b/lib/netrc.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -32,9 +32,9 @@ #include "strequal.h" #include "strtok.h" #include "rawstr.h" -#include "curl_printf.h" -/* The last #include files should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/netrc.h b/lib/netrc.h index a145601..d980166 100644 --- a/lib/netrc.h +++ b/lib/netrc.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/non-ascii.c b/lib/non-ascii.c index 6ccb449..ed14618 100644 --- a/lib/non-ascii.c +++ b/lib/non-ascii.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -51,7 +51,7 @@ * Curl_convert_clone() returns a malloced copy of the source string (if * returning CURLE_OK), with the data converted to network format. */ -CURLcode Curl_convert_clone(struct SessionHandle *data, +CURLcode Curl_convert_clone(struct Curl_easy *data, const char *indata, size_t insize, char **outbuf) @@ -79,7 +79,7 @@ CURLcode Curl_convert_clone(struct SessionHandle *data, * Curl_convert_to_network() is an internal function for performing ASCII * conversions on non-ASCII platforms. It convers the buffer _in place_. */ -CURLcode Curl_convert_to_network(struct SessionHandle *data, +CURLcode Curl_convert_to_network(struct Curl_easy *data, char *buffer, size_t length) { if(data->set.convtonetwork) { @@ -139,7 +139,7 @@ CURLcode Curl_convert_to_network(struct SessionHandle *data, * Curl_convert_from_network() is an internal function for performing ASCII * conversions on non-ASCII platforms. It convers the buffer _in place_. */ -CURLcode Curl_convert_from_network(struct SessionHandle *data, +CURLcode Curl_convert_from_network(struct Curl_easy *data, char *buffer, size_t length) { if(data->set.convfromnetwork) { @@ -199,7 +199,7 @@ CURLcode Curl_convert_from_network(struct SessionHandle *data, * Curl_convert_from_utf8() is an internal function for performing UTF-8 * conversions on non-ASCII platforms. */ -CURLcode Curl_convert_from_utf8(struct SessionHandle *data, +CURLcode Curl_convert_from_utf8(struct Curl_easy *data, char *buffer, size_t length) { if(data->set.convfromutf8) { @@ -261,9 +261,9 @@ CURLcode Curl_convert_from_utf8(struct SessionHandle *data, } /* - * Init conversion stuff for a SessionHandle + * Init conversion stuff for a Curl_easy */ -void Curl_convert_init(struct SessionHandle *data) +void Curl_convert_init(struct Curl_easy *data) { #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) /* conversion descriptors for iconv calls */ @@ -276,9 +276,9 @@ void Curl_convert_init(struct SessionHandle *data) } /* - * Setup conversion stuff for a SessionHandle + * Setup conversion stuff for a Curl_easy */ -void Curl_convert_setup(struct SessionHandle *data) +void Curl_convert_setup(struct Curl_easy *data) { data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, CURL_ICONV_CODESET_OF_NETWORK); @@ -289,10 +289,10 @@ void Curl_convert_setup(struct SessionHandle *data) } /* - * Close conversion stuff for a SessionHandle + * Close conversion stuff for a Curl_easy */ -void Curl_convert_close(struct SessionHandle *data) +void Curl_convert_close(struct Curl_easy *data) { #ifdef HAVE_ICONV /* close iconv conversion descriptors */ @@ -314,7 +314,7 @@ void Curl_convert_close(struct SessionHandle *data) * Curl_convert_form() is used from http.c, this converts any form items that need to be sent in the network encoding. Returns CURLE_OK on success. */ -CURLcode Curl_convert_form(struct SessionHandle *data, struct FormData *form) +CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form) { CURLcode result; diff --git a/lib/non-ascii.h b/lib/non-ascii.h index 8b4b7c2..e27f1f4 100644 --- a/lib/non-ascii.h +++ b/lib/non-ascii.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -33,22 +33,22 @@ * * If no conversion was needed *outbuf may be NULL. */ -CURLcode Curl_convert_clone(struct SessionHandle *data, +CURLcode Curl_convert_clone(struct Curl_easy *data, const char *indata, size_t insize, char **outbuf); -void Curl_convert_init(struct SessionHandle *data); -void Curl_convert_setup(struct SessionHandle *data); -void Curl_convert_close(struct SessionHandle *data); +void Curl_convert_init(struct Curl_easy *data); +void Curl_convert_setup(struct Curl_easy *data); +void Curl_convert_close(struct Curl_easy *data); -CURLcode Curl_convert_to_network(struct SessionHandle *data, +CURLcode Curl_convert_to_network(struct Curl_easy *data, char *buffer, size_t length); -CURLcode Curl_convert_from_network(struct SessionHandle *data, +CURLcode Curl_convert_from_network(struct Curl_easy *data, char *buffer, size_t length); -CURLcode Curl_convert_from_utf8(struct SessionHandle *data, +CURLcode Curl_convert_from_utf8(struct Curl_easy *data, char *buffer, size_t length); -CURLcode Curl_convert_form(struct SessionHandle *data, struct FormData *form); +CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form); #else #define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK) #define Curl_convert_init(x) Curl_nop_stmt diff --git a/lib/nonblock.c b/lib/nonblock.c index 1447c87..b764278 100644 --- a/lib/nonblock.c +++ b/lib/nonblock.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -77,7 +77,7 @@ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */ /* Amiga */ long flags = nonblock ? 1L : 0L; - return IoctlSocket(sockfd, FIONBIO, flags); + return IoctlSocket(sockfd, FIONBIO, (char *)&flags); #elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK) diff --git a/lib/nonblock.h b/lib/nonblock.h index b540ae4..98cdc25 100644 --- a/lib/nonblock.h +++ b/lib/nonblock.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/nwlib.c b/lib/nwlib.c index bd3f27e..42b6aa0 100644 --- a/lib/nwlib.c +++ b/lib/nwlib.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -58,26 +58,26 @@ rtag_t gAllocTag = (rtag_t) NULL; NXMutex_t *gLibLock = (NXMutex_t *) NULL; /* internal library function prototypes... */ -int DisposeLibraryData( void * ); -void DisposeThreadData( void * ); -int GetOrSetUpData( int id, libdata_t **data, libthreaddata_t **threaddata ); - - -int _NonAppStart( void *NLMHandle, - void *errorScreen, - const char *cmdLine, - const char *loadDirPath, - size_t uninitializedDataLength, - void *NLMFileHandle, - int (*readRoutineP)( int conn, - void *fileHandle, size_t offset, - size_t nbytes, - size_t *bytesRead, - void *buffer ), +int DisposeLibraryData(void *); +void DisposeThreadData(void *); +int GetOrSetUpData(int id, libdata_t **data, libthreaddata_t **threaddata); + + +int _NonAppStart(void *NLMHandle, + void *errorScreen, + const char *cmdLine, + const char *loadDirPath, + size_t uninitializedDataLength, + void *NLMFileHandle, + int (*readRoutineP)(int conn, + void *fileHandle, size_t offset, + size_t nbytes, + size_t *bytesRead, + void *buffer), size_t customDataOffset, size_t customDataSize, int messageCount, - const char **messages ) + const char **messages) { NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0); @@ -132,7 +132,7 @@ int _NonAppStart( void *NLMHandle, * Here we clean up any resources we allocated. Resource tags is a big part * of what we created, but NetWare doesn't ask us to free those. */ -void _NonAppStop( void ) +void _NonAppStop(void) { (void) unregister_library(gLibId); NXMutexFree(gLibLock); @@ -149,13 +149,13 @@ void _NonAppStop( void ) * we return a non-zero value. Right now, there isn't any reason not to allow * it. */ -int _NonAppCheckUnload( void ) +int _NonAppCheckUnload(void) { return 0; } int GetOrSetUpData(int id, libdata_t **appData, - libthreaddata_t **threadData ) + libthreaddata_t **threadData) { int err; libdata_t *app_data; @@ -277,7 +277,7 @@ int GetOrSetUpData(int id, libdata_t **appData, return err; } -int DisposeLibraryData( void *data ) +int DisposeLibraryData(void *data) { if(data) { void *tenbytes = ((libdata_t *) data)->tenbytes; @@ -289,7 +289,7 @@ int DisposeLibraryData( void *data ) return 0; } -void DisposeThreadData( void *data ) +void DisposeThreadData(void *data) { if(data) { void *twentybytes = ((libthreaddata_t *) data)->twentybytes; @@ -303,7 +303,7 @@ void DisposeThreadData( void *data ) /* For native CLib-based NLM seems we can do a bit more simple. */ #include -int main ( void ) +int main (void) { /* initialize any globals here... */ diff --git a/lib/nwos.c b/lib/nwos.c index 23ff2a7..385f9c8 100644 --- a/lib/nwos.c +++ b/lib/nwos.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,7 +26,7 @@ #ifdef __NOVELL_LIBC__ /* For native LibC-based NLM we need to do nothing. */ -int netware_init ( void ) +int netware_init (void) { return 0; } @@ -45,7 +45,7 @@ NETDB_DEFINE_CONTEXT #include NETINET_DEFINE_CONTEXT -int netware_init ( void ) +int netware_init (void) { int rc = 0; unsigned int myHandle = GetNLMHandle(); @@ -72,13 +72,13 @@ int netware_init ( void ) } /* dummy function to satisfy newer prelude */ -int __init_environment ( void ) +int __init_environment (void) { return 0; } /* dummy function to satisfy newer prelude */ -int __deinit_environment ( void ) +int __deinit_environment (void) { return 0; } diff --git a/lib/openldap.c b/lib/openldap.c index bee552f..4b8cfb9 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -6,11 +6,11 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010, Howard Chu, - * Copyright (C) 2011 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2011 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -46,9 +46,8 @@ #include "curl_ldap.h" #include "curl_base64.h" #include "connect.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -151,7 +150,7 @@ static CURLcode ldap_setup_connection(struct connectdata *conn) { ldapconninfo *li; LDAPURLDesc *lud; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; int rc, proto; CURLcode status; @@ -189,7 +188,7 @@ static Sockbuf_IO ldapsb_tls; static CURLcode ldap_connect(struct connectdata *conn, bool *done) { ldapconninfo *li = conn->proto.generic; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int rc, proto = LDAP_VERSION3; char hosturl[1024]; char *ptr; @@ -227,7 +226,7 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done) static CURLcode ldap_connecting(struct connectdata *conn, bool *done) { ldapconninfo *li = conn->proto.generic; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; LDAPMessage *msg = NULL; struct timeval tv = {0, 1}, *tvp; int rc, err; @@ -353,7 +352,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done) int rc = 0; LDAPURLDesc *ludp = NULL; int msgid; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; connkeep(conn, "OpenLDAP do"); @@ -416,7 +415,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err) { ldapconninfo *li = conn->proto.generic; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; ldapreqinfo *lr = data->req.protop; int rc, ret; LDAPMessage *msg = NULL; @@ -446,6 +445,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, ent = ldap_next_message(li->ld, ent)) { struct berval bv, *bvals, **bvp = &bvals; int binary = 0, msgtype; + CURLcode writeerr; msgtype = ldap_msgtype(ent); if(msgtype == LDAP_RES_SEARCH_RESULT) { @@ -485,18 +485,24 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, *err = CURLE_RECV_ERROR; return -1; } - *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); - if(*err) + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); + if(writeerr) { + *err = writeerr; return -1; + } - *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, - bv.bv_len); - if(*err) + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, + bv.bv_len); + if(writeerr) { + *err = writeerr; return -1; + } - *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); - if(*err) + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + if(writeerr) { + *err = writeerr; return -1; + } data->req.bytecount += bv.bv_len + 5; for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp); @@ -513,18 +519,24 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, for(i=0; bvals[i].bv_val != NULL; i++) { int binval = 0; - *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); - if(*err) - return -1; - - *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, - bv.bv_len); - if(*err) + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); + if(writeerr) { + *err = writeerr; return -1; + } - *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1); - if(*err) - return -1; + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, + bv.bv_len); + if(writeerr) { + *err = writeerr; + return -1; + } + + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1); + if(writeerr) { + *err = writeerr; + return -1; + } data->req.bytecount += bv.bv_len + 2; if(!binary) { @@ -558,47 +570,62 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, *err = error; return -1; } - *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); - if(*err) + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, + (char *)": ", 2); + if(writeerr) { + *err = writeerr; return -1; + } data->req.bytecount += 2; if(val_b64_sz > 0) { - *err = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz); - if(*err) + if(writeerr) { + *err = writeerr; return -1; + } free(val_b64); data->req.bytecount += val_b64_sz; } } else { - *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1); - if(*err) + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1); + if(writeerr) { + *err = writeerr; return -1; + } - *err = Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val, - bvals[i].bv_len); - if(*err) + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val, + bvals[i].bv_len); + if(writeerr) { + *err = writeerr; return -1; + } data->req.bytecount += bvals[i].bv_len + 1; } - *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); - if(*err) + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + if(writeerr) { + *err = writeerr; return -1; + } data->req.bytecount++; } ber_memfree(bvals); - *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); - if(*err) + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + if(writeerr) { + *err = writeerr; return -1; + } data->req.bytecount++; } - *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); - if(*err) + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + if(writeerr) { + *err = writeerr; return -1; + } data->req.bytecount++; ber_free(ber, 0); } diff --git a/lib/parsedate.c b/lib/parsedate.c index 3e168f5..dfcf855 100644 --- a/lib/parsedate.c +++ b/lib/parsedate.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/parsedate.h b/lib/parsedate.h index ade0f4f..2e59eb1 100644 --- a/lib/parsedate.h +++ b/lib/parsedate.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/pingpong.c b/lib/pingpong.c index 1670792..92ff84b 100644 --- a/lib/pingpong.c +++ b/lib/pingpong.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -34,10 +34,10 @@ #include "multiif.h" #include "non-ascii.h" #include "vtls/vtls.h" -#include "curl_printf.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" #ifdef USE_PINGPONG @@ -47,7 +47,7 @@ long Curl_pp_state_timeout(struct pingpong *pp) { struct connectdata *conn = pp->conn; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; long timeout_ms; /* in milliseconds */ long timeout2_ms; /* in milliseconds */ long response_time= (data->set.server_response_timeout)? @@ -85,10 +85,10 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block) int rc; long interval_ms; long timeout_ms = Curl_pp_state_timeout(pp); - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; CURLcode result = CURLE_OK; - if(timeout_ms <=0 ) { + if(timeout_ms <=0) { failf(data, "server response timeout"); return CURLE_OPERATION_TIMEDOUT; /* already too little time */ } @@ -165,7 +165,7 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp, char *s; CURLcode result; struct connectdata *conn = pp->conn; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; #ifdef HAVE_GSSAPI enum protection_level data_sec = conn->data_prot; @@ -271,7 +271,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, ssize_t gotbytes; char *ptr; struct connectdata *conn = pp->conn; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char * const buf = data->state.buffer; CURLcode result = CURLE_OK; diff --git a/lib/pingpong.h b/lib/pingpong.h index b925ab9..2f649d5 100644 --- a/lib/pingpong.h +++ b/lib/pingpong.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/pipeline.c b/lib/pipeline.c index 1b38836..0ff82f0 100644 --- a/lib/pipeline.c +++ b/lib/pipeline.c @@ -10,7 +10,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -57,7 +57,7 @@ static void server_blacklist_llist_dtor(void *user, void *element) free(element); } -bool Curl_pipeline_penalized(struct SessionHandle *data, +bool Curl_pipeline_penalized(struct Curl_easy *data, struct connectdata *conn) { if(data) { @@ -70,7 +70,7 @@ bool Curl_pipeline_penalized(struct SessionHandle *data, /* Find the head of the recv pipe, if any */ if(conn->recv_pipe && conn->recv_pipe->head) { - struct SessionHandle *recv_handle = conn->recv_pipe->head->ptr; + struct Curl_easy *recv_handle = conn->recv_pipe->head->ptr; recv_size = recv_handle->req.size; @@ -91,7 +91,7 @@ bool Curl_pipeline_penalized(struct SessionHandle *data, return FALSE; } -static CURLcode addHandleToPipeline(struct SessionHandle *data, +static CURLcode addHandleToPipeline(struct Curl_easy *data, struct curl_llist *pipeline) { if(!Curl_llist_insert_next(pipeline, pipeline->tail, data)) @@ -100,7 +100,7 @@ static CURLcode addHandleToPipeline(struct SessionHandle *data, } -CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle, +CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle, struct connectdata *conn) { struct curl_llist_element *sendhead = conn->send_pipe->head; @@ -130,7 +130,7 @@ CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle, checked to update what sockets it acts on. */ -void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle, +void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle, struct connectdata *conn) { struct curl_llist_element *curr; @@ -162,7 +162,7 @@ void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle, } } -bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle, +bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle, struct connectdata *conn) { if(handle->multi) { @@ -254,7 +254,7 @@ CURLMcode Curl_pipeline_set_site_blacklist(char **sites, return CURLM_OK; } -bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle, +bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle, char *server_name) { if(handle->multi && server_name) { @@ -299,11 +299,16 @@ CURLMcode Curl_pipeline_set_server_blacklist(char **servers, char *server_name; server_name = strdup(*servers); - if(!server_name) + if(!server_name) { + Curl_llist_destroy(new_list, NULL); return CURLM_OUT_OF_MEMORY; + } - if(!Curl_llist_insert_next(new_list, new_list->tail, server_name)) + if(!Curl_llist_insert_next(new_list, new_list->tail, server_name)) { + Curl_llist_destroy(new_list, NULL); + Curl_safefree(server_name); return CURLM_OUT_OF_MEMORY; + } servers++; } @@ -320,25 +325,26 @@ CURLMcode Curl_pipeline_set_server_blacklist(char **servers, return CURLM_OK; } -static bool pipe_head(struct SessionHandle *data, +static bool pipe_head(struct Curl_easy *data, struct curl_llist *pipeline) { - struct curl_llist_element *curr = pipeline->head; - if(curr) - return (curr->ptr == data) ? TRUE : FALSE; - + if(pipeline) { + struct curl_llist_element *curr = pipeline->head; + if(curr) + return (curr->ptr == data) ? TRUE : FALSE; + } return FALSE; } /* returns TRUE if the given handle is head of the recv pipe */ -bool Curl_recvpipe_head(struct SessionHandle *data, +bool Curl_recvpipe_head(struct Curl_easy *data, struct connectdata *conn) { return pipe_head(data, conn->recv_pipe); } /* returns TRUE if the given handle is head of the send pipe */ -bool Curl_sendpipe_head(struct SessionHandle *data, +bool Curl_sendpipe_head(struct Curl_easy *data, struct connectdata *conn) { return pipe_head(data, conn->send_pipe); @@ -352,7 +358,7 @@ bool Curl_sendpipe_head(struct SessionHandle *data, * If not available, return FALSE. */ -bool Curl_pipeline_checkget_write(struct SessionHandle *data, +bool Curl_pipeline_checkget_write(struct Curl_easy *data, struct connectdata *conn) { if(conn->bits.multiplex) @@ -375,7 +381,7 @@ bool Curl_pipeline_checkget_write(struct SessionHandle *data, * If not available, return FALSE. */ -bool Curl_pipeline_checkget_read(struct SessionHandle *data, +bool Curl_pipeline_checkget_read(struct Curl_easy *data, struct connectdata *conn) { if(conn->bits.multiplex) @@ -412,7 +418,7 @@ void print_pipeline(struct connectdata *conn) { struct curl_llist_element *curr; struct connectbundle *cb_ptr; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; cb_ptr = conn->bundle; diff --git a/lib/pipeline.h b/lib/pipeline.h index bf229f1..a64f710 100644 --- a/lib/pipeline.h +++ b/lib/pipeline.h @@ -12,7 +12,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -23,34 +23,34 @@ * ***************************************************************************/ -CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle, +CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle, struct connectdata *conn); -void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle, +void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle, struct connectdata *conn); -bool Curl_pipeline_penalized(struct SessionHandle *data, +bool Curl_pipeline_penalized(struct Curl_easy *data, struct connectdata *conn); -bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle, +bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle, struct connectdata *conn); CURLMcode Curl_pipeline_set_site_blacklist(char **sites, struct curl_llist **list_ptr); -bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle, +bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle, char *server_name); CURLMcode Curl_pipeline_set_server_blacklist(char **servers, struct curl_llist **list_ptr); -bool Curl_pipeline_checkget_write(struct SessionHandle *data, +bool Curl_pipeline_checkget_write(struct Curl_easy *data, struct connectdata *conn); -bool Curl_pipeline_checkget_read(struct SessionHandle *data, +bool Curl_pipeline_checkget_read(struct Curl_easy *data, struct connectdata *conn); void Curl_pipeline_leave_write(struct connectdata *conn); void Curl_pipeline_leave_read(struct connectdata *conn); -bool Curl_recvpipe_head(struct SessionHandle *data, +bool Curl_recvpipe_head(struct Curl_easy *data, struct connectdata *conn); -bool Curl_sendpipe_head(struct SessionHandle *data, +bool Curl_sendpipe_head(struct Curl_easy *data, struct connectdata *conn); #endif /* HEADER_CURL_PIPELINE_H */ diff --git a/lib/pop3.c b/lib/pop3.c index 53510a2..591e877 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -83,9 +83,9 @@ #include "curl_sasl.h" #include "curl_md5.h" #include "warnless.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* Local API functions */ @@ -214,7 +214,7 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { /* SASL parameters for the pop3 protocol */ static const struct SASLproto saslpop3 = { "pop", /* The service name */ - '+', /* Code received when continuation is expected */ + '*', /* Code received when continuation is expected */ '+', /* Code to receive upon authentication success */ 255 - 8, /* Maximum initial response length (no max) */ pop3_perform_auth, /* Send authentication command */ @@ -225,7 +225,11 @@ static const struct SASLproto saslpop3 = { #ifdef USE_SSL static void pop3_to_pop3s(struct connectdata *conn) { + /* Change the connection handler */ conn->handler = &Curl_handler_pop3s; + + /* Set the connection's upgraded to TLS flag */ + conn->tls_upgraded = TRUE; } #else #define pop3_to_pop3s(x) Curl_nop_stmt @@ -256,21 +260,29 @@ static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len, if(pop3c->state == POP3_CAPA) { /* Do we have the terminating line? */ if(len >= 1 && !memcmp(line, ".", 1)) + /* Treat the response as a success */ *resp = '+'; else + /* Treat the response as an untagged continuation */ *resp = '*'; return TRUE; } - /* Do we have a command or continuation response? */ - if((len >= 3 && !memcmp("+OK", line, 3)) || - (len >= 1 && !memcmp("+", line, 1))) { + /* Do we have a success response? */ + if(len >= 3 && !memcmp("+OK", line, 3)) { *resp = '+'; return TRUE; } + /* Do we have a continuation response? */ + if(len >= 1 && !memcmp("+", line, 1)) { + *resp = '*'; + + return TRUE; + } + return FALSE; /* Nothing for us */ } @@ -585,7 +597,7 @@ static CURLcode pop3_perform_authentication(struct connectdata *conn) static CURLcode pop3_perform_command(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; const char *command = NULL; @@ -641,7 +653,7 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct pop3_conn *pop3c = &conn->proto.pop3c; const char *line = data->state.buffer; size_t len = strlen(line); @@ -692,7 +704,7 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct pop3_conn *pop3c = &conn->proto.pop3c; const char *line = data->state.buffer; size_t len = strlen(line); @@ -700,7 +712,7 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code, (void)instate; /* no use for this yet */ - /* Do we have a untagged response? */ + /* Do we have a untagged continuation response? */ if(pop3code == '*') { /* Does the server support the STLS capability? */ if(len >= 4 && !memcmp(line, "STLS", 4)) @@ -741,8 +753,8 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code, wordlen++; /* Test the word for a matching authentication mechanism */ - if((mechbit = Curl_sasl_decode_mech(line, wordlen, &llen)) && - llen == wordlen) + mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); + if(mechbit && llen == wordlen) pop3c->sasl.authmechs |= mechbit; line += wordlen; @@ -783,7 +795,7 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -807,7 +819,7 @@ static CURLcode pop3_state_auth_resp(struct connectdata *conn, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct pop3_conn *pop3c = &conn->proto.pop3c; saslprogress progress; @@ -847,7 +859,7 @@ static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -868,7 +880,7 @@ static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -891,7 +903,7 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -912,7 +924,7 @@ static CURLcode pop3_state_command_resp(struct connectdata *conn, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; struct pop3_conn *pop3c = &conn->proto.pop3c; struct pingpong *pp = &pop3c->pp; @@ -1066,12 +1078,12 @@ static CURLcode pop3_block_statemach(struct connectdata *conn) return result; } -/* Allocate and initialize the POP3 struct for the current SessionHandle if +/* Allocate and initialize the POP3 struct for the current Curl_easy if required */ static CURLcode pop3_init(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3; pop3 = data->req.protop = calloc(sizeof(struct POP3), 1); @@ -1148,16 +1160,12 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, bool premature) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; (void)premature; if(!pop3) - /* When the easy handle is removed from the multi interface while libcurl - is still trying to resolve the host name, the POP3 struct is not yet - initialized. However, the removal action calls Curl_done() which in - turn calls this function, so we simply return success. */ return CURLE_OK; if(status) { @@ -1316,7 +1324,7 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn, { CURLcode result = CURLE_OK; bool connected = FALSE; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Make sure size is unknown at this point */ data->req.size = -1; @@ -1339,13 +1347,17 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn, static CURLcode pop3_setup_connection(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Initialise the POP3 layer */ CURLcode result = pop3_init(conn); if(result) return result; + /* Clear the TLS upgraded flag */ + conn->tls_upgraded = FALSE; + + /* Set up the proxy if necessary */ if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { /* Unless we have asked to tunnel POP3 operations through the proxy, we switch and use HTTP operations only */ @@ -1442,7 +1454,7 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn) static CURLcode pop3_parse_url_path(struct connectdata *conn) { /* The POP3 struct is already initialised in pop3_connect() */ - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; const char *path = data->state.path; @@ -1459,7 +1471,7 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn) static CURLcode pop3_parse_custom_request(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; const char *custom = data->set.str[STRING_CUSTOMREQUEST]; @@ -1481,7 +1493,7 @@ CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread) { /* This code could be made into a special function in the handler struct */ CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SingleRequest *k = &data->req; struct pop3_conn *pop3c = &conn->proto.pop3c; diff --git a/lib/pop3.h b/lib/pop3.h index 7bc53aa..a8e697c 100644 --- a/lib/pop3.h +++ b/lib/pop3.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -45,9 +45,9 @@ typedef enum { POP3_LAST /* never used */ } pop3state; -/* This POP3 struct is used in the SessionHandle. All POP3 data that is +/* This POP3 struct is used in the Curl_easy. All POP3 data that is connection-oriented must be in pop3_conn to properly deal with the fact that - perhaps the SessionHandle is changed between the times the connection is + perhaps the Curl_easy is changed between the times the connection is used. */ struct POP3 { curl_pp_transfer transfer; diff --git a/lib/progress.c b/lib/progress.c index b46e274..760ca1c 100644 --- a/lib/progress.c +++ b/lib/progress.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -133,7 +133,7 @@ static char *max5data(curl_off_t bytes, char *max5) int Curl_pgrsDone(struct connectdata *conn) { int rc; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; data->progress.lastshow=0; rc = Curl_pgrsUpdate(conn); /* the final (forced) update */ if(rc) @@ -150,7 +150,7 @@ int Curl_pgrsDone(struct connectdata *conn) } /* reset all times except redirect, and reset the known transfer sizes */ -void Curl_pgrsResetTimesSizes(struct SessionHandle *data) +void Curl_pgrsResetTimesSizes(struct Curl_easy *data) { data->progress.t_nslookup = 0.0; data->progress.t_connect = 0.0; @@ -161,7 +161,7 @@ void Curl_pgrsResetTimesSizes(struct SessionHandle *data) Curl_pgrsSetUploadSize(data, -1); } -void Curl_pgrsTime(struct SessionHandle *data, timerid timer) +void Curl_pgrsTime(struct Curl_easy *data, timerid timer) { struct timeval now = Curl_tvnow(); @@ -212,7 +212,7 @@ void Curl_pgrsTime(struct SessionHandle *data, timerid timer) } } -void Curl_pgrsStartNow(struct SessionHandle *data) +void Curl_pgrsStartNow(struct Curl_easy *data) { data->progress.speeder_c = 0; /* reset the progress meter display */ data->progress.start = Curl_tvnow(); @@ -220,17 +220,17 @@ void Curl_pgrsStartNow(struct SessionHandle *data) data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT; } -void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size) +void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size) { data->progress.downloaded = size; } -void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size) +void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size) { data->progress.uploaded = size; } -void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size) +void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size) { if(size >= 0) { data->progress.size_dl = size; @@ -242,7 +242,7 @@ void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size) } } -void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size) +void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size) { if(size >= 0) { data->progress.size_ul = size; @@ -269,7 +269,7 @@ int Curl_pgrsUpdate(struct connectdata *conn) curl_off_t total_transfer; curl_off_t total_expected_transfer; curl_off_t timespent; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int nowindex = data->progress.speeder_c% CURR_TIME; int checkindex; int countindex; /* amount of seconds stored in the speeder array */ diff --git a/lib/progress.h b/lib/progress.h index a1e6f1a..a77b7ce 100644 --- a/lib/progress.h +++ b/lib/progress.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -41,14 +41,14 @@ typedef enum { } timerid; int Curl_pgrsDone(struct connectdata *); -void Curl_pgrsStartNow(struct SessionHandle *data); -void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size); -void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size); -void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size); -void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size); +void Curl_pgrsStartNow(struct Curl_easy *data); +void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size); +void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size); +void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size); +void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size); int Curl_pgrsUpdate(struct connectdata *); -void Curl_pgrsResetTimesSizes(struct SessionHandle *data); -void Curl_pgrsTime(struct SessionHandle *data, timerid timer); +void Curl_pgrsResetTimesSizes(struct Curl_easy *data); +void Curl_pgrsTime(struct Curl_easy *data, timerid timer); /* Don't show progress for sizes smaller than: */ diff --git a/lib/rawstr.c b/lib/rawstr.c index e27dac4..5665ebd 100644 --- a/lib/rawstr.c +++ b/lib/rawstr.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -28,6 +28,10 @@ its behavior is altered by the current locale. */ char Curl_raw_toupper(char in) { +#if !defined(CURL_DOES_CONVERSIONS) + if(in >= 'a' && in <= 'z') + return (char)('A' + in - 'a'); +#else switch (in) { case 'a': return 'A'; @@ -82,13 +86,15 @@ char Curl_raw_toupper(char in) case 'z': return 'Z'; } +#endif + return in; } /* * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant * to be locale independent and only compare strings we know are safe for - * this. See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for + * this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for * some further explanation to why this function is necessary. * * The function is capable of comparing a-z case insensitively even for diff --git a/lib/rawstr.h b/lib/rawstr.h index b491460..4af00f1 100644 --- a/lib/rawstr.h +++ b/lib/rawstr.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/rtsp.c b/lib/rtsp.c index c30afd3..27955bc 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -36,9 +36,8 @@ #include "rawstr.h" #include "select.h" #include "connect.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -74,7 +73,7 @@ static int rtsp_getsock_do(struct connectdata *conn, * data is parsed and k->str is moved up * readmore: whether or not the RTP parser needs more data right away */ -static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data, +static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *readmore); @@ -159,7 +158,7 @@ bool Curl_rtsp_connisdead(struct connectdata *check) } else if((sval & CURL_CSELECT_IN) && check->data) { /* readable with no error. could be closed or could be alive but we can - only check if we have a proper SessionHandle for the connection */ + only check if we have a proper Curl_easy for the connection */ curl_socket_t connectinfo = Curl_getconnectinfo(check->data, &check); if(connectinfo != CURL_SOCKET_BAD) ret_val = FALSE; @@ -171,7 +170,7 @@ bool Curl_rtsp_connisdead(struct connectdata *check) static CURLcode rtsp_connect(struct connectdata *conn, bool *done) { CURLcode httpStatus; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; httpStatus = Curl_http_connect(conn, done); @@ -197,7 +196,7 @@ static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead) static CURLcode rtsp_done(struct connectdata *conn, CURLcode status, bool premature) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct RTSP *rtsp = data->req.protop; CURLcode httpStatus; long CSeq_sent; @@ -231,7 +230,7 @@ static CURLcode rtsp_done(struct connectdata *conn, static CURLcode rtsp_do(struct connectdata *conn, bool *done) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result=CURLE_OK; Curl_RtspReq rtspreq = data->set.rtspreq; struct RTSP *rtsp = data->req.protop; @@ -249,6 +248,8 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) const char *p_stream_uri = NULL; const char *p_transport = NULL; const char *p_uagent = NULL; + const char *p_proxyuserpwd = NULL; + const char *p_userpwd = NULL; *done = TRUE; @@ -326,7 +327,6 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) return CURLE_BAD_FUNCTION_ARGUMENT; } - /* TODO: auth? */ /* TODO: proxy? */ /* Stream URI. Default to server '*' if not specified */ @@ -392,6 +392,14 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) p_uagent = conn->allocptr.uagent; } + /* setup the authentication headers */ + result = Curl_http_output_auth(conn, p_request, p_stream_uri, FALSE); + if(result) + return result; + + p_proxyuserpwd = conn->allocptr.proxyuserpwd; + p_userpwd = conn->allocptr.userpwd; + /* Referrer */ Curl_safefree(conn->allocptr.ref); if(data->change.referer && !Curl_checkheaders(conn, "Referer:")) @@ -464,13 +472,25 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) "%s" /* range */ "%s" /* referrer */ "%s" /* user-agent */ + "%s" /* proxyuserpwd */ + "%s" /* userpwd */ , p_transport ? p_transport : "", p_accept ? p_accept : "", p_accept_encoding ? p_accept_encoding : "", p_range ? p_range : "", p_referrer ? p_referrer : "", - p_uagent ? p_uagent : ""); + p_uagent ? p_uagent : "", + p_proxyuserpwd ? p_proxyuserpwd : "", + p_userpwd ? p_userpwd : ""); + + /* + * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM + * with basic and digest, it will be freed anyway by the next request + */ + Curl_safefree (conn->allocptr.userpwd); + conn->allocptr.userpwd = NULL; + if(result) return result; @@ -580,7 +600,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) } -static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data, +static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *readmore) { @@ -711,7 +731,7 @@ static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data, static CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; size_t wrote; curl_write_callback writeit; @@ -739,7 +759,7 @@ CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len) CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; long CSeq = 0; if(checkprefix("CSeq:", header)) { diff --git a/lib/rtsp.h b/lib/rtsp.h index 3ffa70c..5a8d555 100644 --- a/lib/rtsp.h +++ b/lib/rtsp.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/security.c b/lib/security.c index 014bbf1..a0bcaea 100644 --- a/lib/security.c +++ b/lib/security.c @@ -476,7 +476,7 @@ Curl_sec_request_prot(struct connectdata *conn, const char *level) static CURLcode choose_mech(struct connectdata *conn) { int ret; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; void *tmp_allocation; const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech; diff --git a/lib/select.c b/lib/select.c index 24dc5fd..abf55d8 100644 --- a/lib/select.c +++ b/lib/select.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -316,15 +316,15 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ curl_socket_t is unsigned in such cases and thus -1 is the largest value). */ +#ifdef USE_WINSOCK r = select((int)maxfd + 1, -#ifndef USE_WINSOCK - &fds_read, - &fds_write, -#else fds_read.fd_count ? &fds_read : NULL, fds_write.fd_count ? &fds_write : NULL, -#endif &fds_err, ptimeout); +#else + r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); +#endif + if(r != -1) break; error = SOCKERRNO; @@ -505,19 +505,19 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) pending_tv.tv_sec = 0; pending_tv.tv_usec = 0; } + +#ifdef USE_WINSOCK r = select((int)maxfd + 1, -#ifndef USE_WINSOCK - &fds_read, &fds_write, &fds_err, -#else /* WinSock select() can't handle fd_sets with zero bits set, so don't give it such arguments. See the comment about this in Curl_check_socket(). */ fds_read.fd_count ? &fds_read : NULL, fds_write.fd_count ? &fds_write : NULL, - fds_err.fd_count ? &fds_err : NULL, + fds_err.fd_count ? &fds_err : NULL, ptimeout); +#else + r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); #endif - ptimeout); if(r != -1) break; error = SOCKERRNO; diff --git a/lib/select.h b/lib/select.h index c00afe1..695bb69 100644 --- a/lib/select.h +++ b/lib/select.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/sendf.c b/lib/sendf.c index 5f39d1f..2101797 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -31,10 +31,11 @@ #include "ssh.h" #include "multiif.h" #include "non-ascii.h" -#include "curl_printf.h" #include "strerror.h" +#include "select.h" -/* The last #include files should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" @@ -45,7 +46,7 @@ * blocks of data. Remaining, bare CRs are changed to LFs. The possibly new * size of the data is returned. */ -static size_t convert_lineends(struct SessionHandle *data, +static size_t convert_lineends(struct Curl_easy *data, char *startPtr, size_t size) { char *inPtr, *outPtr; @@ -120,9 +121,93 @@ static size_t convert_lineends(struct SessionHandle *data, } #endif /* CURL_DO_LINEEND_CONV */ +#ifdef USE_RECV_BEFORE_SEND_WORKAROUND +static void pre_receive_plain(struct connectdata *conn, int num) +{ + const curl_socket_t sockfd = conn->sock[num]; + struct postponed_data * const psnd = &(conn->postponed[num]); + size_t bytestorecv = psnd->allocated_size - psnd->recv_size; + /* WinSock will destroy unread received data if send() is + failed. + To avoid lossage of received data, recv() must be + performed before every send() if any incoming data is + available. However, skip this, if buffer is already full. */ + if((conn->handler->protocol&PROTO_FAMILY_HTTP) != 0 && + conn->recv[num] == Curl_recv_plain && + (!psnd->buffer || bytestorecv)) { + const int readymask = Curl_socket_check(sockfd, CURL_SOCKET_BAD, + CURL_SOCKET_BAD, 0); + if(readymask != -1 && (readymask & CURL_CSELECT_IN) != 0) { + /* Have some incoming data */ + if(!psnd->buffer) { + /* Use buffer double default size for intermediate buffer */ + psnd->allocated_size = 2 * BUFSIZE; + psnd->buffer = malloc(psnd->allocated_size); + psnd->recv_size = 0; + psnd->recv_processed = 0; +#ifdef DEBUGBUILD + psnd->bindsock = sockfd; /* Used only for DEBUGASSERT */ +#endif /* DEBUGBUILD */ + bytestorecv = psnd->allocated_size; + } + if(psnd->buffer) { + ssize_t recvedbytes; + DEBUGASSERT(psnd->bindsock == sockfd); + recvedbytes = sread(sockfd, psnd->buffer + psnd->recv_size, + bytestorecv); + if(recvedbytes > 0) + psnd->recv_size += recvedbytes; + } + else + psnd->allocated_size = 0; + } + } +} + +static ssize_t get_pre_recved(struct connectdata *conn, int num, char *buf, + size_t len) +{ + struct postponed_data * const psnd = &(conn->postponed[num]); + size_t copysize; + if(!psnd->buffer) + return 0; + + DEBUGASSERT(psnd->allocated_size > 0); + DEBUGASSERT(psnd->recv_size <= psnd->allocated_size); + DEBUGASSERT(psnd->recv_processed <= psnd->recv_size); + /* Check and process data that already received and storied in internal + intermediate buffer */ + if(psnd->recv_size > psnd->recv_processed) { + DEBUGASSERT(psnd->bindsock == conn->sock[num]); + copysize = CURLMIN(len, psnd->recv_size - psnd->recv_processed); + memcpy(buf, psnd->buffer + psnd->recv_processed, copysize); + psnd->recv_processed += copysize; + } + else + copysize = 0; /* buffer was allocated, but nothing was received */ + + /* Free intermediate buffer if it has no unprocessed data */ + if(psnd->recv_processed == psnd->recv_size) { + free(psnd->buffer); + psnd->buffer = NULL; + psnd->allocated_size = 0; + psnd->recv_size = 0; + psnd->recv_processed = 0; +#ifdef DEBUGBUILD + psnd->bindsock = CURL_SOCKET_BAD; +#endif /* DEBUGBUILD */ + } + return (ssize_t)copysize; +} +#else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ +/* Use "do-nothing" macros instead of functions when workaround not used */ +#define pre_receive_plain(c,n) do {} WHILE_FALSE +#define get_pre_recved(c,n,b,l) 0 +#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ + /* Curl_infof() is for info message along the way */ -void Curl_infof(struct SessionHandle *data, const char *fmt, ...) +void Curl_infof(struct Curl_easy *data, const char *fmt, ...) { if(data && data->set.verbose) { va_list ap; @@ -140,7 +225,7 @@ void Curl_infof(struct SessionHandle *data, const char *fmt, ...) * The message SHALL NOT include any LF or CR. */ -void Curl_failf(struct SessionHandle *data, const char *fmt, ...) +void Curl_failf(struct Curl_easy *data, const char *fmt, ...) { va_list ap; size_t len; @@ -168,7 +253,7 @@ void Curl_failf(struct SessionHandle *data, const char *fmt, ...) CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, const char *fmt, ...) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; ssize_t bytes_written; size_t write_len; CURLcode result = CURLE_OK; @@ -254,7 +339,23 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num, const void *mem, size_t len, CURLcode *code) { curl_socket_t sockfd = conn->sock[num]; - ssize_t bytes_written = swrite(sockfd, mem, len); + ssize_t bytes_written; + /* WinSock will destroy unread received data if send() is + failed. + To avoid lossage of received data, recv() must be + performed before every send() if any incoming data is + available. */ + pre_receive_plain(conn, num); + +#ifdef MSG_FASTOPEN /* Linux */ + if(conn->bits.tcp_fastopen) { + bytes_written = sendto(sockfd, mem, len, MSG_FASTOPEN, + conn->ip_addr->ai_addr, conn->ip_addr->ai_addrlen); + conn->bits.tcp_fastopen = FALSE; + } + else +#endif + bytes_written = swrite(sockfd, mem, len); *code = CURLE_OK; if(-1 == bytes_written) { @@ -268,7 +369,8 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num, /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned due to its inability to send off data without blocking. We therefor treat both error codes the same here */ - (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) + (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) || + (EINPROGRESS == err) #endif ) { /* this is just a case of EWOULDBLOCK */ @@ -311,7 +413,16 @@ ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf, size_t len, CURLcode *code) { curl_socket_t sockfd = conn->sock[num]; - ssize_t nread = sread(sockfd, buf, len); + ssize_t nread; + /* Check and return data that already received and storied in internal + intermediate buffer */ + nread = get_pre_recved(conn, num, buf, len); + if(nread > 0) { + *code = CURLE_OK; + return nread; + } + + nread = sread(sockfd, buf, len); *code = CURLE_OK; if(-1 == nread) { @@ -341,7 +452,7 @@ ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf, return nread; } -static CURLcode pausewrite(struct SessionHandle *data, +static CURLcode pausewrite(struct Curl_easy *data, int type, /* what type of data */ const char *ptr, size_t len) @@ -380,7 +491,7 @@ CURLcode Curl_client_chop_write(struct connectdata *conn, char * ptr, size_t len) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_write_callback writeheader = NULL; curl_write_callback writebody = NULL; @@ -487,7 +598,7 @@ CURLcode Curl_client_write(struct connectdata *conn, char *ptr, size_t len) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(0 == len) len = strlen(ptr); @@ -520,11 +631,13 @@ CURLcode Curl_read_plain(curl_socket_t sockfd, if(-1 == nread) { int err = SOCKERRNO; + int return_error; #ifdef USE_WINSOCK - if(WSAEWOULDBLOCK == err) + return_error = WSAEWOULDBLOCK == err; #else - if((EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)) + return_error = EWOULDBLOCK == err || EAGAIN == err || EINTR == err; #endif + if(return_error) return CURLE_AGAIN; else return CURLE_RECV_ERROR; @@ -551,7 +664,10 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */ ssize_t nread = 0; size_t bytesfromsocket = 0; char *buffertofill = NULL; - bool pipelining = Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1); + + /* if HTTP/1 pipelining is both wanted and possible */ + bool pipelining = Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1) && + (conn->bundle->multiuse == BUNDLE_PIPELINING); /* Set 'num' to 0 or 1, depending on which socket that has been sent here. If it is the second socket, we set num to 1. Otherwise to 0. This lets @@ -602,7 +718,7 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */ } /* return 0 on success */ -static int showit(struct SessionHandle *data, curl_infotype type, +static int showit(struct Curl_easy *data, curl_infotype type, char *ptr, size_t size) { static const char s_infotype[CURLINFO_END][3] = { @@ -671,7 +787,7 @@ static int showit(struct SessionHandle *data, curl_infotype type, return 0; } -int Curl_debug(struct SessionHandle *data, curl_infotype type, +int Curl_debug(struct Curl_easy *data, curl_infotype type, char *ptr, size_t size, struct connectdata *conn) { diff --git a/lib/sendf.h b/lib/sendf.h index 86f06cf..a951a0b 100644 --- a/lib/sendf.h +++ b/lib/sendf.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,8 +26,8 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *, const char *fmt, ...); -void Curl_infof(struct SessionHandle *, const char *fmt, ...); -void Curl_failf(struct SessionHandle *, const char *fmt, ...); +void Curl_infof(struct Curl_easy *, const char *fmt, ...); +void Curl_failf(struct Curl_easy *, const char *fmt, ...); #if defined(CURL_DISABLE_VERBOSE_STRINGS) @@ -84,7 +84,7 @@ CURLcode Curl_write_plain(struct connectdata *conn, ssize_t *written); /* the function used to output verbose information */ -int Curl_debug(struct SessionHandle *handle, curl_infotype type, +int Curl_debug(struct Curl_easy *handle, curl_infotype type, char *data, size_t size, struct connectdata *conn); diff --git a/lib/setup-os400.h b/lib/setup-os400.h index fae8567..e32b72f 100644 --- a/lib/setup-os400.h +++ b/lib/setup-os400.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/setup-vms.h b/lib/setup-vms.h index 520a35d..4b78e0b 100644 --- a/lib/setup-vms.h +++ b/lib/setup-vms.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/share.c b/lib/share.c index 1720248..5b3957f 100644 --- a/lib/share.c +++ b/lib/share.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -31,7 +31,7 @@ /* The last #include file should be: */ #include "memdebug.h" -CURLSH * +struct Curl_share * curl_share_init(void) { struct Curl_share *share = calloc(1, sizeof(struct Curl_share)); @@ -49,9 +49,8 @@ curl_share_init(void) #undef curl_share_setopt CURLSHcode -curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) +curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...) { - struct Curl_share *share = (struct Curl_share *)sh; va_list param; int type; curl_lock_function lockfunc; @@ -71,14 +70,14 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) /* this is a type this share will share */ type = va_arg(param, int); share->specifier |= (1<cookies) { - share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE ); + share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE); if(!share->cookies) res = CURLSHE_NOMEM; } @@ -114,7 +113,7 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) /* this is a type this share will no longer share */ type = va_arg(param, int); share->specifier &= ~(1<share; @@ -231,7 +228,7 @@ Curl_share_lock(struct SessionHandle *data, curl_lock_data type, } CURLSHcode -Curl_share_unlock(struct SessionHandle *data, curl_lock_data type) +Curl_share_unlock(struct Curl_easy *data, curl_lock_data type) { struct Curl_share *share = data->share; diff --git a/lib/share.h b/lib/share.h index 8e6629b..e689ff2 100644 --- a/lib/share.h +++ b/lib/share.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -54,8 +54,8 @@ struct Curl_share { long sessionage; }; -CURLSHcode Curl_share_lock (struct SessionHandle *, curl_lock_data, +CURLSHcode Curl_share_lock (struct Curl_easy *, curl_lock_data, curl_lock_access); -CURLSHcode Curl_share_unlock (struct SessionHandle *, curl_lock_data); +CURLSHcode Curl_share_unlock (struct Curl_easy *, curl_lock_data); #endif /* HEADER_CURL_SHARE_H */ diff --git a/lib/sigpipe.h b/lib/sigpipe.h index e8d2acd..800f9d3 100644 --- a/lib/sigpipe.h +++ b/lib/sigpipe.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -38,10 +38,10 @@ struct sigpipe_ignore { * internals, and then sigpipe_restore() will restore the situation when we * return from libcurl again. */ -static void sigpipe_ignore(struct SessionHandle *data, +static void sigpipe_ignore(struct Curl_easy *data, struct sigpipe_ignore *ig) { - /* get a local copy of no_signal because the SessionHandle might not be + /* get a local copy of no_signal because the Curl_easy might not be around when we restore */ ig->no_signal = data->set.no_signal; if(!data->set.no_signal) { diff --git a/lib/slist.c b/lib/slist.c index 9c0b2a5..e5adc0e 100644 --- a/lib/slist.c +++ b/lib/slist.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,6 +22,8 @@ #include "curl_setup.h" +#include + #include "slist.h" /* The last #include files should be: */ diff --git a/lib/slist.h b/lib/slist.h index ea7dcc4..b3f498c 100644 --- a/lib/slist.h +++ b/lib/slist.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/smb.c b/lib/smb.c index d461a71..56a38c2 100644 --- a/lib/smb.c +++ b/lib/smb.c @@ -10,7 +10,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -131,7 +131,7 @@ const struct Curl_handler Curl_handler_smbs = { defined(__OS400__) static unsigned short smb_swap16(unsigned short x) { - return (x << 8) | ((x >> 8) & 0xff); + return (unsigned short) ((x << 8) | ((x >> 8) & 0xff)); } static unsigned int smb_swap32(unsigned int x) @@ -143,12 +143,14 @@ static unsigned int smb_swap32(unsigned int x) #ifdef HAVE_LONGLONG static unsigned long long smb_swap64(unsigned long long x) { - return ((unsigned long long)smb_swap32(x) << 32) | smb_swap32(x >> 32); + return ((unsigned long long) smb_swap32((unsigned int) x) << 32) | + smb_swap32((unsigned int) (x >> 32)); } #else static unsigned __int64 smb_swap64(unsigned __int64 x) { - return ((unsigned __int64)smb_swap32(x) << 32) | smb_swap32(x >> 32); + return ((unsigned __int64) smb_swap32((unsigned int) x) << 32) | + smb_swap32((unsigned int) (x >> 32)); } #endif #else @@ -903,7 +905,6 @@ static CURLcode smb_disconnect(struct connectdata *conn, bool dead) /* smb_done is not always called, so cleanup the request */ if(req) { Curl_safefree(req->share); - Curl_safefree(conn->data->req.protop); } return CURLE_OK; @@ -928,7 +929,7 @@ static int smb_getsock(struct connectdata *conn, curl_socket_t *socks, static CURLcode smb_parse_url_path(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct smb_request *req = data->req.protop; char *path; char *slash; diff --git a/lib/smb.h b/lib/smb.h index 7852fa1..1a4f66e 100644 --- a/lib/smb.h +++ b/lib/smb.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/smtp.c b/lib/smtp.c index dada087..d203b53 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -82,9 +82,9 @@ #include "curl_gethostname.h" #include "curl_sasl.h" #include "warnless.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* Local API functions */ @@ -224,7 +224,11 @@ static const struct SASLproto saslsmtp = { #ifdef USE_SSL static void smtp_to_smtps(struct connectdata *conn) { + /* Change the connection handler */ conn->handler = &Curl_handler_smtps; + + /* Set the connection's upgraded to TLS flag */ + conn->tls_upgraded = TRUE; } #else #define smtp_to_smtps(x) Curl_nop_stmt @@ -288,7 +292,7 @@ static void smtp_get_message(char *buffer, char** outptr) /* Find the end of the message */ for(len = strlen(message); len--;) if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && - message[len] != '\t') + message[len] != '\t') break; /* Terminate the message */ @@ -486,7 +490,7 @@ static CURLcode smtp_perform_authentication(struct connectdata *conn) /* Check we have enough data to authenticate with, and the server supports authentiation, and end the connect phase if not */ if(!smtpc->auth_supported || - !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) { + !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) { state(conn, SMTP_STOP); return result; } @@ -516,15 +520,15 @@ static CURLcode smtp_perform_authentication(struct connectdata *conn) static CURLcode smtp_perform_command(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; /* Send the command */ if(smtp->rcpt) result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s %s", - smtp->custom && smtp->custom[0] != '\0' ? - smtp->custom : "VRFY", - smtp->rcpt->data); + smtp->custom && smtp->custom[0] != '\0' ? + smtp->custom : "VRFY", + smtp->rcpt->data); else result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", smtp->custom && smtp->custom[0] != '\0' ? @@ -548,7 +552,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) char *auth = NULL; char *size = NULL; CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Calculate the FROM parameter */ if(!data->set.str[STRING_MAIL_FROM]) @@ -623,16 +627,16 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) static CURLcode smtp_perform_rcpt_to(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; /* Send the RCPT TO command */ if(smtp->rcpt->data[0] == '<') result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s", - smtp->rcpt->data); + smtp->rcpt->data); else result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>", - smtp->rcpt->data); + smtp->rcpt->data); if(!result) state(conn, SMTP_RCPT); @@ -664,7 +668,7 @@ static CURLcode smtp_state_servergreet_resp(struct connectdata *conn, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -684,7 +688,7 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -707,7 +711,7 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct smtp_conn *smtpc = &conn->proto.smtpc; const char *line = data->state.buffer; size_t len = strlen(line); @@ -766,8 +770,8 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode, wordlen++; /* Test the word for a matching authentication mechanism */ - if((mechbit = Curl_sasl_decode_mech(line, wordlen, &llen)) && - llen == wordlen) + mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); + if(mechbit && llen == wordlen) smtpc->sasl.authmechs |= mechbit; line += wordlen; @@ -802,7 +806,7 @@ static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -823,7 +827,7 @@ static CURLcode smtp_state_auth_resp(struct connectdata *conn, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct smtp_conn *smtpc = &conn->proto.smtpc; saslprogress progress; @@ -851,7 +855,7 @@ static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; char *line = data->state.buffer; size_t len = strlen(line); @@ -897,7 +901,7 @@ static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -917,7 +921,7 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; (void)instate; /* no use for this yet */ @@ -949,7 +953,7 @@ static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -994,7 +998,7 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) { CURLcode result = CURLE_OK; curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int smtpcode; struct smtp_conn *smtpc = &conn->proto.smtpc; struct pingpong *pp = &smtpc->pp; @@ -1104,12 +1108,12 @@ static CURLcode smtp_block_statemach(struct connectdata *conn) return result; } -/* Allocate and initialize the SMTP struct for the current SessionHandle if +/* Allocate and initialize the SMTP struct for the current Curl_easy if required */ static CURLcode smtp_init(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp; smtp = data->req.protop = calloc(sizeof(struct SMTP), 1); @@ -1190,7 +1194,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, bool premature) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; struct pingpong *pp = &conn->proto.smtpc.pp; char *eob; @@ -1200,10 +1204,6 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, (void)premature; if(!smtp || !pp->conn) - /* When the easy handle is removed from the multi interface while libcurl - is still trying to resolve the host name, the SMTP struct is not yet - initialized. However, the removal action calls Curl_done() which in - turn calls this function, so we simply return success. */ return CURLE_OK; if(status) { @@ -1258,8 +1258,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, TODO: when the multi interface is used, this _really_ should be using the smtp_multi_statemach function but we have no general support for - non-blocking DONE operations, not in the multi state machine and with - Curl_done() invokes on several places in the code! + non-blocking DONE operations! */ result = smtp_block_statemach(conn); } @@ -1285,7 +1284,7 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected, { /* This is SMTP and no proxy */ CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; DEBUGF(infof(conn->data, "DO phase starts\n")); @@ -1424,7 +1423,7 @@ static CURLcode smtp_regular_transfer(struct connectdata *conn, { CURLcode result = CURLE_OK; bool connected = FALSE; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Make sure size is unknown at this point */ data->req.size = -1; @@ -1447,9 +1446,13 @@ static CURLcode smtp_regular_transfer(struct connectdata *conn, static CURLcode smtp_setup_connection(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result; + /* Clear the TLS upgraded flag */ + conn->tls_upgraded = FALSE; + + /* Set up the proxy if necessary */ if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { /* Unless we have asked to tunnel SMTP operations through the proxy, we switch and use HTTP operations only */ @@ -1502,7 +1505,7 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn) const char *value; while(*ptr && *ptr != '=') - ptr++; + ptr++; value = ptr + 1; @@ -1531,7 +1534,7 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn) static CURLcode smtp_parse_url_path(struct connectdata *conn) { /* The SMTP struct is already initialised in smtp_connect() */ - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct smtp_conn *smtpc = &conn->proto.smtpc; const char *path = data->state.path; char localhost[HOSTNAME_MAX + 1]; @@ -1557,7 +1560,7 @@ static CURLcode smtp_parse_url_path(struct connectdata *conn) static CURLcode smtp_parse_custom_request(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; const char *custom = data->set.str[STRING_CUSTOMREQUEST]; @@ -1578,7 +1581,7 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread) */ ssize_t i; ssize_t si; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; char *scratch = data->state.scratch; char *newscratch = NULL; diff --git a/lib/smtp.h b/lib/smtp.h index 9fbe0c5..b67340a 100644 --- a/lib/smtp.h +++ b/lib/smtp.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -47,9 +47,9 @@ typedef enum { SMTP_LAST /* never used */ } smtpstate; -/* This SMTP struct is used in the SessionHandle. All SMTP data that is +/* This SMTP struct is used in the Curl_easy. All SMTP data that is connection-oriented must be in smtp_conn to properly deal with the fact that - perhaps the SessionHandle is changed between the times the connection is + perhaps the Curl_easy is changed between the times the connection is used. */ struct SMTP { curl_pp_transfer transfer; diff --git a/lib/sockaddr.h b/lib/sockaddr.h index 6a2151c..95ba4c3 100644 --- a/lib/sockaddr.h +++ b/lib/sockaddr.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/socks.c b/lib/socks.c index 7d3f782..fccb16d 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -119,7 +119,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, int result; CURLcode code; curl_socket_t sock = conn->sock[sockindex]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(Curl_timeleft(data, NULL, TRUE) < 0) { /* time-out, bail out, go home */ @@ -173,8 +173,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name, unsigned short ip[4]; Curl_printable_address(hp, buf, sizeof(buf)); - if(4 == sscanf( buf, "%hu.%hu.%hu.%hu", - &ip[0], &ip[1], &ip[2], &ip[3])) { + if(4 == sscanf(buf, "%hu.%hu.%hu.%hu", + &ip[0], &ip[1], &ip[2], &ip[3])) { /* Set DSTIP */ socksreq[4] = (unsigned char)ip[0]; socksreq[5] = (unsigned char)ip[1]; @@ -300,8 +300,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name, ", request rejected or failed.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], - ((socksreq[8] << 8) | socksreq[9]), - socksreq[1]); + (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; case 92: failf(data, @@ -310,8 +310,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name, "identd on the client.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], - ((socksreq[8] << 8) | socksreq[9]), - socksreq[1]); + (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; case 93: failf(data, @@ -320,8 +320,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name, "report different user-ids.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], - ((socksreq[8] << 8) | socksreq[9]), - socksreq[1]); + (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; default: failf(data, @@ -329,8 +329,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name, ", Unknown.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], - ((socksreq[8] << 8) | socksreq[9]), - socksreq[1]); + (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; } } @@ -374,7 +374,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, int result; CURLcode code; curl_socket_t sock = conn->sock[sockindex]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; long timeout; bool socks5_resolve_local = (conn->proxytype == CURLPROXY_SOCKS5)?TRUE:FALSE; const size_t hostname_len = strlen(hostname); @@ -603,7 +603,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, if(hp->ai_family == AF_INET) { socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ - saddr_in = (struct sockaddr_in*)hp->ai_addr; + saddr_in = (struct sockaddr_in*)(void*)hp->ai_addr; for(i = 0; i < 4; i++) { socksreq[len++] = ((unsigned char*)&saddr_in->sin_addr.s_addr)[i]; infof(data, "%d\n", socksreq[len-1]); @@ -613,7 +613,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, else if(hp->ai_family == AF_INET6) { socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ - saddr_in6 = (struct sockaddr_in6*)hp->ai_addr; + saddr_in6 = (struct sockaddr_in6*)(void*)hp->ai_addr; for(i = 0; i < 16; i++) { socksreq[len++] = ((unsigned char*)&saddr_in6->sin6_addr.s6_addr)[i]; } @@ -674,15 +674,15 @@ CURLcode Curl_SOCKS5(const char *proxy_name, "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], - ((socksreq[8] << 8) | socksreq[9]), - socksreq[1]); + (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); } else if(socksreq[3] == 3) { failf(data, "Can't complete SOCKS5 connection to %s:%d. (%d)", hostname, - ((socksreq[8] << 8) | socksreq[9]), - socksreq[1]); + (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); } else if(socksreq[3] == 4) { failf(data, @@ -696,8 +696,8 @@ CURLcode Curl_SOCKS5(const char *proxy_name, (unsigned char)socksreq[14], (unsigned char)socksreq[15], (unsigned char)socksreq[16], (unsigned char)socksreq[17], (unsigned char)socksreq[18], (unsigned char)socksreq[19], - ((socksreq[8] << 8) | socksreq[9]), - socksreq[1]); + (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); } return CURLE_COULDNT_CONNECT; } diff --git a/lib/socks.h b/lib/socks.h index 29e3bf0..a44ada6 100644 --- a/lib/socks.h +++ b/lib/socks.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index 8e575c2..369245a 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -6,11 +6,11 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2009, 2011, Markus Moeller, - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -32,9 +32,10 @@ #include "timeval.h" #include "socks.h" #include "warnless.h" + +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; @@ -42,7 +43,7 @@ static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; /* * Helper GSS-API error functions. */ -static int check_gss_err(struct SessionHandle *data, +static int check_gss_err(struct Curl_easy *data, OM_uint32 major_status, OM_uint32 minor_status, const char* function) @@ -101,7 +102,7 @@ static int check_gss_err(struct SessionHandle *data, CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_socket_t sock = conn->sock[sockindex]; CURLcode code; ssize_t actualread; @@ -120,7 +121,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, unsigned short us_length; char *user=NULL; unsigned char socksreq[4]; /* room for GSS-API exchange header only */ - char *serviceptr = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE]; + const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ? + data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; /* GSS-API request looks like * +----+------+-----+----------------+ diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index a7708b2..6053490 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -5,12 +5,12 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. * Copyright (C) 2009, 2011, Markus Moeller, * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -34,9 +34,10 @@ #include "curl_sspi.h" #include "curl_multibyte.h" #include "warnless.h" +#include "strdup.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* @@ -61,7 +62,7 @@ static int check_sspi_err(struct connectdata *conn, CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_socket_t sock = conn->sock[sockindex]; CURLcode code; ssize_t actualread; @@ -70,7 +71,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, /* Needs GSS-API authentication */ SECURITY_STATUS status; unsigned long sspi_ret_flags = 0; - int gss_enc; + unsigned char gss_enc; SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3]; SecBufferDesc input_desc, output_desc, wrap_desc; SecPkgContext_Sizes sspi_sizes; @@ -83,7 +84,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, unsigned short us_length; unsigned long qop; unsigned char socksreq[4]; /* room for GSS-API exchange header only */ - char *service = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE]; + const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ? + data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; /* GSS-API request looks like * +----+------+-----+----------------+ @@ -95,10 +97,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, /* prepare service name */ if(strchr(service, '/')) { - service_name = malloc(strlen(service)); + service_name = strdup(service); if(!service_name) return CURLE_OUT_OF_MEMORY; - memcpy(service_name, service, strlen(service)); } else { service_name = malloc(strlen(service) + strlen(conn->proxy.name) + 2); diff --git a/lib/speedcheck.c b/lib/speedcheck.c index ac7447c..13c34af 100644 --- a/lib/speedcheck.c +++ b/lib/speedcheck.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -28,12 +28,12 @@ #include "multiif.h" #include "speedcheck.h" -void Curl_speedinit(struct SessionHandle *data) +void Curl_speedinit(struct Curl_easy *data) { memset(&data->state.keeps_speed, 0, sizeof(struct timeval)); } -CURLcode Curl_speedcheck(struct SessionHandle *data, +CURLcode Curl_speedcheck(struct Curl_easy *data, struct timeval now) { if((data->progress.current_speed >= 0) && diff --git a/lib/speedcheck.h b/lib/speedcheck.h index 786cd12..7dbe3d6 100644 --- a/lib/speedcheck.h +++ b/lib/speedcheck.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,8 +26,8 @@ #include "timeval.h" -void Curl_speedinit(struct SessionHandle *data); -CURLcode Curl_speedcheck(struct SessionHandle *data, +void Curl_speedinit(struct Curl_easy *data); +CURLcode Curl_speedcheck(struct Curl_easy *data, struct timeval now); #endif /* HEADER_CURL_SPEEDCHECK_H */ diff --git a/lib/splay.c b/lib/splay.c index b87b6cf..7aa2e4b 100644 --- a/lib/splay.c +++ b/lib/splay.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/splay.h b/lib/splay.h index 5f9ef24..427bfc8 100644 --- a/lib/splay.h +++ b/lib/splay.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1997 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1997 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -55,7 +55,7 @@ int Curl_splayremovebyaddr(struct Curl_tree *t, #define Curl_splaycomparekeys(i,j) ( ((i.tv_sec) < (j.tv_sec)) ? -1 : \ ( ((i.tv_sec) > (j.tv_sec)) ? 1 : \ ( ((i.tv_usec) < (j.tv_usec)) ? -1 : \ - ( ((i.tv_usec) > (j.tv_usec)) ? 1 : 0 )))) + ( ((i.tv_usec) > (j.tv_usec)) ? 1 : 0)))) #ifdef DEBUGBUILD void Curl_splayprint(struct Curl_tree * t, int d, char output); diff --git a/lib/ssh.c b/lib/ssh.c index 94195a7..7bc3136 100644 --- a/lib/ssh.c +++ b/lib/ssh.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -83,9 +83,10 @@ #include "multiif.h" #include "select.h" #include "warnless.h" + +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" #ifdef WIN32 @@ -101,6 +102,11 @@ have their definition hidden well */ #endif +#if LIBSSH2_VERSION_NUM >= 0x010206 +/* libssh2_sftp_statvfs and friends were added in 1.2.6 */ +#define HAS_STATVFS_SUPPORT 1 +#endif + #define sftp_libssh2_last_error(s) curlx_ultosi(libssh2_sftp_last_error(s)) #define sftp_libssh2_realpath(s,p,t,m) \ @@ -362,6 +368,9 @@ static void state(struct connectdata *conn, sshstate nowstate) "SSH_SFTP_QUOTE_RENAME", "SSH_SFTP_QUOTE_RMDIR", "SSH_SFTP_QUOTE_UNLINK", + "SSH_SFTP_QUOTE_STATVFS", + "SSH_SFTP_GETINFO", + "SSH_SFTP_FILETIME", "SSH_SFTP_TRANS_INIT", "SSH_SFTP_UPLOAD_INIT", "SSH_SFTP_CREATE_DIRS_INIT", @@ -404,7 +413,7 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn, char **path) /* returns the allocated real path to work with */ { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char *real_path = NULL; char *working_path; int working_path_len; @@ -414,7 +423,7 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn, if(!working_path) return CURLE_OUT_OF_MEMORY; - /* Check for /~/ , indicating relative to the user's home directory */ + /* Check for /~/, indicating relative to the user's home directory */ if(conn->handler->protocol & CURLPROTO_SCP) { real_path = malloc(working_path_len+1); if(real_path == NULL) { @@ -464,7 +473,7 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn, } #ifdef HAVE_LIBSSH2_KNOWNHOST_API -static int sshkeycallback(CURL *easy, +static int sshkeycallback(struct Curl_easy *easy, const struct curl_khkey *knownkey, /* known */ const struct curl_khkey *foundkey, /* found */ enum curl_khmatch match, @@ -513,7 +522,7 @@ static CURLcode ssh_knownhost(struct connectdata *conn) CURLcode result = CURLE_OK; #ifdef HAVE_LIBSSH2_KNOWNHOST_API - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(data->set.str[STRING_SSH_KNOWNHOSTS]) { /* we're asked to verify the host against a file */ @@ -648,7 +657,7 @@ static CURLcode ssh_knownhost(struct connectdata *conn) static CURLcode ssh_check_fingerprint(struct connectdata *conn) { struct ssh_conn *sshc = &conn->proto.sshc; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]; char md5buffer[33]; int i; @@ -699,7 +708,7 @@ static CURLcode ssh_check_fingerprint(struct connectdata *conn) static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SSHPROTO *sftp_scp = data->req.protop; struct ssh_conn *sshc = &conn->proto.sshc; curl_socket_t sock = conn->sock[FIRSTSOCKET]; @@ -848,7 +857,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) * libssh2 extract the public key from the private key file. * This is done by simply passing sshc->rsa_pub = NULL. */ - if(data->set.str[STRING_SSH_PUBLIC_KEY]) { + if(data->set.str[STRING_SSH_PUBLIC_KEY] + /* treat empty string the same way as NULL */ + && data->set.str[STRING_SSH_PUBLIC_KEY][0]) { sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]); if(!sshc->rsa_pub) out_of_memory = TRUE; @@ -869,7 +880,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) free(home); - infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub); + if(sshc->rsa_pub) + infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub); infof(data, "Using SSH private key file '%s'\n", sshc->rsa); state(conn, SSH_AUTH_PKEY); @@ -1149,8 +1161,13 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) else { /* Return the error type */ err = sftp_libssh2_last_error(sshc->sftp_session); - result = sftp_libssh2_error_to_CURLE(err); - sshc->actualcode = result?result:CURLE_SSH; + if(err) + result = sftp_libssh2_error_to_CURLE(err); + else + /* in this case, the error wasn't in the SFTP level but for example + a time-out or similar */ + result = CURLE_SSH; + sshc->actualcode = result; DEBUGF(infof(data, "error = %d makes libcurl = %d\n", err, (int)result)); state(conn, SSH_STOP); @@ -1180,7 +1197,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_QUOTE); } else { - state(conn, SSH_SFTP_TRANS_INIT); + state(conn, SSH_SFTP_GETINFO); } break; @@ -1358,6 +1375,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_QUOTE_UNLINK); break; } +#ifdef HAS_STATVFS_SUPPORT + else if(curl_strnequal(cmd, "statvfs ", 8)) { + state(conn, SSH_SFTP_QUOTE_STATVFS); + break; + } +#endif failf(data, "Unknown SFTP command"); Curl_safefree(sshc->quote_path1); @@ -1369,7 +1392,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } } if(!sshc->quote_item) { - state(conn, SSH_SFTP_TRANS_INIT); + state(conn, SSH_SFTP_GETINFO); } break; @@ -1388,7 +1411,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->nextstate = SSH_NO_STATE; } else { - state(conn, SSH_SFTP_TRANS_INIT); + state(conn, SSH_SFTP_GETINFO); } } break; @@ -1608,6 +1631,88 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_NEXT_QUOTE); break; +#ifdef HAS_STATVFS_SUPPORT + case SSH_SFTP_QUOTE_STATVFS: + { + LIBSSH2_SFTP_STATVFS statvfs; + rc = libssh2_sftp_statvfs(sshc->sftp_session, sshc->quote_path1, + curlx_uztoui(strlen(sshc->quote_path1)), + &statvfs); + + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + else if(rc != 0 && !sshc->acceptfail) { + err = sftp_libssh2_last_error(sshc->sftp_session); + Curl_safefree(sshc->quote_path1); + failf(data, "statvfs command failed: %s", sftp_libssh2_strerror(err)); + state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + else if(rc == 0) { + char *tmp = aprintf("statvfs:\n" + "f_bsize: %llu\n" "f_frsize: %llu\n" + "f_blocks: %llu\n" "f_bfree: %llu\n" + "f_bavail: %llu\n" "f_files: %llu\n" + "f_ffree: %llu\n" "f_favail: %llu\n" + "f_fsid: %llu\n" "f_flag: %llu\n" + "f_namemax: %llu\n", + statvfs.f_bsize, statvfs.f_frsize, + statvfs.f_blocks, statvfs.f_bfree, + statvfs.f_bavail, statvfs.f_files, + statvfs.f_ffree, statvfs.f_favail, + statvfs.f_fsid, statvfs.f_flag, + statvfs.f_namemax); + if(!tmp) { + result = CURLE_OUT_OF_MEMORY; + state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + break; + } + + result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp)); + free(tmp); + if(result) { + state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + } + } + state(conn, SSH_SFTP_NEXT_QUOTE); + break; + } +#endif + case SSH_SFTP_GETINFO: + { + if(data->set.get_filetime) { + state(conn, SSH_SFTP_FILETIME); + } + else { + state(conn, SSH_SFTP_TRANS_INIT); + } + break; + } + + case SSH_SFTP_FILETIME: + { + LIBSSH2_SFTP_ATTRIBUTES attrs; + + rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path, + curlx_uztoui(strlen(sftp_scp->path)), + LIBSSH2_SFTP_STAT, &attrs); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + else if(rc == 0) { + data->info.filetime = (long)attrs.mtime; + } + + state(conn, SSH_SFTP_TRANS_INIT); + break; + } + case SSH_SFTP_TRANS_INIT: if(data->set.upload) state(conn, SSH_SFTP_UPLOAD_INIT); @@ -1740,8 +1845,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) BUFSIZE : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread = - data->set.fread_func(data->state.buffer, 1, readthisamountnow, - data->set.in); + data->state.fread_func(data->state.buffer, 1, + readthisamountnow, data->state.in); passed += actuallyread; if((actuallyread == 0) || (actuallyread > readthisamountnow)) { @@ -2368,19 +2473,30 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) case SSH_SCP_DOWNLOAD_INIT: { + curl_off_t bytecount; + /* * We must check the remote file; if it is a directory no values will * be set in sb */ - struct stat sb; - curl_off_t bytecount; - /* clear the struct scp recv will fill in */ - memset(&sb, 0, sizeof(struct stat)); + /* + * If support for >2GB files exists, use it. + */ /* get a fresh new channel from the ssh layer */ +#if LIBSSH2_VERSION_NUM < 0x010700 + struct stat sb; + memset(&sb, 0, sizeof(struct stat)); sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session, sftp_scp->path, &sb); +#else + libssh2_struct_stat sb; + memset(&sb, 0, sizeof(libssh2_struct_stat)); + sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session, + sftp_scp->path, &sb); +#endif + if(!sshc->ssh_channel) { if(libssh2_session_last_errno(sshc->ssh_session) == LIBSSH2_ERROR_EAGAIN) { @@ -2708,7 +2824,7 @@ static CURLcode ssh_block_statemach(struct connectdata *conn, { struct ssh_conn *sshc = &conn->proto.sshc; CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; while((sshc->state != SSH_STOP) && !result) { bool block; @@ -2782,7 +2898,7 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done) #endif struct ssh_conn *ssh; CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* initialize per-handle data if not already */ if(!data->req.protop) @@ -2908,7 +3024,7 @@ static CURLcode ssh_do(struct connectdata *conn, bool *done) { CURLcode result; bool connected = 0; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssh_conn *sshc = &conn->proto.sshc; *done = FALSE; /* default to false */ @@ -2941,8 +3057,6 @@ static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection) struct ssh_conn *ssh = &conn->proto.sshc; (void) dead_connection; - Curl_safefree(conn->data->req.protop); - if(ssh->ssh_session) { /* only if there's a session still around to use! */ @@ -2966,8 +3080,7 @@ static CURLcode ssh_done(struct connectdata *conn, CURLcode status) TODO: when the multi interface is used, this _really_ should be using the ssh_multi_statemach function but we have no general support for - non-blocking DONE operations, not in the multi state machine and with - Curl_done() invokes on several places in the code! + non-blocking DONE operations! */ result = ssh_block_statemach(conn, FALSE); } @@ -3105,8 +3218,6 @@ static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection) DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n")); - Curl_safefree(conn->data->req.protop); - if(conn->proto.sshc.ssh_session) { /* only if there's a session still around to use! */ state(conn, SSH_SFTP_SHUTDOWN); diff --git a/lib/ssh.h b/lib/ssh.h index b3cc54c..b350dcf 100644 --- a/lib/ssh.h +++ b/lib/ssh.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -66,6 +66,9 @@ typedef enum { SSH_SFTP_QUOTE_RENAME, SSH_SFTP_QUOTE_RMDIR, SSH_SFTP_QUOTE_UNLINK, + SSH_SFTP_QUOTE_STATVFS, + SSH_SFTP_GETINFO, + SSH_SFTP_FILETIME, SSH_SFTP_TRANS_INIT, SSH_SFTP_UPLOAD_INIT, SSH_SFTP_CREATE_DIRS_INIT, @@ -95,7 +98,7 @@ typedef enum { } sshstate; /* this struct is used in the HandleData struct which is part of the - SessionHandle, which means this is used on a per-easy handle basis. + Curl_easy, which means this is used on a per-easy handle basis. Everything that is strictly related to a connection is banned from this struct. */ struct SSHPROTO { diff --git a/lib/strdup.c b/lib/strdup.c index 5685b81..23f554e 100644 --- a/lib/strdup.c +++ b/lib/strdup.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -19,7 +19,11 @@ * KIND, either express or implied. * ***************************************************************************/ + #include "curl_setup.h" + +#include + #include "strdup.h" #include "curl_memory.h" diff --git a/lib/strdup.h b/lib/strdup.h index 23a71f8..4c48ca4 100644 --- a/lib/strdup.h +++ b/lib/strdup.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/strequal.c b/lib/strequal.c index 5f2f508..01c3784 100644 --- a/lib/strequal.c +++ b/lib/strequal.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/strequal.h b/lib/strequal.h index 117a305..ff56df5 100644 --- a/lib/strequal.h +++ b/lib/strequal.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/strerror.c b/lib/strerror.c index 5657141..0e268d5 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2004 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2004 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -39,10 +39,14 @@ #include #endif +#ifdef USE_WINDOWS_SSPI +#include "curl_sspi.h" +#endif + #include "strerror.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" const char * @@ -301,6 +305,9 @@ curl_easy_strerror(CURLcode error) case CURLE_SSL_INVALIDCERTSTATUS: return "SSL server certificate status verification FAILED"; + case CURLE_HTTP2_STREAM: + return "Stream error in the HTTP/2 framing layer"; + /* error codes not used by current libcurl */ case CURLE_OBSOLETE20: case CURLE_OBSOLETE24: @@ -1072,14 +1079,13 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err) strncpy(outbuf, txt, outmax); else if(err == SEC_E_ILLEGAL_MESSAGE) snprintf(outbuf, outmax, - "SEC_E_ILLEGAL_MESSAGE (0x%04X%04X) - This error usually occurs " + "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually occurs " "when a fatal SSL/TLS alert is received (e.g. handshake failed). " "More detail may be available in the Windows System event log.", - (err >> 16) & 0xffff, err & 0xffff); + err); else { str = txtbuf; - snprintf(txtbuf, sizeof(txtbuf), "%s (0x%04X%04X)", - txt, (err >> 16) & 0xffff, err & 0xffff); + snprintf(txtbuf, sizeof(txtbuf), "%s (0x%08X)", txt, err); txtbuf[sizeof(txtbuf)-1] = '\0'; #ifdef _WIN32_WCE diff --git a/lib/strerror.h b/lib/strerror.h index f1b2221..ae8c96b 100644 --- a/lib/strerror.h +++ b/lib/strerror.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/strtok.c b/lib/strtok.c index 0d31351..460eb87 100644 --- a/lib/strtok.c +++ b/lib/strtok.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/strtok.h b/lib/strtok.h index 1147d70..90b831e 100644 --- a/lib/strtok.h +++ b/lib/strtok.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/strtoofft.c b/lib/strtoofft.c index 03a97e8..6d5d2d5 100644 --- a/lib/strtoofft.c +++ b/lib/strtoofft.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/strtoofft.h b/lib/strtoofft.h index 75c73d4..f4039f3 100644 --- a/lib/strtoofft.h +++ b/lib/strtoofft.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/system_win32.c b/lib/system_win32.c new file mode 100644 index 0000000..d6a998b --- /dev/null +++ b/lib/system_win32.c @@ -0,0 +1,294 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2016, Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(WIN32) + +#include +#include "system_win32.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \ + defined(USE_WINSOCK)) + + +#if !defined(LOAD_WITH_ALTERED_SEARCH_PATH) +#define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008 +#endif + +#if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32) +#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 +#endif + +/* We use our own typedef here since some headers might lack these */ +typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD); + +/* See function definitions in winbase.h */ +#ifdef UNICODE +# ifdef _WIN32_WCE +# define LOADLIBARYEX L"LoadLibraryExW" +# else +# define LOADLIBARYEX "LoadLibraryExW" +# endif +#else +# define LOADLIBARYEX "LoadLibraryExA" +#endif + +#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */ + +/* + * Curl_verify_windows_version() + * + * This is used to verify if we are running on a specific windows version. + * + * Parameters: + * + * majorVersion [in] - The major version number. + * minorVersion [in] - The minor version number. + * platform [in] - The optional platform identifer. + * condition [in] - The test condition used to specifier whether we are + * checking a version less then, equal to or greater than + * what is specified in the major and minor version + * numbers. + * + * Returns TRUE if matched; otherwise FALSE. + */ +bool Curl_verify_windows_version(const unsigned int majorVersion, + const unsigned int minorVersion, + const PlatformIdentifier platform, + const VersionCondition condition) +{ + bool matched = FALSE; + +#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ + (_WIN32_WINNT < _WIN32_WINNT_WIN2K) + OSVERSIONINFO osver; + + memset(&osver, 0, sizeof(osver)); + osver.dwOSVersionInfoSize = sizeof(osver); + + /* Find out Windows version */ + if(GetVersionEx(&osver)) { + /* Verify the Operating System version number */ + switch(condition) { + case VERSION_LESS_THAN: + if(osver.dwMajorVersion < majorVersion || + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion < minorVersion)) + matched = TRUE; + break; + + case VERSION_LESS_THAN_EQUAL: + if(osver.dwMajorVersion <= majorVersion && + osver.dwMinorVersion <= minorVersion) + matched = TRUE; + break; + + case VERSION_EQUAL: + if(osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion == minorVersion) + matched = TRUE; + break; + + case VERSION_GREATER_THAN_EQUAL: + if(osver.dwMajorVersion >= majorVersion && + osver.dwMinorVersion >= minorVersion) + matched = TRUE; + break; + + case VERSION_GREATER_THAN: + if(osver.dwMajorVersion > majorVersion || + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion > minorVersion)) + matched = TRUE; + break; + } + + /* Verify the platform identifier (if necessary) */ + if(matched && platform != PLATFORM_DONT_CARE) { + switch(platform) { + case PLATFORM_WINDOWS: + if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) + matched = FALSE; + break; + + case PLATFORM_WINNT: + if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT) + matched = FALSE; + } + } + } +#else + ULONGLONG cm = 0; + OSVERSIONINFOEX osver; + BYTE majorCondition; + BYTE minorCondition; + BYTE spMajorCondition; + BYTE spMinorCondition; + + switch(condition) { + case VERSION_LESS_THAN: + majorCondition = VER_LESS; + minorCondition = VER_LESS; + spMajorCondition = VER_LESS_EQUAL; + spMinorCondition = VER_LESS_EQUAL; + break; + + case VERSION_LESS_THAN_EQUAL: + majorCondition = VER_LESS_EQUAL; + minorCondition = VER_LESS_EQUAL; + spMajorCondition = VER_LESS_EQUAL; + spMinorCondition = VER_LESS_EQUAL; + break; + + case VERSION_EQUAL: + majorCondition = VER_EQUAL; + minorCondition = VER_EQUAL; + spMajorCondition = VER_GREATER_EQUAL; + spMinorCondition = VER_GREATER_EQUAL; + break; + + case VERSION_GREATER_THAN_EQUAL: + majorCondition = VER_GREATER_EQUAL; + minorCondition = VER_GREATER_EQUAL; + spMajorCondition = VER_GREATER_EQUAL; + spMinorCondition = VER_GREATER_EQUAL; + break; + + case VERSION_GREATER_THAN: + majorCondition = VER_GREATER; + minorCondition = VER_GREATER; + spMajorCondition = VER_GREATER_EQUAL; + spMinorCondition = VER_GREATER_EQUAL; + break; + + default: + return FALSE; + } + + memset(&osver, 0, sizeof(osver)); + osver.dwOSVersionInfoSize = sizeof(osver); + osver.dwMajorVersion = majorVersion; + osver.dwMinorVersion = minorVersion; + if(platform == PLATFORM_WINDOWS) + osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; + else if(platform == PLATFORM_WINNT) + osver.dwPlatformId = VER_PLATFORM_WIN32_NT; + + cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition); + cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition); + if(platform != PLATFORM_DONT_CARE) + cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL); + + if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), + cm)) + matched = TRUE; +#endif + + return matched; +} + +#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \ + defined(USE_WINSOCK)) + +/* + * Curl_load_library() + * + * This is used to dynamically load DLLs using the most secure method available + * for the version of Windows that we are running on. + * + * Parameters: + * + * filename [in] - The filename or full path of the DLL to load. If only the + * filename is passed then the DLL will be loaded from the + * Windows system directory. + * + * Returns the handle of the module on success; otherwise NULL. + */ +HMODULE Curl_load_library(LPCTSTR filename) +{ + HMODULE hModule = NULL; + LOADLIBRARYEX_FN pLoadLibraryEx = NULL; + + /* Get a handle to kernel32 so we can access it's functions at runtime */ + HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32")); + if(!hKernel32) + return NULL; + + /* Attempt to find LoadLibraryEx() which is only available on Windows 2000 + and above */ + pLoadLibraryEx = (LOADLIBRARYEX_FN) GetProcAddress(hKernel32, LOADLIBARYEX); + + /* Detect if there's already a path in the filename and load the library if + there is. Note: Both back slashes and forward slashes have been supported + since the earlier days of DOS at an API level although they are not + supported by command prompt */ + if(_tcspbrk(filename, TEXT("\\/"))) { + /** !checksrc! disable BANNEDFUNC 1 **/ + hModule = pLoadLibraryEx ? + pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) : + LoadLibrary(filename); + } + /* Detect if KB2533623 is installed, as LOAD_LIBARY_SEARCH_SYSTEM32 is only + supported on Windows Vista, Windows Server 2008, Windows 7 and Windows + Server 2008 R2 with this patch or natively on Windows 8 and above */ + else if(pLoadLibraryEx && GetProcAddress(hKernel32, "AddDllDirectory")) { + /* Load the DLL from the Windows system directory */ + hModule = pLoadLibraryEx(filename, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + } + else { + /* Attempt to get the Windows system path */ + UINT systemdirlen = GetSystemDirectory(NULL, 0); + if(systemdirlen) { + /* Allocate space for the full DLL path (Room for the null terminator + is included in systemdirlen) */ + size_t filenamelen = _tcslen(filename); + TCHAR *path = malloc(sizeof(TCHAR) * (systemdirlen + 1 + filenamelen)); + if(path && GetSystemDirectory(path, systemdirlen)) { + /* Calculate the full DLL path */ + _tcscpy(path + _tcslen(path), TEXT("\\")); + _tcscpy(path + _tcslen(path), filename); + + /* Load the DLL from the Windows system directory */ + /** !checksrc! disable BANNEDFUNC 1 **/ + hModule = pLoadLibraryEx ? + pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) : + LoadLibrary(path); + + } + free(path); + } + } + + return hModule; +} + +#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */ + +#endif /* WIN32 */ diff --git a/lib/system_win32.h b/lib/system_win32.h new file mode 100644 index 0000000..1e77285 --- /dev/null +++ b/lib/system_win32.h @@ -0,0 +1,61 @@ +#ifndef HEADER_CURL_SYSTEM_WIN32_H +#define HEADER_CURL_SYSTEM_WIN32_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2016, Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(WIN32) + +/* Version condition */ +typedef enum { + VERSION_LESS_THAN, + VERSION_LESS_THAN_EQUAL, + VERSION_EQUAL, + VERSION_GREATER_THAN_EQUAL, + VERSION_GREATER_THAN +} VersionCondition; + +/* Platform identifier */ +typedef enum { + PLATFORM_DONT_CARE, + PLATFORM_WINDOWS, + PLATFORM_WINNT +} PlatformIdentifier; + +/* This is used to verify if we are running on a specific windows version */ +bool Curl_verify_windows_version(const unsigned int majorVersion, + const unsigned int minorVersion, + const PlatformIdentifier platform, + const VersionCondition condition); + +#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \ + defined(USE_WINSOCK)) + +/* This is used to dynamically load DLLs */ +HMODULE Curl_load_library(LPCTSTR filename); + +#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */ + +#endif /* WIN32 */ + +#endif /* HEADER_CURL_SYSTEM_WIN32_H */ diff --git a/lib/telnet.c b/lib/telnet.c index aabf99d..cc705cf 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -51,7 +51,7 @@ #include "telnet.h" #include "connect.h" #include "progress.h" -#include "curl_printf.h" +#include "system_win32.h" #define TELOPTS #define TELCMDS @@ -62,7 +62,8 @@ #include "rawstr.h" #include "warnless.h" -/* The last #include files should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" @@ -91,7 +92,7 @@ #ifdef USE_WINSOCK typedef FARPROC WSOCK2_FUNC; -static CURLcode check_wsock2 ( struct SessionHandle *data ); +static CURLcode check_wsock2 (struct Curl_easy *data); #endif static @@ -100,7 +101,7 @@ CURLcode telrcv(struct connectdata *, ssize_t count); /* Number of bytes received */ #ifndef CURL_DISABLE_VERBOSE_STRINGS -static void printoption(struct SessionHandle *data, +static void printoption(struct Curl_easy *data, const char *direction, int cmd, int option); #endif @@ -110,7 +111,7 @@ static void send_negotiation(struct connectdata *, int cmd, int option); static void set_local_option(struct connectdata *, int cmd, int option); static void set_remote_option(struct connectdata *, int cmd, int option); -static void printsub(struct SessionHandle *data, +static void printsub(struct Curl_easy *data, int direction, unsigned char *pointer, size_t length); static void suboption(struct connectdata *); @@ -198,7 +199,7 @@ const struct Curl_handler Curl_handler_telnet = { #ifdef USE_WINSOCK static CURLcode -check_wsock2 ( struct SessionHandle *data ) +check_wsock2(struct Curl_easy *data) { int err; WORD wVersionRequested; @@ -305,7 +306,7 @@ static void negotiate(struct connectdata *conn) } #ifndef CURL_DISABLE_VERBOSE_STRINGS -static void printoption(struct SessionHandle *data, +static void printoption(struct Curl_easy *data, const char *direction, int cmd, int option) { const char *fmt; @@ -346,7 +347,7 @@ static void send_negotiation(struct connectdata *conn, int cmd, int option) unsigned char buf[3]; ssize_t bytes_written; int err; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; buf[0] = CURL_IAC; buf[1] = (unsigned char)cmd; @@ -702,7 +703,7 @@ void rec_dont(struct connectdata *conn, int option) } -static void printsub(struct SessionHandle *data, +static void printsub(struct Curl_easy *data, int direction, /* '<' or '>' */ unsigned char *pointer, /* where suboption data is */ size_t length) /* length of suboption data */ @@ -821,7 +822,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) struct curl_slist *beg; char option_keyword[128] = ""; char option_arg[256] = ""; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct TELNET *tn = (struct TELNET *)conn->data->req.protop; CURLcode result = CURLE_OK; int binary_option; @@ -931,7 +932,7 @@ static void suboption(struct connectdata *conn) int err; char varname[128] = ""; char varval[128] = ""; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct TELNET *tn = (struct TELNET *)data->req.protop; printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2); @@ -1006,7 +1007,7 @@ static void sendsuboption(struct connectdata *conn, int option) unsigned short x, y; unsigned char*uc1, *uc2; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct TELNET *tn = (struct TELNET *)data->req.protop; switch (option) { @@ -1064,7 +1065,7 @@ CURLcode telrcv(struct connectdata *conn, CURLcode result; int in = 0; int startwrite=-1; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct TELNET *tn = (struct TELNET *)data->req.protop; #define startskipping() \ @@ -1281,7 +1282,7 @@ static CURLcode telnet_done(struct connectdata *conn, static CURLcode telnet_do(struct connectdata *conn, bool *done) { CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; #ifdef USE_WINSOCK HMODULE wsock2; @@ -1334,7 +1335,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) /* OK, so we have WinSock 2.0. We need to dynamically */ /* load ws2_32.dll and get the function pointers we need. */ - wsock2 = LoadLibrary(TEXT("WS2_32.DLL")); + wsock2 = Curl_load_library(TEXT("WS2_32.DLL")); if(wsock2 == NULL) { failf(data, "failed to load WS2_32.DLL (%d)", ERRNO); return CURLE_FAILED_INIT; @@ -1423,8 +1424,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) for(;;) { if(data->set.is_fread_set) { /* read from user-supplied method */ - result = (int)data->set.fread_func(buf, 1, BUFSIZE - 1, - data->set.in); + result = (int)data->state.fread_func(buf, 1, BUFSIZE - 1, + data->state.in); if(result == CURL_READFUNC_ABORT) { keepon = FALSE; result = CURLE_READ_ERROR; @@ -1563,13 +1564,13 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) pfd[0].fd = sockfd; pfd[0].events = POLLIN; - if(data->set.fread_func != (curl_read_callback)fread) { + if(data->set.is_fread_set) { poll_cnt = 1; interval_ms = 100; /* poll user-supplied read function */ } else { /* really using fread, so infile is a FILE* */ - pfd[1].fd = fileno((FILE *)data->set.in); + pfd[1].fd = fileno((FILE *)data->state.in); pfd[1].events = POLLIN; poll_cnt = 2; interval_ms = 1 * 1000; @@ -1628,7 +1629,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) } else { /* read from user-supplied method */ - nread = (int)data->set.fread_func(buf, 1, BUFSIZE - 1, data->set.in); + nread = (int)data->state.fread_func(buf, 1, BUFSIZE - 1, + data->state.in); if(nread == CURL_READFUNC_ABORT) { keepon = FALSE; break; diff --git a/lib/telnet.h b/lib/telnet.h index ddb9e54..419a399 100644 --- a/lib/telnet.h +++ b/lib/telnet.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/tftp.c b/lib/tftp.c index 4c5796f..d7ff94f 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -57,10 +57,10 @@ #include "url.h" #include "rawstr.h" #include "speedcheck.h" -#include "curl_printf.h" #include "select.h" -/* The last #include files should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" @@ -312,14 +312,14 @@ static const char *tftp_option_get(const char *buf, size_t len, { size_t loc; - loc = Curl_strnlen( buf, len ); + loc = Curl_strnlen(buf, len); loc++; /* NULL term */ if(loc >= len) return NULL; *option = buf; - loc += Curl_strnlen( buf+loc, len-loc ); + loc += Curl_strnlen(buf+loc, len-loc); loc++; /* NULL term */ if(loc > len) @@ -333,7 +333,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, const char *ptr, int len) { const char *tmp = ptr; - struct SessionHandle *data = state->conn->data; + struct Curl_easy *data = state->conn->data; /* if OACK doesn't contain blksize option, the default (512) must be used */ state->blksize = TFTP_BLKSIZE_DEFAULT; @@ -352,7 +352,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, if(checkprefix(option, TFTP_OPTION_BLKSIZE)) { long blksize; - blksize = strtol( value, NULL, 10 ); + blksize = strtol(value, NULL, 10); if(!blksize) { failf(data, "invalid blocksize value in OACK packet"); @@ -384,7 +384,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, else if(checkprefix(option, TFTP_OPTION_TSIZE)) { long tsize = 0; - tsize = strtol( value, NULL, 10 ); + tsize = strtol(value, NULL, 10); infof(data, "%s (%ld)\n", "tsize parsed from OACK", tsize); /* tsize should be ignored on upload: Who cares about the size of the @@ -405,7 +405,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, static size_t tftp_option_add(tftp_state_data_t *state, size_t csize, char *buf, const char *option) { - if(( strlen(option) + csize + 1 ) > (size_t)state->blksize) + if(( strlen(option) + csize + 1) > (size_t)state->blksize) return 0; strcpy(buf, option); return strlen(option) + 1; @@ -416,7 +416,7 @@ static CURLcode tftp_connect_for_tx(tftp_state_data_t *state, { CURLcode result; #ifndef CURL_DISABLE_VERBOSE_STRINGS - struct SessionHandle *data = state->conn->data; + struct Curl_easy *data = state->conn->data; infof(data, "%s\n", "Connected for transmit"); #endif @@ -432,7 +432,7 @@ static CURLcode tftp_connect_for_rx(tftp_state_data_t *state, { CURLcode result; #ifndef CURL_DISABLE_VERBOSE_STRINGS - struct SessionHandle *data = state->conn->data; + struct Curl_easy *data = state->conn->data; infof(data, "%s\n", "Connected for receive"); #endif @@ -450,7 +450,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) const char *mode = "octet"; char *filename; char buf[64]; - struct SessionHandle *data = state->conn->data; + struct Curl_easy *data = state->conn->data; CURLcode result = CURLE_OK; /* Set ascii mode if -B flag was used */ @@ -494,33 +494,36 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) "%s%c%s%c", filename, '\0', mode, '\0'); sbytes = 4 + strlen(filename) + strlen(mode); - /* add tsize option */ - if(data->set.upload && (data->state.infilesize != -1)) - snprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T, - data->state.infilesize); - else - strcpy(buf, "0"); /* the destination is large enough */ - - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, - TFTP_OPTION_TSIZE); - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, buf); - /* add blksize option */ - snprintf( buf, sizeof(buf), "%d", state->requested_blksize ); - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, - TFTP_OPTION_BLKSIZE); - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, buf ); - - /* add timeout option */ - snprintf( buf, sizeof(buf), "%d", state->retry_time); - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, - TFTP_OPTION_INTERVAL); - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, buf ); + /* optional addition of TFTP options */ + if(!data->set.tftp_no_options) { + /* add tsize option */ + if(data->set.upload && (data->state.infilesize != -1)) + snprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T, + data->state.infilesize); + else + strcpy(buf, "0"); /* the destination is large enough */ + + sbytes += tftp_option_add(state, sbytes, + (char *)state->spacket.data+sbytes, + TFTP_OPTION_TSIZE); + sbytes += tftp_option_add(state, sbytes, + (char *)state->spacket.data+sbytes, buf); + /* add blksize option */ + snprintf(buf, sizeof(buf), "%d", state->requested_blksize); + sbytes += tftp_option_add(state, sbytes, + (char *)state->spacket.data+sbytes, + TFTP_OPTION_BLKSIZE); + sbytes += tftp_option_add(state, sbytes, + (char *)state->spacket.data+sbytes, buf); + + /* add timeout option */ + snprintf(buf, sizeof(buf), "%d", state->retry_time); + sbytes += tftp_option_add(state, sbytes, + (char *)state->spacket.data+sbytes, + TFTP_OPTION_INTERVAL); + sbytes += tftp_option_add(state, sbytes, + (char *)state->spacket.data+sbytes, buf); + } /* the typecase for the 3rd argument is mostly for systems that do not have a size_t argument, like older unixes that want an 'int' */ @@ -578,7 +581,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) { ssize_t sbytes; int rblock; - struct SessionHandle *data = state->conn->data; + struct Curl_easy *data = state->conn->data; switch(event) { @@ -697,7 +700,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) **********************************************************/ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) { - struct SessionHandle *data = state->conn->data; + struct Curl_easy *data = state->conn->data; ssize_t sbytes; int rblock; CURLcode result = CURLE_OK; @@ -886,7 +889,7 @@ static CURLcode tftp_state_machine(tftp_state_data_t *state, tftp_event_t event) { CURLcode result = CURLE_OK; - struct SessionHandle *data = state->conn->data; + struct Curl_easy *data = state->conn->data; switch(state->state) { case TFTP_STATE_START: @@ -957,7 +960,7 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done) /* alloc pkt buffers based on specified blksize */ if(conn->data->set.tftp_blksize) { blksize = (int)conn->data->set.tftp_blksize; - if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN ) + if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN) return CURLE_TFTP_ILLEGAL; } @@ -975,7 +978,7 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done) return CURLE_OUT_OF_MEMORY; } - /* we don't keep TFTP connections up bascially because there's none or very + /* we don't keep TFTP connections up basically because there's none or very * little gain for UDP */ connclose(conn, "TFTP"); @@ -1078,7 +1081,7 @@ static CURLcode tftp_receive_packet(struct connectdata *conn) struct Curl_sockaddr_storage fromaddr; curl_socklen_t fromlen; CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; struct SingleRequest *k = &data->req; @@ -1197,7 +1200,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) int rc; tftp_event_t event; CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; long timeout_ms = tftp_state_timeout(conn, &event); @@ -1339,7 +1342,7 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done) static CURLcode tftp_setup_connection(struct connectdata * conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char * type; char command; diff --git a/lib/tftp.h b/lib/tftp.h index 117b40f..c2325b2 100644 --- a/lib/tftp.h +++ b/lib/tftp.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/timeval.c b/lib/timeval.c index 45731ac..629f1c8 100644 --- a/lib/timeval.c +++ b/lib/timeval.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -113,10 +113,18 @@ struct timeval curlx_tvnow(void) * Make sure that the first argument is the more recent time, as otherwise * we'll get a weird negative time-diff back... * - * Returns: the time difference in number of milliseconds. + * Returns: the time difference in number of milliseconds. For large diffs it + * returns 0x7fffffff on 32bit time_t systems. */ long curlx_tvdiff(struct timeval newer, struct timeval older) { +#if SIZEOF_TIME_T < 8 + /* for 32bit time_t systems, add a precaution to avoid overflow for really + big time differences */ + time_t diff = newer.tv_sec-older.tv_sec; + if(diff >= (0x7fffffff/1000)) + return 0x7fffffff; +#endif return (newer.tv_sec-older.tv_sec)*1000+ (long)(newer.tv_usec-older.tv_usec)/1000; } diff --git a/lib/timeval.h b/lib/timeval.h index 3f1b9ea..50c31a2 100644 --- a/lib/timeval.h +++ b/lib/timeval.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/transfer.c b/lib/transfer.c index 718139b..f5987fe 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -71,17 +71,13 @@ #include "url.h" #include "getinfo.h" #include "vtls/vtls.h" -#include "http_digest.h" -#include "curl_ntlm.h" -#include "http_negotiate.h" -#include "share.h" #include "select.h" #include "multiif.h" #include "connect.h" #include "non-ascii.h" -#include "curl_printf.h" -/* The last #include files should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" @@ -91,7 +87,7 @@ */ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; size_t buffersize = (size_t)bytes; int nread; #ifdef CURL_DOES_CONVERSIONS @@ -115,8 +111,8 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) /* this function returns a size_t, so we typecast to int to prevent warnings with picky compilers */ - nread = (int)data->set.fread_func(data->req.upload_fromhere, 1, - buffersize, data->set.in); + nread = (int)data->state.fread_func(data->req.upload_fromhere, 1, + buffersize, data->state.in); if(nread == CURL_READFUNC_ABORT) { failf(data, "operation aborted by callback"); @@ -246,7 +242,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) */ CURLcode Curl_readrewind(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; conn->bits.rewindaftersend = FALSE; /* we rewind now */ @@ -289,8 +285,8 @@ CURLcode Curl_readrewind(struct connectdata *conn) /* If no CURLOPT_READFUNCTION is used, we know that we operate on a given FILE * stream and we can actually attempt to rewind that ourselves with fseek() */ - if(data->set.fread_func == (curl_read_callback)fread) { - if(-1 != fseek(data->set.in, 0, SEEK_SET)) + if(data->state.fread_func == (curl_read_callback)fread) { + if(-1 != fseek(data->state.in, 0, SEEK_SET)) /* successful rewind */ return CURLE_OK; } @@ -356,7 +352,7 @@ static void read_rewind(struct connectdata *conn, * Check to see if CURLOPT_TIMECONDITION was met by comparing the time of the * remote document with the time provided by CURLOPT_TIMEVAL */ -bool Curl_meets_timecondition(struct SessionHandle *data, time_t timeofdoc) +bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc) { if((timeofdoc == 0) || (data->set.timevalue == 0)) return TRUE; @@ -389,7 +385,7 @@ bool Curl_meets_timecondition(struct SessionHandle *data, time_t timeofdoc) * the stream was rewound (in which case we have data in a * buffer) */ -static CURLcode readwrite_data(struct SessionHandle *data, +static CURLcode readwrite_data(struct Curl_easy *data, struct connectdata *conn, struct SingleRequest *k, int *didwhat, bool *done) @@ -399,6 +395,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, size_t excess = 0; /* excess bytes read */ bool is_empty_data = FALSE; bool readmore = FALSE; /* used by RTP to signal for more data */ + int maxloops = 100; *done = FALSE; @@ -409,7 +406,18 @@ static CURLcode readwrite_data(struct SessionHandle *data, data->set.buffer_size : BUFSIZE; size_t bytestoread = buffersize; - if(k->size != -1 && !k->header) { + if( +#if defined(USE_NGHTTP2) + /* For HTTP/2, read data without caring about the content + length. This is safe because body in HTTP/2 is always + segmented thanks to its framing layer. Meanwhile, we have to + call Curl_read to ensure that http2_handle_stream_close is + called when we read all incoming bytes for a particular + stream. */ + !((conn->handler->protocol & PROTO_FAMILY_HTTP) && + conn->httpversion == 20) && +#endif + k->size != -1 && !k->header) { /* make sure we don't read "too much" if we can help it since we might be pipelining and then someone else might want to read what follows! */ @@ -686,7 +694,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, } nread = (ssize_t) (k->maxdownload - k->bytecount); - if(nread < 0 ) /* this should be unusual */ + if(nread < 0) /* this should be unusual */ nread = 0; k->keepon &= ~KEEP_RECV; /* we're done reading */ @@ -771,7 +779,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, return result; } - } /* if(! header and data to read ) */ + } /* if(!header and data to read) */ if(conn->handler->readwrite && (excess > 0 && !conn->bits.stream_was_rewound)) { @@ -794,10 +802,10 @@ static CURLcode readwrite_data(struct SessionHandle *data, k->keepon &= ~KEEP_RECV; } - } while(data_pending(conn)); + } while(data_pending(conn) && maxloops--); if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) && - conn->bits.close ) { + conn->bits.close) { /* When we've read the entire thing and the close bit is set, the server may now close the connection. If there's now any kind of sending going on from our side, we need to stop that immediately. */ @@ -808,10 +816,24 @@ static CURLcode readwrite_data(struct SessionHandle *data, return CURLE_OK; } +static CURLcode done_sending(struct connectdata *conn, + struct SingleRequest *k) +{ + k->keepon &= ~KEEP_SEND; /* we're done writing */ + + if(conn->bits.rewindaftersend) { + CURLcode result = Curl_readrewind(conn); + if(result) + return result; + } + return CURLE_OK; +} + + /* * Send data to upload to the server, when the socket is writable. */ -static CURLcode readwrite_upload(struct SessionHandle *data, +static CURLcode readwrite_upload(struct Curl_easy *data, struct connectdata *conn, struct SingleRequest *k, int *didwhat) @@ -879,14 +901,9 @@ static CURLcode readwrite_upload(struct SessionHandle *data, break; } else if(nread<=0) { - /* done */ - k->keepon &= ~KEEP_SEND; /* we're done writing */ - - if(conn->bits.rewindaftersend) { - result = Curl_readrewind(conn); - if(result) - return result; - } + result = done_sending(conn, k); + if(result) + return result; break; } @@ -923,7 +940,8 @@ static CURLcode readwrite_upload(struct SessionHandle *data, if(!data->set.crlf) { /* we're here only because FTP is in ASCII mode... bump infilesize for the LF we just added */ - data->state.infilesize++; + if(data->state.infilesize != -1) + data->state.infilesize++; } } else @@ -995,8 +1013,9 @@ static CURLcode readwrite_upload(struct SessionHandle *data, data->req.upload_present = 0; /* no more bytes left */ if(k->upload_done) { - /* switch off writing, we're done! */ - k->keepon &= ~KEEP_SEND; /* we're done writing */ + result = done_sending(conn, k); + if(result) + return result; } } @@ -1012,7 +1031,7 @@ static CURLcode readwrite_upload(struct SessionHandle *data, * be read and written to/from the connection. */ CURLcode Curl_readwrite(struct connectdata *conn, - struct SessionHandle *data, + struct Curl_easy *data, bool *done) { struct SingleRequest *k = &data->req; @@ -1189,7 +1208,7 @@ int Curl_single_getsock(const struct connectdata *conn, of sockets */ int numsocks) { - const struct SessionHandle *data = conn->data; + const struct Curl_easy *data = conn->data; int bitmap = GETSOCK_BLANK; unsigned sockindex = 0; @@ -1284,10 +1303,20 @@ long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, return (long)rv; } +/* Curl_init_CONNECT() gets called each time the handle switches to CONNECT + which means this gets called once for each subsequent redirect etc */ +void Curl_init_CONNECT(struct Curl_easy *data) +{ + data->state.fread_func = data->set.fread_func_set; + data->state.in = data->set.in_set; +} + /* - * Curl_pretransfer() is called immediately before a transfer starts. + * Curl_pretransfer() is called immediately before a transfer starts, and only + * once for one transfer no matter if it has redirects or do multi-pass + * authentication etc. */ -CURLcode Curl_pretransfer(struct SessionHandle *data) +CURLcode Curl_pretransfer(struct Curl_easy *data) { CURLcode result; if(!data->change.url) { @@ -1356,6 +1385,16 @@ CURLcode Curl_pretransfer(struct SessionHandle *data) consider to be fine */ data->state.authhost.picked &= data->state.authhost.want; data->state.authproxy.picked &= data->state.authproxy.want; + + if(data->set.wildcardmatch) { + struct WildcardData *wc = &data->wildcard; + if(!wc->filelist) { + result = Curl_wildcard_init(wc); /* init wildcard structures */ + if(result) + return CURLE_OUT_OF_MEMORY; + } + } + } return result; @@ -1364,7 +1403,7 @@ CURLcode Curl_pretransfer(struct SessionHandle *data) /* * Curl_posttransfer() is called immediately after a transfer ends */ -CURLcode Curl_posttransfer(struct SessionHandle *data) +CURLcode Curl_posttransfer(struct Curl_easy *data) { #if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL) /* restore the signal handler for SIGPIPE before we get back */ @@ -1384,16 +1423,18 @@ CURLcode Curl_posttransfer(struct SessionHandle *data) */ static size_t strlen_url(const char *url) { - const char *ptr; + const unsigned char *ptr; size_t newlen=0; bool left=TRUE; /* left side of the ? */ - for(ptr=url; *ptr; ptr++) { + for(ptr=(unsigned char *)url; *ptr; ptr++) { switch(*ptr) { case '?': left=FALSE; /* fall through */ default: + if(*ptr >= 0x80) + newlen += 2; newlen++; break; case ' ': @@ -1414,9 +1455,9 @@ static void strcpy_url(char *output, const char *url) { /* we must add this with whitespace-replacing */ bool left=TRUE; - const char *iptr; + const unsigned char *iptr; char *optr = output; - for(iptr = url; /* read from here */ + for(iptr = (unsigned char *)url; /* read from here */ *iptr; /* until zero byte */ iptr++) { switch(*iptr) { @@ -1424,7 +1465,12 @@ static void strcpy_url(char *output, const char *url) left=FALSE; /* fall through */ default: - *optr++=*iptr; + if(*iptr >= 0x80) { + snprintf(optr, 4, "%%%02x", *iptr); + optr += 3; + } + else + *optr++=*iptr; break; case ' ': if(left) { @@ -1614,7 +1660,7 @@ static char *concat_url(const char *base, const char *relurl) * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string * as given by the remote server and set up the new URL to request. */ -CURLcode Curl_follow(struct SessionHandle *data, +CURLcode Curl_follow(struct Curl_easy *data, char *newurl, /* this 'newurl' is the Location: string, and it must be malloc()ed before passed here */ @@ -1672,23 +1718,21 @@ CURLcode Curl_follow(struct SessionHandle *data, newurl = absolute; } else { + /* The new URL MAY contain space or high byte values, that means a mighty + stupid redirect URL but we still make an effort to do "right". */ + char *newest; + size_t newlen = strlen_url(newurl); + /* This is an absolute URL, don't allow the custom port number */ disallowport = TRUE; - if(strchr(newurl, ' ')) { - /* This new URL contains at least one space, this is a mighty stupid - redirect but we still make an effort to do "right". */ - char *newest; - size_t newlen = strlen_url(newurl); - - newest = malloc(newlen+1); /* get memory for this */ - if(!newest) - return CURLE_OUT_OF_MEMORY; - strcpy_url(newest, newurl); /* create a space-free URL */ + newest = malloc(newlen+1); /* get memory for this */ + if(!newest) + return CURLE_OUT_OF_MEMORY; + strcpy_url(newest, newurl); /* create a space-free URL */ - free(newurl); /* that was no good */ - newurl = newest; /* use this instead now */ - } + free(newurl); /* that was no good */ + newurl = newest; /* use this instead now */ } @@ -1814,70 +1858,13 @@ CURLcode Curl_follow(struct SessionHandle *data, #endif /* CURL_DISABLE_HTTP */ } -CURLcode -Curl_reconnect_request(struct connectdata **connp) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = *connp; - struct SessionHandle *data = conn->data; - - /* This was a re-use of a connection and we got a write error in the - * DO-phase. Then we DISCONNECT this connection and have another attempt to - * CONNECT and then DO again! The retry cannot possibly find another - * connection to re-use, since we only keep one possible connection for - * each. */ - - infof(data, "Re-used connection seems dead, get a new one\n"); - - connclose(conn, "Reconnect dead connection"); /* enforce close */ - result = Curl_done(&conn, result, FALSE); /* we are so done with this */ - - /* conn may no longer be a good pointer, clear it to avoid mistakes by - parent functions */ - *connp = NULL; - - /* - * According to bug report #1330310. We need to check for CURLE_SEND_ERROR - * here as well. I figure this could happen when the request failed on a FTP - * connection and thus Curl_done() itself tried to use the connection - * (again). Slight Lack of feedback in the report, but I don't think this - * extra check can do much harm. - */ - if(!result || (CURLE_SEND_ERROR == result)) { - bool async; - bool protocol_done = TRUE; - - /* Now, redo the connect and get a new connection */ - result = Curl_connect(data, connp, &async, &protocol_done); - if(!result) { - /* We have connected or sent away a name resolve query fine */ - - conn = *connp; /* setup conn to again point to something nice */ - if(async) { - /* Now, if async is TRUE here, we need to wait for the name - to resolve */ - result = Curl_resolver_wait_resolv(conn, NULL); - if(result) - return result; - - /* Resolved, continue with the connection */ - result = Curl_async_resolved(conn, &protocol_done); - if(result) - return result; - } - } - } - - return result; -} - /* Returns CURLE_OK *and* sets '*url' if a request retry is wanted. NOTE: that the *url is malloc()ed. */ CURLcode Curl_retry_request(struct connectdata *conn, char **url) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; *url = NULL; @@ -1933,7 +1920,7 @@ Curl_setup_transfer( curl_off_t *writecountp /* return number of bytes written or NULL */ ) { - struct SessionHandle *data; + struct Curl_easy *data; struct SingleRequest *k; DEBUGASSERT(conn != NULL); diff --git a/lib/transfer.h b/lib/transfer.h index 316aeae..0e253e3 100644 --- a/lib/transfer.h +++ b/lib/transfer.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,9 +22,11 @@ * ***************************************************************************/ -CURLcode Curl_pretransfer(struct SessionHandle *data); +void Curl_init_CONNECT(struct Curl_easy *data); + +CURLcode Curl_pretransfer(struct Curl_easy *data); CURLcode Curl_second_connect(struct connectdata *conn); -CURLcode Curl_posttransfer(struct SessionHandle *data); +CURLcode Curl_posttransfer(struct Curl_easy *data); typedef enum { FOLLOW_NONE, /* not used within the function, just a placeholder to @@ -36,20 +38,19 @@ typedef enum { FOLLOW_LAST /* never used */ } followtype; -CURLcode Curl_follow(struct SessionHandle *data, char *newurl, +CURLcode Curl_follow(struct Curl_easy *data, char *newurl, followtype type); CURLcode Curl_readwrite(struct connectdata *conn, - struct SessionHandle *data, bool *done); + struct Curl_easy *data, bool *done); int Curl_single_getsock(const struct connectdata *conn, curl_socket_t *socks, int numsocks); CURLcode Curl_readrewind(struct connectdata *conn); CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp); -CURLcode Curl_reconnect_request(struct connectdata **connp); CURLcode Curl_retry_request(struct connectdata *conn, char **url); -bool Curl_meets_timecondition(struct SessionHandle *data, time_t timeofdoc); +bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc); /* This sets up a forthcoming transfer */ void diff --git a/lib/url.c b/lib/url.c index 406c1f0..e547e5c 100644 --- a/lib/url.c +++ b/lib/url.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -75,7 +75,7 @@ void idn_free (void *ptr); #endif #elif defined(USE_WIN32_IDN) /* prototype for curl_win32_idn_to_ascii() */ -int curl_win32_idn_to_ascii(const char *in, char **out); +bool curl_win32_idn_to_ascii(const char *in, char **out); #endif /* USE_LIBIDN */ #include "urldata.h" @@ -111,6 +111,7 @@ int curl_win32_idn_to_ascii(const char *in, char **out); #include "telnet.h" #include "tftp.h" #include "http.h" +#include "http2.h" #include "file.h" #include "curl_ldap.h" #include "ssh.h" @@ -118,7 +119,7 @@ int curl_win32_idn_to_ascii(const char *in, char **out); #include "url.h" #include "connect.h" #include "inet_ntop.h" -#include "curl_ntlm.h" +#include "http_ntlm.h" #include "curl_ntlm_wb.h" #include "socks.h" #include "curl_rtmp.h" @@ -129,26 +130,27 @@ int curl_win32_idn_to_ascii(const char *in, char **out); #include "pipeline.h" #include "dotdot.h" #include "strdup.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* Local static prototypes */ static struct connectdata * -find_oldest_idle_connection(struct SessionHandle *data); -static struct connectdata * -find_oldest_idle_connection_in_bundle(struct SessionHandle *data, +find_oldest_idle_connection_in_bundle(struct Curl_easy *data, struct connectbundle *bundle); static void conn_free(struct connectdata *conn); +static void free_fixed_hostname(struct hostname *host); static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke); -static CURLcode parse_url_login(struct SessionHandle *data, +static CURLcode parse_url_login(struct Curl_easy *data, struct connectdata *conn, char **userptr, char **passwdptr, char **optionsptr); static CURLcode parse_login_details(const char *login, const size_t len, char **userptr, char **passwdptr, char **optionsptr); +static unsigned int get_protocol_family(unsigned int protocol); + /* * Protocol table. */ @@ -275,7 +277,7 @@ static const struct Curl_handler Curl_handler_dummy = { PROTOPT_NONE /* flags */ }; -void Curl_freeset(struct SessionHandle *data) +void Curl_freeset(struct Curl_easy *data) { /* Free all dynamic strings stored in the data->set substructure. */ enum dupstring i; @@ -295,7 +297,7 @@ void Curl_freeset(struct SessionHandle *data) data->change.url = NULL; } -static CURLcode setstropt(char **charp, char *s) +static CURLcode setstropt(char **charp, const char *s) { /* Release the previous storage at `charp' and replace by a dynamic storage copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */ @@ -303,12 +305,12 @@ static CURLcode setstropt(char **charp, char *s) Curl_safefree(*charp); if(s) { - s = strdup(s); + char *str = strdup(s); - if(!s) + if(!str) return CURLE_OUT_OF_MEMORY; - *charp = s; + *charp = str; } return CURLE_OK; @@ -353,7 +355,7 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp) return result; } -CURLcode Curl_dupset(struct SessionHandle *dst, struct SessionHandle *src) +CURLcode Curl_dupset(struct Curl_easy *dst, struct Curl_easy *src) { CURLcode result = CURLE_OK; enum dupstring i; @@ -396,7 +398,7 @@ CURLcode Curl_dupset(struct SessionHandle *dst, struct SessionHandle *src) * when curl_easy_perform() is invoked. */ -CURLcode Curl_close(struct SessionHandle *data) +CURLcode Curl_close(struct Curl_easy *data) { struct Curl_multi *m; @@ -482,28 +484,34 @@ CURLcode Curl_close(struct SessionHandle *data) Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); } + if(data->set.wildcardmatch) { + /* destruct wildcard structures if it is needed */ + struct WildcardData *wc = &data->wildcard; + Curl_wildcard_dtor(wc); + } + Curl_freeset(data); free(data); return CURLE_OK; } /* - * Initialize the UserDefined fields within a SessionHandle. - * This may be safely called on a new or existing SessionHandle. + * Initialize the UserDefined fields within a Curl_easy. + * This may be safely called on a new or existing Curl_easy. */ CURLcode Curl_init_userdefined(struct UserDefined *set) { CURLcode result = CURLE_OK; set->out = stdout; /* default output to stdout */ - set->in = stdin; /* default input from stdin */ + set->in_set = stdin; /* default input from stdin */ set->err = stderr; /* default stderr to stderr */ /* use fwrite as default function to store output */ set->fwrite_func = (curl_write_callback)fwrite; /* use fread as default function to read input */ - set->fread_func = (curl_read_callback)fread; + set->fread_func_set = (curl_read_callback)fread; set->is_fread_set = 0; set->is_fwrite_set = 0; @@ -569,33 +577,16 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) * seem not to follow rfc1961 section 4.3/4.4 */ set->socks5_gssapi_nec = FALSE; - /* set default GSS-API service name */ - result = setstropt(&set->str[STRING_SOCKS5_GSSAPI_SERVICE], - (char *) CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE); - if(result) - return result; - - /* set default negotiate proxy service name */ - result = setstropt(&set->str[STRING_PROXY_SERVICE_NAME], - (char *) CURL_DEFAULT_PROXY_SERVICE_NAME); - if(result) - return result; - - /* set default negotiate service name */ - result = setstropt(&set->str[STRING_SERVICE_NAME], - (char *) CURL_DEFAULT_SERVICE_NAME); - if(result) - return result; #endif /* This is our preferred CA cert bundle/path since install time */ #if defined(CURL_CA_BUNDLE) - result = setstropt(&set->str[STRING_SSL_CAFILE], (char *) CURL_CA_BUNDLE); + result = setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE); if(result) return result; #endif #if defined(CURL_CA_PATH) - result = setstropt(&set->str[STRING_SSL_CAPATH], (char *) CURL_CA_PATH); + result = setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH); if(result) return result; #endif @@ -610,12 +601,15 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) set->tcp_keepalive = FALSE; set->tcp_keepintvl = 60; set->tcp_keepidle = 60; + set->tcp_fastopen = FALSE; set->ssl_enable_npn = TRUE; set->ssl_enable_alpn = TRUE; set->expect_100_timeout = 1000L; /* Wait for a second by default. */ set->sep_headers = TRUE; /* separated header lists by default */ + + Curl_http2_init_userset(set); return result; } @@ -627,16 +621,16 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) * @return CURLcode */ -CURLcode Curl_open(struct SessionHandle **curl) +CURLcode Curl_open(struct Curl_easy **curl) { CURLcode result; - struct SessionHandle *data; + struct Curl_easy *data; /* Very simple start-up: alloc the struct, init it with zeroes and return */ - data = calloc(1, sizeof(struct SessionHandle)); + data = calloc(1, sizeof(struct Curl_easy)); if(!data) { /* this is a very serious error */ - DEBUGF(fprintf(stderr, "Error: calloc of SessionHandle failed\n")); + DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n")); return CURLE_OUT_OF_MEMORY; } @@ -673,6 +667,8 @@ CURLcode Curl_open(struct SessionHandle **curl) data->wildcard.filelist = NULL; data->set.fnmatch = ZERO_NULL; data->set.maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ + + Curl_http2_init_state(&data->state); } if(result) { @@ -688,7 +684,7 @@ CURLcode Curl_open(struct SessionHandle **curl) return result; } -CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, +CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, va_list param) { char *argptr; @@ -705,7 +701,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, case CURLOPT_DNS_USE_GLOBAL_CACHE: /* remember we want this enabled */ arg = va_arg(param, long); - data->set.global_dns_cache = (0 != arg)?TRUE:FALSE; + data->set.global_dns_cache = (0 != arg) ? TRUE : FALSE; break; case CURLOPT_SSL_CIPHER_LIST: /* set a list of cipher we want to use in the SSL connection */ @@ -740,33 +736,33 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * When this transfer is done, it must not be left to be reused by a * subsequent transfer but shall be closed immediately. */ - data->set.reuse_forbid = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.reuse_forbid = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FRESH_CONNECT: /* * This transfer shall not use a previously cached connection but * should be made with a fresh new connect! */ - data->set.reuse_fresh = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.reuse_fresh = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_VERBOSE: /* * Verbose means infof() calls that give a lot of information about * the connection and transfer procedures as well as internal choices. */ - data->set.verbose = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.verbose = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_HEADER: /* * Set to include the header in the general data output stream. */ - data->set.include_header = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.include_header = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_NOPROGRESS: /* * Shut off the internal supported progress meter */ - data->set.hide_progress = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.hide_progress = (0 != va_arg(param, long)) ? TRUE : FALSE; if(data->set.hide_progress) data->progress.flags |= PGRS_HIDE; else @@ -776,14 +772,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Do not include the body part in the output data stream. */ - data->set.opt_no_body = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FAILONERROR: /* * Don't output the >=400 error code HTML-page, but instead only * return error. */ - data->set.http_fail_on_error = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.http_fail_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_UPLOAD: case CURLOPT_PUT: @@ -791,7 +787,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * We want to sent data to the remote host. If this is HTTP, that equals * using the PUT request. */ - data->set.upload = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE; if(data->set.upload) { /* If this is HTTP, PUT is what's needed to "upload" */ data->set.httpreq = HTTPREQ_PUT; @@ -807,7 +803,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Try to get the file time of the remote document. The time will * later (possibly) become available using curl_easy_getinfo(). */ - data->set.get_filetime = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.get_filetime = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_CREATE_MISSING_DIRS: /* @@ -835,11 +831,18 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Option that specifies how quickly an server response must be obtained * before it is considered failure. For pingpong protocols. */ - data->set.server_response_timeout = va_arg( param , long ) * 1000; + data->set.server_response_timeout = va_arg(param, long) * 1000; + break; + case CURLOPT_TFTP_NO_OPTIONS: + /* + * Option that prevents libcurl from sending TFTP option requests to the + * server. + */ + data->set.tftp_no_options = va_arg(param, long) != 0; break; case CURLOPT_TFTP_BLKSIZE: /* - * TFTP option that specifies the block size to use for data transmission + * TFTP option that specifies the block size to use for data transmission. */ data->set.tftp_blksize = va_arg(param, long); break; @@ -848,13 +851,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * An option that changes the command to one that asks for a list * only, no file info details. */ - data->set.ftp_list_only = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ftp_list_only = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_APPEND: /* * We want to upload and append to an existing file. */ - data->set.ftp_append = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ftp_append = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_FILEMETHOD: /* @@ -882,7 +885,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * * Transfer using ASCII (instead of BINARY). */ - data->set.prefer_ascii = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.prefer_ascii = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_TIMECONDITION: /* @@ -915,7 +918,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Switch on automatic referer that gets set if curl follows locations. */ - data->set.http_auto_referer = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.http_auto_referer = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_ACCEPT_ENCODING: @@ -931,18 +934,19 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, argptr = va_arg(param, char *); result = setstropt(&data->set.str[STRING_ENCODING], (argptr && !*argptr)? - (char *) ALL_CONTENT_ENCODINGS: argptr); + ALL_CONTENT_ENCODINGS: argptr); break; case CURLOPT_TRANSFER_ENCODING: - data->set.http_transfer_encoding = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.http_transfer_encoding = (0 != va_arg(param, long)) ? + TRUE : FALSE; break; case CURLOPT_FOLLOWLOCATION: /* * Follow Location: header hints on a HTTP-server. */ - data->set.http_follow_location = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.http_follow_location = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_UNRESTRICTED_AUTH: @@ -951,7 +955,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * hostname changed. */ data->set.http_disable_hostname_check_before_authentication = - (0 != va_arg(param, long))?TRUE:FALSE; + (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_MAXREDIRS: @@ -1212,7 +1216,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * We run mostly with the original cookie spec, as hardly anyone implements * anything else. */ - data->set.cookiesession = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.cookiesession = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_COOKIELIST: @@ -1289,7 +1293,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ arg = va_arg(param, long); #ifndef USE_NGHTTP2 - if(arg == CURL_HTTP_VERSION_2_0) + if(arg >= CURL_HTTP_VERSION_2) return CURLE_UNSUPPORTED_PROTOCOL; #endif data->set.httpversion = arg; @@ -1311,7 +1315,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* the DIGEST_IE bit is only used to set a special marker, for all the rest we need to handle it as normal DIGEST */ - data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE)?TRUE:FALSE; + data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE; if(auth & CURLAUTH_DIGEST_IE) { auth |= CURLAUTH_DIGEST; /* set standard digest bit */ @@ -1374,7 +1378,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Tunnel operations through the proxy instead of normal proxy use */ - data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long)) ? + TRUE : FALSE; break; case CURLOPT_PROXYPORT: @@ -1400,7 +1405,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* the DIGEST_IE bit is only used to set a special marker, for all the rest we need to handle it as normal DIGEST */ - data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE)?TRUE:FALSE; + data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE; if(auth & CURLAUTH_DIGEST_IE) { auth |= CURLAUTH_DIGEST; /* set standard digest bit */ @@ -1475,32 +1480,28 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, #endif /* CURL_DISABLE_PROXY */ #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - case CURLOPT_SOCKS5_GSSAPI_SERVICE: + case CURLOPT_SOCKS5_GSSAPI_NEC: /* - * Set GSS-API service name + * Set flag for NEC SOCK5 support */ - result = setstropt(&data->set.str[STRING_SOCKS5_GSSAPI_SERVICE], - va_arg(param, char *)); + data->set.socks5_gssapi_nec = (0 != va_arg(param, long)) ? TRUE : FALSE; break; + case CURLOPT_SOCKS5_GSSAPI_SERVICE: case CURLOPT_PROXY_SERVICE_NAME: /* - * Set negotiate proxy service name + * Set proxy authentication service name for Kerberos 5 and SPNEGO */ result = setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME], va_arg(param, char *)); break; +#endif - case CURLOPT_SOCKS5_GSSAPI_NEC: - /* - * set flag for nec socks5 support - */ - data->set.socks5_gssapi_nec = (0 != va_arg(param, long))?TRUE:FALSE; - break; - +#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \ + defined(USE_SPNEGO) case CURLOPT_SERVICE_NAME: /* - * Set negotiate service identity + * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO */ result = setstropt(&data->set.str[STRING_SERVICE_NAME], va_arg(param, char *)); @@ -1534,20 +1535,19 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ result = setstropt(&data->set.str[STRING_FTPPORT], va_arg(param, char *)); - data->set.ftp_use_port = (NULL != data->set.str[STRING_FTPPORT]) ? - TRUE:FALSE; + data->set.ftp_use_port = (data->set.str[STRING_FTPPORT]) ? TRUE : FALSE; break; case CURLOPT_FTP_USE_EPRT: - data->set.ftp_use_eprt = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ftp_use_eprt = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_USE_EPSV: - data->set.ftp_use_epsv = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ftp_use_epsv = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_USE_PRET: - data->set.ftp_use_pret = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ftp_use_pret = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_SSL_CCC: @@ -1559,7 +1559,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the * bypass of the IP address in PASV responses. */ - data->set.ftp_skip_ip = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ftp_skip_ip = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_READDATA: @@ -1567,7 +1567,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * FILE pointer to read the file to be uploaded from. Or possibly * used as argument to the read callback. */ - data->set.in = va_arg(param, void *); + data->set.in_set = va_arg(param, void *); break; case CURLOPT_INFILESIZE: /* @@ -1695,7 +1695,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, case CURLOPT_XOAUTH2_BEARER: /* - * XOAUTH2 bearer token to use in the operation + * OAuth 2.0 bearer token to use in the operation */ result = setstropt(&data->set.str[STRING_BEARER], va_arg(param, char *)); @@ -1862,11 +1862,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Read data callback */ - data->set.fread_func = va_arg(param, curl_read_callback); - if(!data->set.fread_func) { + data->set.fread_func_set = va_arg(param, curl_read_callback); + if(!data->set.fread_func_set) { data->set.is_fread_set = 0; /* When set to NULL, reset to our internal default function */ - data->set.fread_func = (curl_read_callback)fread; + data->set.fread_func_set = (curl_read_callback)fread; } else data->set.is_fread_set = 1; @@ -1967,7 +1967,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Kludgy option to enable CRLF conversions. Subject for removal. */ - data->set.crlf = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.crlf = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_INTERFACE: @@ -1996,7 +1996,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ result = setstropt(&data->set.str[STRING_KRB_LEVEL], va_arg(param, char *)); - data->set.krb = (NULL != data->set.str[STRING_KRB_LEVEL])?TRUE:FALSE; + data->set.krb = (data->set.str[STRING_KRB_LEVEL]) ? TRUE : FALSE; break; case CURLOPT_GSSAPI_DELEGATION: /* @@ -2008,7 +2008,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Enable peer SSL verifying. */ - data->set.ssl.verifypeer = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ssl.verifypeer = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_SSL_VERIFYHOST: /* @@ -2026,7 +2026,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, return CURLE_BAD_FUNCTION_ARGUMENT; } - data->set.ssl.verifyhost = (0 != arg)?TRUE:FALSE; + data->set.ssl.verifyhost = (0 != arg) ? TRUE : FALSE; break; case CURLOPT_SSL_VERIFYSTATUS: /* @@ -2037,7 +2037,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; } - data->set.ssl.verifystatus = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ssl.verifystatus = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_SSL_CTX_FUNCTION: #ifdef have_curlssl_ssl_ctx @@ -2068,22 +2068,26 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; } - data->set.ssl.falsestart = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ssl.falsestart = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_CERTINFO: #ifdef have_curlssl_certinfo - data->set.ssl.certinfo = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE; #else result = CURLE_NOT_BUILT_IN; #endif break; case CURLOPT_PINNEDPUBLICKEY: +#ifdef have_curlssl_pinnedpubkey /* only by supported backends */ /* * Set pinned public key for SSL connection. * Specify file name of the public key in DER format. */ result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY], va_arg(param, char *)); +#else + result = CURLE_NOT_BUILT_IN; +#endif break; case CURLOPT_CAINFO: /* @@ -2135,7 +2139,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ data->set.buffer_size = va_arg(param, long); - if((data->set.buffer_size> (BUFSIZE -1 )) || + if((data->set.buffer_size> (BUFSIZE -1)) || (data->set.buffer_size < 1)) data->set.buffer_size = 0; /* huge internal default */ @@ -2146,7 +2150,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * The application asks not to set any signal() or alarm() handlers, * even when using a timeout. */ - data->set.no_signal = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.no_signal = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_SHARE: @@ -2262,7 +2266,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Enable or disable TCP_NODELAY, which will disable/enable the Nagle * algorithm */ - data->set.tcp_nodelay = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.tcp_nodelay = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_ACCOUNT: @@ -2271,14 +2275,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_IGNORE_CONTENT_LENGTH: - data->set.ignorecl = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ignorecl = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_CONNECT_ONLY: /* * No data transfer, set up connection and let application use the socket */ - data->set.connect_only = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.connect_only = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_ALTERNATIVE_TO_USER: @@ -2331,7 +2335,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_SSL_SESSIONID_CACHE: - data->set.ssl.sessionid = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ssl.sessionid = (0 != va_arg(param, long)) ? TRUE : FALSE; break; #ifdef USE_LIBSSH2 @@ -2392,14 +2396,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * disable libcurl transfer encoding is used */ - data->set.http_te_skip = (0 == va_arg(param, long))?TRUE:FALSE; + data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_HTTP_CONTENT_DECODING: /* * raw data passed to the application when content encoding is used */ - data->set.http_ce_skip = (0 == va_arg(param, long))?TRUE:FALSE; + data->set.http_ce_skip = (0 == va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_NEW_FILE_PERMS: @@ -2441,6 +2445,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.redir_protocols = va_arg(param, long); break; + case CURLOPT_DEFAULT_PROTOCOL: + /* Set the protocol to use when the URL doesn't include any protocol */ + result = setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL], + va_arg(param, char *)); + break; + case CURLOPT_MAIL_FROM: /* Set the SMTP mail originator */ result = setstropt(&data->set.str[STRING_MAIL_FROM], @@ -2573,7 +2583,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_WILDCARDMATCH: - data->set.wildcardmatch = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.wildcardmatch = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_CHUNK_BGN_FUNCTION: data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback); @@ -2624,7 +2634,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_TCP_KEEPALIVE: - data->set.tcp_keepalive = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.tcp_keepalive = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_TCP_KEEPIDLE: data->set.tcp_keepidle = va_arg(param, long); @@ -2632,11 +2642,18 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, case CURLOPT_TCP_KEEPINTVL: data->set.tcp_keepintvl = va_arg(param, long); break; + case CURLOPT_TCP_FASTOPEN: +#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) + data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE; +#else + result = CURLE_NOT_BUILT_IN; +#endif + break; case CURLOPT_SSL_ENABLE_NPN: - data->set.ssl_enable_npn = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ssl_enable_npn = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_SSL_ENABLE_ALPN: - data->set.ssl_enable_alpn = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE; break; #ifdef USE_UNIX_SOCKETS @@ -2647,10 +2664,36 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, #endif case CURLOPT_PATH_AS_IS: - data->set.path_as_is = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.path_as_is = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_PIPEWAIT: - data->set.pipewait = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.pipewait = (0 != va_arg(param, long)) ? TRUE : FALSE; + break; + case CURLOPT_STREAM_WEIGHT: +#ifndef USE_NGHTTP2 + return CURLE_NOT_BUILT_IN; +#else + arg = va_arg(param, long); + if((arg>=1) && (arg <= 256)) + data->set.stream_weight = (int)arg; + break; +#endif + case CURLOPT_STREAM_DEPENDS: + case CURLOPT_STREAM_DEPENDS_E: + { +#ifndef USE_NGHTTP2 + return CURLE_NOT_BUILT_IN; +#else + struct Curl_easy *dep = va_arg(param, struct Curl_easy *); + if(dep && GOOD_EASY_HANDLE(dep)) { + data->set.stream_depends_on = dep; + data->set.stream_depends_e = (option == CURLOPT_STREAM_DEPENDS_E); + } + break; +#endif + } + case CURLOPT_CONNECT_TO: + data->set.connect_to = va_arg(param, struct curl_slist *); break; default: /* unknown tag and its companion, just ignore: */ @@ -2661,6 +2704,45 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, return result; } +#ifdef USE_RECV_BEFORE_SEND_WORKAROUND +static void conn_reset_postponed_data(struct connectdata *conn, int num) +{ + struct postponed_data * const psnd = &(conn->postponed[num]); + if(psnd->buffer) { + DEBUGASSERT(psnd->allocated_size > 0); + DEBUGASSERT(psnd->recv_size <= psnd->allocated_size); + DEBUGASSERT(psnd->recv_size ? + (psnd->recv_processed < psnd->recv_size) : + (psnd->recv_processed == 0)); + DEBUGASSERT(psnd->bindsock != CURL_SOCKET_BAD); + free(psnd->buffer); + psnd->buffer = NULL; + psnd->allocated_size = 0; + psnd->recv_size = 0; + psnd->recv_processed = 0; +#ifdef DEBUGBUILD + psnd->bindsock = CURL_SOCKET_BAD; /* used only for DEBUGASSERT */ +#endif /* DEBUGBUILD */ + } + else { + DEBUGASSERT (psnd->allocated_size == 0); + DEBUGASSERT (psnd->recv_size == 0); + DEBUGASSERT (psnd->recv_processed == 0); + DEBUGASSERT (psnd->bindsock == CURL_SOCKET_BAD); + } +} + +static void conn_reset_all_postponed_data(struct connectdata *conn) +{ + conn_reset_postponed_data(conn, 0); + conn_reset_postponed_data(conn, 1); +} +#else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ +/* Use "do-nothing" macros instead of functions when workaround not used */ +#define conn_reset_postponed_data(c,n) do {} WHILE_FALSE +#define conn_reset_all_postponed_data(c) do {} WHILE_FALSE +#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ + static void conn_free(struct connectdata *conn) { if(!conn) @@ -2691,7 +2773,7 @@ static void conn_free(struct connectdata *conn) Curl_safefree(conn->user); Curl_safefree(conn->passwd); - Curl_safefree(conn->xoauth2_bearer); + Curl_safefree(conn->oauth_bearer); Curl_safefree(conn->options); Curl_safefree(conn->proxyuser); Curl_safefree(conn->proxypasswd); @@ -2707,9 +2789,12 @@ static void conn_free(struct connectdata *conn) Curl_safefree(conn->allocptr.rtsp_transport); Curl_safefree(conn->trailer); Curl_safefree(conn->host.rawalloc); /* host name buffer */ + Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */ Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */ Curl_safefree(conn->master_buffer); + conn_reset_all_postponed_data(conn); + Curl_llist_destroy(conn->send_pipe, NULL); Curl_llist_destroy(conn->recv_pipe, NULL); @@ -2727,14 +2812,14 @@ static void conn_free(struct connectdata *conn) * primary connection, like when freeing room in the connection cache or * killing of a dead old connection. * - * This function MUST NOT reset state in the SessionHandle struct if that + * This function MUST NOT reset state in the Curl_easy struct if that * isn't strictly bound to the life-time of *this* particular connection. * */ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) { - struct SessionHandle *data; + struct Curl_easy *data; if(!conn) return CURLE_OK; /* this is closed and fine already */ data = conn->data; @@ -2764,23 +2849,9 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) infof(data, "Closing connection %ld\n", conn->connection_id); Curl_conncache_remove_conn(data->state.conn_cache, conn); -#if defined(USE_LIBIDN) - if(conn->host.encalloc) - idn_free(conn->host.encalloc); /* encoded host name buffer, must be freed - with idn_free() since this was allocated - by libidn */ - if(conn->proxy.encalloc) - idn_free(conn->proxy.encalloc); /* encoded proxy name buffer, must be - freed with idn_free() since this was - allocated by libidn */ -#elif defined(USE_WIN32_IDN) - free(conn->host.encalloc); /* encoded host name buffer, must be freed with - idn_free() since this was allocated by - curl_win32_idn_to_ascii */ - free(conn->proxy.encalloc); /* encoded proxy name buffer, must be freed - with idn_free() since this was allocated by - curl_win32_idn_to_ascii */ -#endif + free_fixed_hostname(&conn->host); + free_fixed_hostname(&conn->conn_to_host); + free_fixed_hostname(&conn->proxy); Curl_ssl_close(conn, FIRSTSOCKET); @@ -2817,7 +2888,7 @@ static bool SocketIsDead(curl_socket_t sock) * IsPipeliningPossible() returns TRUE if the options set would allow * pipelining/multiplexing and the connection is using a HTTP protocol. */ -static bool IsPipeliningPossible(const struct SessionHandle *handle, +static bool IsPipeliningPossible(const struct Curl_easy *handle, const struct connectdata *conn) { /* If a HTTP protocol and pipelining is enabled */ @@ -2831,25 +2902,27 @@ static bool IsPipeliningPossible(const struct SessionHandle *handle, return TRUE; if(Curl_pipeline_wanted(handle->multi, CURLPIPE_MULTIPLEX) && - (handle->set.httpversion == CURL_HTTP_VERSION_2_0)) + (handle->set.httpversion >= CURL_HTTP_VERSION_2)) /* allows HTTP/2 */ return TRUE; } return FALSE; } -int Curl_removeHandleFromPipeline(struct SessionHandle *handle, +int Curl_removeHandleFromPipeline(struct Curl_easy *handle, struct curl_llist *pipeline) { - struct curl_llist_element *curr; + if(pipeline) { + struct curl_llist_element *curr; - curr = pipeline->head; - while(curr) { - if(curr->ptr == handle) { - Curl_llist_remove(pipeline, curr, NULL); - return 1; /* we removed a handle */ + curr = pipeline->head; + while(curr) { + if(curr->ptr == handle) { + Curl_llist_remove(pipeline, curr, NULL); + return 1; /* we removed a handle */ + } + curr = curr->next; } - curr = curr->next; } return 0; @@ -2862,18 +2935,18 @@ static void Curl_printPipeline(struct curl_llist *pipeline) curr = pipeline->head; while(curr) { - struct SessionHandle *data = (struct SessionHandle *) curr->ptr; + struct Curl_easy *data = (struct Curl_easy *) curr->ptr; infof(data, "Handle in pipeline: %s\n", data->state.path); curr = curr->next; } } #endif -static struct SessionHandle* gethandleathead(struct curl_llist *pipeline) +static struct Curl_easy* gethandleathead(struct curl_llist *pipeline) { struct curl_llist_element *curr = pipeline->head; if(curr) { - return (struct SessionHandle *) curr->ptr; + return (struct Curl_easy *) curr->ptr; } return NULL; @@ -2881,7 +2954,7 @@ static struct SessionHandle* gethandleathead(struct curl_llist *pipeline) /* remove the specified connection from all (possible) pipelines and related queues */ -void Curl_getoff_all_pipelines(struct SessionHandle *data, +void Curl_getoff_all_pipelines(struct Curl_easy *data, struct connectdata *conn) { bool recv_head = (conn->readchannel_inuse && @@ -2905,7 +2978,7 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke) curr = pipeline->head; while(curr) { struct curl_llist_element *next = curr->next; - struct SessionHandle *data = (struct SessionHandle *) curr->ptr; + struct Curl_easy *data = (struct Curl_easy *) curr->ptr; #ifdef DEBUGBUILD /* debug-only code */ if(data->magic != CURLEASY_MAGIC_NUMBER) { @@ -2929,8 +3002,8 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke) * Returns the pointer to the oldest idle connection, or NULL if none was * found. */ -static struct connectdata * -find_oldest_idle_connection(struct SessionHandle *data) +struct connectdata * +Curl_oldest_idle_connection(struct Curl_easy *data) { struct conncache *bc = data->state.conn_cache; struct curl_hash_iterator iter; @@ -2982,7 +3055,7 @@ find_oldest_idle_connection(struct SessionHandle *data) * found. */ static struct connectdata * -find_oldest_idle_connection_in_bundle(struct SessionHandle *data, +find_oldest_idle_connection_in_bundle(struct Curl_easy *data, struct connectbundle *bundle) { struct curl_llist_element *curr; @@ -3022,7 +3095,7 @@ find_oldest_idle_connection_in_bundle(struct SessionHandle *data, * Returns TRUE if the connection actually was dead and disconnected. */ static bool disconnect_if_dead(struct connectdata *conn, - struct SessionHandle *data) + struct Curl_easy *data) { size_t pipeLen = conn->send_pipe->size + conn->recv_pipe->size; if(!pipeLen && !conn->inuse) { @@ -3056,7 +3129,7 @@ static bool disconnect_if_dead(struct connectdata *conn, static int call_disconnect_if_dead(struct connectdata *conn, void *param) { - struct SessionHandle* data = (struct SessionHandle*)param; + struct Curl_easy* data = (struct Curl_easy*)param; disconnect_if_dead(conn, data); return 0; /* continue iteration */ } @@ -3066,7 +3139,7 @@ static int call_disconnect_if_dead(struct connectdata *conn, * closes and removes them. * The cleanup is done at most once per second. */ -static void prune_dead_connections(struct SessionHandle *data) +static void prune_dead_connections(struct Curl_easy *data) { struct timeval now = Curl_tvnow(); long elapsed = Curl_tvdiff(now, data->state.conn_cache->last_cleanup); @@ -3098,7 +3171,7 @@ static size_t max_pipeline_length(struct Curl_multi *multi) * the pipelining strategy wants to open a new connection instead of reusing. */ static bool -ConnectionExists(struct SessionHandle *data, +ConnectionExists(struct Curl_easy *data, struct connectdata *needle, struct connectdata **usethis, bool *force_reuse, @@ -3106,13 +3179,19 @@ ConnectionExists(struct SessionHandle *data, { struct connectdata *check; struct connectdata *chosen = 0; + bool foundPendingCandidate = FALSE; bool canPipeline = IsPipeliningPossible(data, needle); + struct connectbundle *bundle; + #ifdef USE_NTLM - bool wantNTLMhttp = ((data->state.authhost.want & CURLAUTH_NTLM) || - (data->state.authhost.want & CURLAUTH_NTLM_WB)) && - (needle->handler->protocol & PROTO_FAMILY_HTTP) ? TRUE : FALSE; + bool wantNTLMhttp = ((data->state.authhost.want & + (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + (needle->handler->protocol & PROTO_FAMILY_HTTP)); + bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd && + ((data->state.authproxy.want & + (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + (needle->handler->protocol & PROTO_FAMILY_HTTP))); #endif - struct connectbundle *bundle; *force_reuse = FALSE; *waitpipe = FALSE; @@ -3131,9 +3210,19 @@ ConnectionExists(struct SessionHandle *data, max_pipeline_length(data->multi):0; size_t best_pipe_len = max_pipe_len; struct curl_llist_element *curr; + const char *hostname; - infof(data, "Found bundle for host %s: %p\n", - needle->host.name, (void *)bundle); + if(needle->bits.conn_to_host) + hostname = needle->conn_to_host.name; + else + hostname = needle->host.name; + + infof(data, "Found bundle for host %s: %p [%s]\n", + hostname, (void *)bundle, + (bundle->multiuse== BUNDLE_PIPELINING? + "can pipeline": + (bundle->multiuse== BUNDLE_MULTIPLEX? + "can multiplex":"serially"))); /* We can't pipe if we don't know anything about the server */ if(canPipeline) { @@ -3147,19 +3236,27 @@ ConnectionExists(struct SessionHandle *data, infof(data, "Server doesn't support multi-use (yet)\n"); canPipeline = FALSE; } + if((bundle->multiuse == BUNDLE_PIPELINING) && + !Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1)) { + /* not asked for, switch off */ + infof(data, "Could pipeline, but not asked to!\n"); + canPipeline = FALSE; + } + else if((bundle->multiuse == BUNDLE_MULTIPLEX) && + !Curl_pipeline_wanted(data->multi, CURLPIPE_MULTIPLEX)) { + infof(data, "Could multiplex, but not asked to!\n"); + canPipeline = FALSE; + } } curr = bundle->conn_list->head; while(curr) { bool match = FALSE; -#if defined(USE_NTLM) - bool credentialsMatch = FALSE; -#endif size_t pipeLen; /* - * Note that if we use a HTTP proxy, we check connections to that - * proxy and not to the actual remote server. + * Note that if we use a HTTP proxy in normal mode (no tunneling), we + * check connections to that proxy and not to the actual remote server. */ check = curr->ptr; curr = curr->next; @@ -3173,8 +3270,8 @@ ConnectionExists(struct SessionHandle *data, if(!check->bits.multiplex) { /* If not multiplexing, make sure the pipe has only GET requests */ - struct SessionHandle* sh = gethandleathead(check->send_pipe); - struct SessionHandle* rh = gethandleathead(check->recv_pipe); + struct Curl_easy* sh = gethandleathead(check->send_pipe); + struct Curl_easy* rh = gethandleathead(check->recv_pipe); if(sh) { if(!IsPipeliningPossible(sh, check)) continue; @@ -3205,6 +3302,8 @@ ConnectionExists(struct SessionHandle *data, if((check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) || check->bits.close) { + if(!check->bits.close) + foundPendingCandidate = TRUE; /* Don't pick a connection that hasn't connected yet or that is going to get closed. */ infof(data, "Connection #%ld isn't open enough, can't reuse\n", @@ -3223,7 +3322,8 @@ ConnectionExists(struct SessionHandle *data, if((needle->handler->flags&PROTOPT_SSL) != (check->handler->flags&PROTOPT_SSL)) /* don't do mixed SSL and non-SSL connections */ - if(!(needle->handler->protocol & check->handler->protocol)) + if(get_protocol_family(check->handler->protocol) != + needle->handler->protocol || !check->tls_upgraded) /* except protocols that have been upgraded via TLS */ continue; @@ -3237,6 +3337,25 @@ ConnectionExists(struct SessionHandle *data, /* don't do mixed proxy and non-proxy connections */ continue; + if(needle->bits.proxy && + (needle->proxytype != check->proxytype || + needle->bits.httpproxy != check->bits.httpproxy || + needle->bits.tunnel_proxy != check->bits.tunnel_proxy || + !Curl_raw_equal(needle->proxy.name, check->proxy.name) || + needle->port != check->port)) + /* don't mix connections that use different proxies */ + continue; + + if(needle->bits.conn_to_host != check->bits.conn_to_host) + /* don't mix connections that use the "connect to host" feature and + * connections that don't use this feature */ + continue; + + if(needle->bits.conn_to_port != check->bits.conn_to_port) + /* don't mix connections that use the "connect to port" feature and + * connections that don't use this feature */ + continue; + if(!canPipeline && check->inuse) /* this request can't be pipelined but the checked connection is already in use so we skip it */ @@ -3262,37 +3381,33 @@ ConnectionExists(struct SessionHandle *data, continue; } - if((!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) -#ifdef USE_NTLM - || (wantNTLMhttp || check->ntlm.state != NTLMSTATE_NONE) -#endif - ) { - /* This protocol requires credentials per connection or is HTTP+NTLM, + if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) { + /* This protocol requires credentials per connection, so verify that we're using the same name and password as well */ if(!strequal(needle->user, check->user) || !strequal(needle->passwd, check->passwd)) { /* one of them was different */ continue; } -#if defined(USE_NTLM) - credentialsMatch = TRUE; -#endif } - if(!needle->bits.httpproxy || needle->handler->flags&PROTOPT_SSL || - (needle->bits.httpproxy && check->bits.httpproxy && - needle->bits.tunnel_proxy && check->bits.tunnel_proxy && - Curl_raw_equal(needle->proxy.name, check->proxy.name) && - (needle->port == check->port))) { + if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) || + (needle->bits.httpproxy && needle->bits.tunnel_proxy)) { /* The requested connection does not use a HTTP proxy or it uses SSL or - it is a non-SSL protocol tunneled over the same http proxy name and - port number or it is a non-SSL protocol which is allowed to be - upgraded via TLS */ - + it is a non-SSL protocol tunneled over the same HTTP proxy name and + port number */ if((Curl_raw_equal(needle->handler->scheme, check->handler->scheme) || - needle->handler->protocol & check->handler->protocol) && + (get_protocol_family(check->handler->protocol) == + needle->handler->protocol && check->tls_upgraded)) && + (!needle->bits.conn_to_host || Curl_raw_equal( + needle->conn_to_host.name, check->conn_to_host.name)) && + (!needle->bits.conn_to_port || + needle->conn_to_port == check->conn_to_port) && Curl_raw_equal(needle->host.name, check->host.name) && needle->remote_port == check->remote_port) { + /* The schemes match or the the protocol family is the same and the + previous connection was TLS upgraded, and the hostname and host + port match */ if(needle->handler->flags & PROTOPT_SSL) { /* This is a SSL connection so verify that we're using the same SSL options as well */ @@ -3305,6 +3420,7 @@ ConnectionExists(struct SessionHandle *data, continue; } else if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) { + foundPendingCandidate = TRUE; DEBUGF(infof(data, "Connection #%ld has not started SSL connect, " "can't reuse\n", @@ -3315,16 +3431,10 @@ ConnectionExists(struct SessionHandle *data, match = TRUE; } } - else { /* The requested needle connection is using a proxy, - is the checked one using the same host, port and type? */ - if(check->bits.proxy && - (needle->proxytype == check->proxytype) && - (needle->bits.tunnel_proxy == check->bits.tunnel_proxy) && - Curl_raw_equal(needle->proxy.name, check->proxy.name) && - needle->port == check->port) { - /* This is the same proxy connection, use it! */ - match = TRUE; - } + else { + /* The requested connection is using the same HTTP proxy in normal + mode (no tunneling) */ + match = TRUE; } if(match) { @@ -3335,20 +3445,47 @@ ConnectionExists(struct SessionHandle *data, possible. (Especially we must not reuse the same connection if partway through a handshake!) */ if(wantNTLMhttp) { - if(credentialsMatch && check->ntlm.state != NTLMSTATE_NONE) { - chosen = check; + if(!strequal(needle->user, check->user) || + !strequal(needle->passwd, check->passwd)) + continue; + } + else if(check->ntlm.state != NTLMSTATE_NONE) { + /* Connection is using NTLM auth but we don't want NTLM */ + continue; + } + + /* Same for Proxy NTLM authentication */ + if(wantProxyNTLMhttp) { + /* Both check->proxyuser and check->proxypasswd can be NULL */ + if(!check->proxyuser || !check->proxypasswd) + continue; + if(!strequal(needle->proxyuser, check->proxyuser) || + !strequal(needle->proxypasswd, check->proxypasswd)) + continue; + } + else if(check->proxyntlm.state != NTLMSTATE_NONE) { + /* Proxy connection is using NTLM auth but we don't want NTLM */ + continue; + } + + if(wantNTLMhttp || wantProxyNTLMhttp) { + /* Credentials are already checked, we can use this connection */ + chosen = check; + + if((wantNTLMhttp && + (check->ntlm.state != NTLMSTATE_NONE)) || + (wantProxyNTLMhttp && + (check->proxyntlm.state != NTLMSTATE_NONE))) { /* We must use this connection, no other */ *force_reuse = TRUE; break; } - else if(credentialsMatch) - /* this is a backup choice */ - chosen = check; + + /* Continue look up for a better connection */ continue; } #endif - if(canPipeline) { /* We can pipeline if we want to. Let's continue looking for the optimal connection to use, i.e the shortest pipe that is not @@ -3413,39 +3550,13 @@ ConnectionExists(struct SessionHandle *data, return TRUE; /* yes, we found one to use! */ } - return FALSE; /* no matching connecting exists */ -} - -/* Mark the connection as 'idle', or close it if the cache is full. - Returns TRUE if the connection is kept, or FALSE if it was closed. */ -static bool -ConnectionDone(struct SessionHandle *data, struct connectdata *conn) -{ - /* data->multi->maxconnects can be negative, deal with it. */ - size_t maxconnects = - (data->multi->maxconnects < 0) ? data->multi->num_easy * 4: - data->multi->maxconnects; - struct connectdata *conn_candidate = NULL; - - /* Mark the current connection as 'unused' */ - conn->inuse = FALSE; - - if(maxconnects > 0 && - data->state.conn_cache->num_connections > maxconnects) { - infof(data, "Connection cache is full, closing the oldest one.\n"); - - conn_candidate = find_oldest_idle_connection(data); - - if(conn_candidate) { - /* Set the connection's owner correctly */ - conn_candidate->data = data; - - /* the winner gets the honour of being disconnected */ - (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE); - } + if(foundPendingCandidate && data->set.pipewait) { + infof(data, + "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set\n"); + *waitpipe = TRUE; } - return (conn_candidate == conn) ? FALSE : TRUE; + return FALSE; /* no matching connecting exists */ } /* after a TCP connection to the proxy has been verified, this function does @@ -3467,16 +3578,27 @@ CURLcode Curl_connected_proxy(struct connectdata *conn, case CURLPROXY_SOCKS5: case CURLPROXY_SOCKS5_HOSTNAME: return Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, - conn->host.name, conn->remote_port, + conn->bits.conn_to_host ? conn->conn_to_host.name : + conn->host.name, + conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port, FIRSTSOCKET, conn); case CURLPROXY_SOCKS4: - return Curl_SOCKS4(conn->proxyuser, conn->host.name, - conn->remote_port, FIRSTSOCKET, conn, FALSE); + return Curl_SOCKS4(conn->proxyuser, + conn->bits.conn_to_host ? conn->conn_to_host.name : + conn->host.name, + conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port, + FIRSTSOCKET, conn, FALSE); case CURLPROXY_SOCKS4A: - return Curl_SOCKS4(conn->proxyuser, conn->host.name, - conn->remote_port, FIRSTSOCKET, conn, TRUE); + return Curl_SOCKS4(conn->proxyuser, + conn->bits.conn_to_host ? conn->conn_to_host.name : + conn->host.name, + conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port, + FIRSTSOCKET, conn, TRUE); #endif /* CURL_DISABLE_PROXY */ case CURLPROXY_HTTP: @@ -3634,7 +3756,7 @@ static bool is_ASCII_name(const char *hostname) /* * Check if characters in hostname is allowed in Top Level Domain. */ -static bool tld_check_name(struct SessionHandle *data, +static bool tld_check_name(struct Curl_easy *data, const char *ace_hostname) { size_t err_pos; @@ -3651,17 +3773,16 @@ static bool tld_check_name(struct SessionHandle *data, if(rc != IDNA_SUCCESS) return FALSE; + /* Warning: err_pos receives "the decoded character offset rather than the + byte position in the string." And as of libidn 1.32 that character offset + is for UTF-8, even if the passed in string is another locale. */ rc = tld_check_lz(uc_name, &err_pos, NULL); #ifndef CURL_DISABLE_VERBOSE_STRINGS #ifdef HAVE_TLD_STRERROR if(rc != TLD_SUCCESS) tld_errmsg = tld_strerror((Tld_rc)rc); #endif - if(rc == TLD_INVALID) - infof(data, "WARNING: %s; pos %u = `%c'/0x%02X\n", - tld_errmsg, err_pos, uc_name[err_pos], - uc_name[err_pos] & 255); - else if(rc != TLD_SUCCESS) + if(rc != TLD_SUCCESS) infof(data, "WARNING: TLD check for %s failed; %s\n", uc_name, tld_errmsg); #endif /* CURL_DISABLE_VERBOSE_STRINGS */ @@ -3677,7 +3798,7 @@ static bool tld_check_name(struct SessionHandle *data, /* * Perform any necessary IDN conversion of hostname */ -static void fix_hostname(struct SessionHandle *data, +static void fix_hostname(struct Curl_easy *data, struct connectdata *conn, struct hostname *host) { size_t len; @@ -3698,49 +3819,64 @@ static void fix_hostname(struct SessionHandle *data, there's no use for it */ host->name[len-1]=0; + /* Check name for non-ASCII and convert hostname to ACE form if we can */ if(!is_ASCII_name(host->name)) { #ifdef USE_LIBIDN - /************************************************************* - * Check name for non-ASCII and convert hostname to ACE form. - *************************************************************/ - if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) { - char *ace_hostname = NULL; - int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0); - infof (data, "Input domain encoded as `%s'\n", - stringprep_locale_charset ()); - if(rc != IDNA_SUCCESS) - infof(data, "Failed to convert %s to ACE; %s\n", - host->name, Curl_idn_strerror(conn, rc)); - else { - /* tld_check_name() displays a warning if the host name contains - "illegal" characters for this TLD */ - (void)tld_check_name(data, ace_hostname); - - host->encalloc = ace_hostname; - /* change the name pointer to point to the encoded hostname */ - host->name = host->encalloc; + if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) { + char *ace_hostname = NULL; + + int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0); + infof(data, "Input domain encoded as `%s'\n", + stringprep_locale_charset()); + if(rc == IDNA_SUCCESS) { + /* tld_check_name() displays a warning if the host name contains + "illegal" characters for this TLD */ + (void)tld_check_name(data, ace_hostname); + + host->encalloc = ace_hostname; + /* change the name pointer to point to the encoded hostname */ + host->name = host->encalloc; + } + else + infof(data, "Failed to convert %s to ACE; %s\n", host->name, + Curl_idn_strerror(conn, rc)); } - } #elif defined(USE_WIN32_IDN) - /************************************************************* - * Check name for non-ASCII and convert hostname to ACE form. - *************************************************************/ char *ace_hostname = NULL; - int rc = curl_win32_idn_to_ascii(host->name, &ace_hostname); - if(rc == 0) - infof(data, "Failed to convert %s to ACE;\n", - host->name); - else { + + if(curl_win32_idn_to_ascii(host->name, &ace_hostname)) { host->encalloc = ace_hostname; /* change the name pointer to point to the encoded hostname */ host->name = host->encalloc; } + else + infof(data, "Failed to convert %s to ACE;\n", host->name); #else infof(data, "IDN support not present, can't parse Unicode domains\n"); #endif } } +/* + * Frees data allocated by fix_hostname() + */ +static void free_fixed_hostname(struct hostname *host) +{ +#if defined(USE_LIBIDN) + if(host->encalloc) { + idn_free(host->encalloc); /* must be freed with idn_free() since this was + allocated by libidn */ + host->encalloc = NULL; + } +#elif defined(USE_WIN32_IDN) + free(host->encalloc); /* must be freed withidn_free() since this was + allocated by curl_win32_idn_to_ascii */ + host->encalloc = NULL; +#else + (void)host; +#endif +} + static void llist_dtor(void *user, void *element) { (void)user; @@ -3751,7 +3887,7 @@ static void llist_dtor(void *user, void *element) /* * Allocate and initialize a new connectdata object. */ -static struct connectdata *allocate_conn(struct SessionHandle *data) +static struct connectdata *allocate_conn(struct Curl_easy *data) { struct connectdata *conn = calloc(1, sizeof(struct connectdata)); if(!conn) @@ -3770,6 +3906,10 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->connection_id = -1; /* no ID */ conn->port = -1; /* unknown at this point */ conn->remote_port = -1; /* unknown */ +#if defined(USE_RECV_BEFORE_SEND_WORKAROUND) && defined(DEBUGBUILD) + conn->postponed[0].bindsock = CURL_SOCKET_BAD; /* no file descriptor */ + conn->postponed[1].bindsock = CURL_SOCKET_BAD; /* no file descriptor */ +#endif /* USE_RECV_BEFORE_SEND_WORKAROUND && DEBUGBUILD */ /* Default protocol-independent behavior doesn't support persistent connections, so we set this to force-close. Protocols that support @@ -3780,7 +3920,7 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->created = Curl_tvnow(); conn->data = data; /* Setup the association between this connection - and the SessionHandle */ + and the Curl_easy */ conn->proxytype = data->set.proxytype; /* type */ @@ -3796,17 +3936,18 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) /* note that these two proxy bits are now just on what looks to be requested, they may be altered down the road */ conn->bits.proxy = (data->set.str[STRING_PROXY] && - *data->set.str[STRING_PROXY])?TRUE:FALSE; + *data->set.str[STRING_PROXY]) ? TRUE : FALSE; conn->bits.httpproxy = (conn->bits.proxy && (conn->proxytype == CURLPROXY_HTTP || - conn->proxytype == CURLPROXY_HTTP_1_0))?TRUE:FALSE; - conn->bits.proxy_user_passwd = - (NULL != data->set.str[STRING_PROXYUSERNAME])?TRUE:FALSE; + conn->proxytype == CURLPROXY_HTTP_1_0)) ? + TRUE : FALSE; + conn->bits.proxy_user_passwd = (data->set.str[STRING_PROXYUSERNAME]) ? + TRUE : FALSE; conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; #endif /* CURL_DISABLE_PROXY */ - conn->bits.user_passwd = (NULL != data->set.str[STRING_USERNAME])?TRUE:FALSE; + conn->bits.user_passwd = (data->set.str[STRING_USERNAME]) ? TRUE : FALSE; conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; @@ -3851,7 +3992,7 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->localport = data->set.localport; /* the close socket stuff needs to be copied to the connection struct as - it may live on without (this specific) SessionHandle */ + it may live on without (this specific) Curl_easy */ conn->fclosesocket = data->set.fclosesocket; conn->closesocket_client = data->set.closesocket_client; @@ -3870,7 +4011,7 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) return NULL; } -static CURLcode findprotocol(struct SessionHandle *data, +static CURLcode findprotocol(struct Curl_easy *data, struct connectdata *conn, const char *protostr) { @@ -3915,7 +4056,7 @@ static CURLcode findprotocol(struct SessionHandle *data, /* * Parse URL and fill in the relevant members of the connection struct. */ -static CURLcode parseurlandfillconn(struct SessionHandle *data, +static CURLcode parseurlandfillconn(struct Curl_easy *data, struct connectdata *conn, bool *prot_missing, char **userp, char **passwdp, @@ -4000,12 +4141,17 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, } else { /* clear path */ + char slashbuf[4]; path[0]=0; - if(2 > sscanf(data->change.url, - "%15[^\n:]://%[^\n/?]%[^\n]", - protobuf, - conn->host.name, path)) { + rc = sscanf(data->change.url, + "%15[^\n:]:%3[/]%[^\n/?]%[^\n]", + protobuf, slashbuf, conn->host.name, path); + if(2 == rc) { + failf(data, "Bad URL"); + return CURLE_URL_MALFORMAT; + } + if(3 > rc) { /* * The URL was badly formatted, let's try the browser-style _without_ @@ -4028,33 +4174,51 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, } /* - * Since there was no protocol part specified, we guess what protocol it - * is based on the first letters of the server name. + * Since there was no protocol part specified in the URL use the + * user-specified default protocol. If we weren't given a default make a + * guess by matching some protocols against the host's outermost + * sub-domain name. Finally if there was no match use HTTP. */ - /* Note: if you add a new protocol, please update the list in - * lib/version.c too! */ - - if(checkprefix("FTP.", conn->host.name)) - protop = "ftp"; - else if(checkprefix("DICT.", conn->host.name)) - protop = "DICT"; - else if(checkprefix("LDAP.", conn->host.name)) - protop = "LDAP"; - else if(checkprefix("IMAP.", conn->host.name)) - protop = "IMAP"; - else if(checkprefix("SMTP.", conn->host.name)) - protop = "smtp"; - else if(checkprefix("POP3.", conn->host.name)) - protop = "pop3"; - else { - protop = "http"; + protop = data->set.str[STRING_DEFAULT_PROTOCOL]; + if(!protop) { + /* Note: if you add a new protocol, please update the list in + * lib/version.c too! */ + if(checkprefix("FTP.", conn->host.name)) + protop = "ftp"; + else if(checkprefix("DICT.", conn->host.name)) + protop = "DICT"; + else if(checkprefix("LDAP.", conn->host.name)) + protop = "LDAP"; + else if(checkprefix("IMAP.", conn->host.name)) + protop = "IMAP"; + else if(checkprefix("SMTP.", conn->host.name)) + protop = "smtp"; + else if(checkprefix("POP3.", conn->host.name)) + protop = "pop3"; + else + protop = "http"; } *prot_missing = TRUE; /* not given in URL */ } - else + else { + size_t s = strlen(slashbuf); protop = protobuf; + if(s != 2) { + infof(data, "Unwillingly accepted illegal URL using %d slash%s!\n", + s, s>1?"es":""); + + if(data->change.url_alloc) + free(data->change.url); + /* repair the URL to use two slashes */ + data->change.url = aprintf("%s://%s%s", + protobuf, conn->host.name, path); + if(!data->change.url) + return CURLE_OUT_OF_MEMORY; + data->change.url_alloc = TRUE; + } + } } /* We search for '?' in the host name (but only on the right side of a @@ -4260,7 +4424,7 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, * If we're doing a resumed transfer, we need to setup our stuff * properly. */ -static CURLcode setup_range(struct SessionHandle *data) +static CURLcode setup_range(struct Curl_easy *data) { struct UrlState *s = &data->state; s->resume_from = data->set.set_resume_from; @@ -4273,7 +4437,7 @@ static CURLcode setup_range(struct SessionHandle *data) else s->range = strdup(data->set.str[STRING_SET_RANGE]); - s->rangestringalloc = (s->range)?TRUE:FALSE; + s->rangestringalloc = (s->range) ? TRUE : FALSE; if(!s->range) return CURLE_OUT_OF_MEMORY; @@ -4292,7 +4456,7 @@ static CURLcode setup_range(struct SessionHandle *data) * setup_connection_internals() - * * Setup connection internals specific to the requested protocol in the - * SessionHandle. This is inited and setup before the connection is made but + * Curl_easy. This is inited and setup before the connection is made but * is about the particular protocol that is to be used. * * This MUST get called after proxy magic has been figured out. @@ -4301,7 +4465,7 @@ static CURLcode setup_connection_internals(struct connectdata *conn) { const struct Curl_handler * p; CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* in some case in the multi state-machine, we go back to the CONNECT state and then a second (or third or...) call to this function will be made @@ -4332,20 +4496,15 @@ static CURLcode setup_connection_internals(struct connectdata *conn) was very likely already set to the proxy port */ conn->port = p->defport; - /* only if remote_port was not already parsed off the URL we use the - default port number */ - if(conn->remote_port < 0) - conn->remote_port = (unsigned short)conn->given->defport; - return CURLE_OK; } /* * Curl_free_request_state() should free temp data that was allocated in the - * SessionHandle for this single request. + * Curl_easy for this single request. */ -void Curl_free_request_state(struct SessionHandle *data) +void Curl_free_request_state(struct Curl_easy *data) { Curl_safefree(data->req.protop); Curl_safefree(data->req.newurl); @@ -4519,7 +4678,7 @@ static char *detect_proxy(struct connectdata *conn) * host name, so that we can re-use an existing connection * that may exist registered to the same proxy host. */ -static CURLcode parse_proxy(struct SessionHandle *data, +static CURLcode parse_proxy(struct Curl_easy *data, struct connectdata *conn, char *proxy) { char *prox_portno; @@ -4611,7 +4770,7 @@ static CURLcode parse_proxy(struct SessionHandle *data, if(strncmp("%25", ptr, 3)) infof(data, "Please URL encode %% as %%25, see RFC 6874.\n"); ptr++; - /* Allow unresered characters as defined in RFC 3986 */ + /* Allow unreserved characters as defined in RFC 3986 */ while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') || (*ptr == '.') || (*ptr == '_') || (*ptr == '~'))) ptr++; @@ -4631,10 +4790,24 @@ static CURLcode parse_proxy(struct SessionHandle *data, /* Get port number off proxy.server.com:1080 */ prox_portno = strchr(portptr, ':'); if(prox_portno) { + char *endp = NULL; + long port = 0; *prox_portno = 0x0; /* cut off number from host name */ prox_portno ++; /* now set the local port number */ - conn->port = strtol(prox_portno, NULL, 10); + port = strtol(prox_portno, &endp, 10); + if((endp && *endp && (*endp != '/') && (*endp != ' ')) || + (port < 0) || (port > 65535)) { + /* meant to detect for example invalid IPv6 numerical addresses without + brackets: "2a00:fac0:a000::7:13". Accept a trailing slash only + because we then allow "URL style" with the number followed by a + slash, used in curl test cases already. Space is also an acceptable + terminating symbol. */ + infof(data, "No valid port number in proxy string (%s)\n", + prox_portno); + } + else + conn->port = port; } else { if(proxyptr[0]=='/') @@ -4647,7 +4820,7 @@ static CURLcode parse_proxy(struct SessionHandle *data, a slash so we strip everything from the first slash */ atsign = strchr(proxyptr, '/'); if(atsign) - *atsign = 0x0; /* cut off path part from host name */ + *atsign = '\0'; /* cut off path part from host name */ if(data->set.proxyport) /* None given in the proxy string, then get the default one if it is @@ -4668,7 +4841,7 @@ static CURLcode parse_proxy(struct SessionHandle *data, /* * Extract the user and password from the authentication string */ -static CURLcode parse_proxy_auth(struct SessionHandle *data, +static CURLcode parse_proxy_auth(struct Curl_easy *data, struct connectdata *conn) { char proxyuser[MAX_CURL_USER_LENGTH]=""; @@ -4713,7 +4886,7 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data, * options - non-zero length if defined * conn->host.name - remove user name and password */ -static CURLcode parse_url_login(struct SessionHandle *data, +static CURLcode parse_url_login(struct Curl_easy *data, struct connectdata *conn, char **user, char **passwd, char **options) { @@ -4952,7 +5125,7 @@ static CURLcode parse_login_details(const char *login, const size_t len, * * The port number embedded in the URL is replaced, if necessary. *************************************************************/ -static CURLcode parse_remote_port(struct SessionHandle *data, +static CURLcode parse_remote_port(struct Curl_easy *data, struct connectdata *conn) { char *portptr; @@ -5051,6 +5224,12 @@ static CURLcode parse_remote_port(struct SessionHandle *data, use the default port. Firefox and Chrome both do that. */ *portptr = '\0'; } + + /* only if remote_port was not already parsed off the URL we use the + default port number */ + if(conn->remote_port < 0) + conn->remote_port = (unsigned short)conn->given->defport; + return CURLE_OK; } @@ -5058,7 +5237,7 @@ static CURLcode parse_remote_port(struct SessionHandle *data, * Override the login details from the URL with that in the CURLOPT_USERPWD * option or a .netrc file, if applicable. */ -static CURLcode override_login(struct SessionHandle *data, +static CURLcode override_login(struct Curl_easy *data, struct connectdata *conn, char **userp, char **passwdp, char **optionsp) { @@ -5093,7 +5272,7 @@ static CURLcode override_login(struct SessionHandle *data, DOT_CHAR "netrc file; using defaults\n", conn->host.name); } - else if(ret < 0 ) { + else if(ret < 0) { return CURLE_OUT_OF_MEMORY; } else { @@ -5156,10 +5335,218 @@ static CURLcode set_login(struct connectdata *conn, return result; } +/* + * Parses a "host:port" string to connect to. + * The hostname and the port may be empty; in this case, NULL is returned for + * the hostname and -1 for the port. + */ +static CURLcode parse_connect_to_host_port(struct Curl_easy *data, + const char *host, + char **hostname_result, + int *port_result) +{ + char *host_dup; + char *hostptr; + char *host_portno; + char *portptr; + int port = -1; + + *hostname_result = NULL; + *port_result = -1; + + if(!host || !*host) + return CURLE_OK; + + host_dup = strdup(host); + if(!host_dup) + return CURLE_OUT_OF_MEMORY; + + hostptr = host_dup; + + /* start scanning for port number at this point */ + portptr = hostptr; + + /* detect and extract RFC6874-style IPv6-addresses */ + if(*hostptr == '[') { + char *ptr = ++hostptr; /* advance beyond the initial bracket */ + while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.'))) + ptr++; + if(*ptr == '%') { + /* There might be a zone identifier */ + if(strncmp("%25", ptr, 3)) + infof(data, "Please URL encode %% as %%25, see RFC 6874.\n"); + ptr++; + /* Allow unreserved characters as defined in RFC 3986 */ + while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') || + (*ptr == '.') || (*ptr == '_') || (*ptr == '~'))) + ptr++; + } + if(*ptr == ']') + /* yeps, it ended nicely with a bracket as well */ + *ptr++ = '\0'; + else + infof(data, "Invalid IPv6 address format\n"); + portptr = ptr; + /* Note that if this didn't end with a bracket, we still advanced the + * hostptr first, but I can't see anything wrong with that as no host + * name nor a numeric can legally start with a bracket. + */ + } + + /* Get port number off server.com:1080 */ + host_portno = strchr(portptr, ':'); + if(host_portno) { + char *endp = NULL; + *host_portno = '\0'; /* cut off number from host name */ + host_portno++; + if(*host_portno) { + long portparse = strtol(host_portno, &endp, 10); + if((endp && *endp) || (portparse < 0) || (portparse > 65535)) { + infof(data, "No valid port number in connect to host string (%s)\n", + host_portno); + hostptr = NULL; + port = -1; + } + else + port = (int)portparse; /* we know it will fit */ + } + } + + /* now, clone the cleaned host name */ + if(hostptr) { + *hostname_result = strdup(hostptr); + if(!*hostname_result) { + free(host_dup); + return CURLE_OUT_OF_MEMORY; + } + } + + *port_result = port; + + free(host_dup); + return CURLE_OK; +} + +/* + * Parses one "connect to" string in the form: + * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT". + */ +static CURLcode parse_connect_to_string(struct Curl_easy *data, + struct connectdata *conn, + const char *conn_to_host, + char **host_result, + int *port_result) +{ + CURLcode result = CURLE_OK; + const char *ptr = conn_to_host; + int host_match = FALSE; + int port_match = FALSE; + + if(*ptr == ':') { + /* an empty hostname always matches */ + host_match = TRUE; + ptr++; + } + else { + /* check whether the URL's hostname matches */ + size_t hostname_to_match_len; + char *hostname_to_match = aprintf("%s%s%s", + conn->bits.ipv6_ip ? "[" : "", + conn->host.name, + conn->bits.ipv6_ip ? "]" : ""); + if(!hostname_to_match) + return CURLE_OUT_OF_MEMORY; + hostname_to_match_len = strlen(hostname_to_match); + host_match = curl_strnequal(ptr, hostname_to_match, hostname_to_match_len); + free(hostname_to_match); + ptr += hostname_to_match_len; + + host_match = host_match && *ptr == ':'; + ptr++; + } + + if(host_match) { + if(*ptr == ':') { + /* an empty port always matches */ + port_match = TRUE; + ptr++; + } + else { + /* check whether the URL's port matches */ + char *ptr_next = strchr(ptr, ':'); + if(ptr_next) { + char *endp = NULL; + long port_to_match = strtol(ptr, &endp, 10); + if((endp == ptr_next) && (port_to_match == conn->remote_port)) { + port_match = TRUE; + ptr = ptr_next + 1; + } + } + } + } + + if(host_match && port_match) { + /* parse the hostname and port to connect to */ + result = parse_connect_to_host_port(data, ptr, host_result, port_result); + } + + return result; +} + +/* + * Processes all strings in the "connect to" slist, and uses the "connect + * to host" and "connect to port" of the first string that matches. + */ +static CURLcode parse_connect_to_slist(struct Curl_easy *data, + struct connectdata *conn, + struct curl_slist *conn_to_host) +{ + CURLcode result = CURLE_OK; + char *host = NULL; + int port = 0; + + while(conn_to_host && !host) { + result = parse_connect_to_string(data, conn, conn_to_host->data, + &host, &port); + if(result) + return result; + + if(host && *host) { + bool ipv6host; + conn->conn_to_host.rawalloc = host; + conn->conn_to_host.name = host; + conn->bits.conn_to_host = TRUE; + + ipv6host = strchr(host, ':') != NULL; + infof(data, "Connecting to hostname: %s%s%s\n", + ipv6host ? "[" : "", host, ipv6host ? "]" : ""); + } + else { + /* no "connect to host" */ + conn->bits.conn_to_host = FALSE; + free(host); + } + + if(port >= 0) { + conn->conn_to_port = port; + conn->bits.conn_to_port = TRUE; + infof(data, "Connecting to port: %d\n", port); + } + else { + /* no "connect to port" */ + conn->bits.conn_to_port = FALSE; + } + + conn_to_host = conn_to_host->next; + } + + return result; +} + /************************************************************* * Resolve the address of the server or proxy *************************************************************/ -static CURLcode resolve_server(struct SessionHandle *data, +static CURLcode resolve_server(struct Curl_easy *data, struct connectdata *conn, bool *async) { @@ -5180,9 +5567,6 @@ static CURLcode resolve_server(struct SessionHandle *data, int rc; struct Curl_dns_entry *hostaddr; - /* set a pointer to the hostname we display */ - fix_hostname(data, conn, &conn->host); - #ifdef USE_UNIX_SOCKETS if(data->set.str[STRING_UNIX_SOCKET_PATH]) { /* Unix domain sockets are local. The host gets ignored, just use the @@ -5210,12 +5594,21 @@ static CURLcode resolve_server(struct SessionHandle *data, else #endif if(!conn->proxy.name || !*conn->proxy.name) { + struct hostname *connhost; + if(conn->bits.conn_to_host) + connhost = &conn->conn_to_host; + else + connhost = &conn->host; + /* If not connecting via a proxy, extract the port from the URL, if it is * there, thus overriding any defaults that might have been set above. */ - conn->port = conn->remote_port; /* it is the same port */ + if(conn->bits.conn_to_port) + conn->port = conn->conn_to_port; + else + conn->port = conn->remote_port; /* it is the same port */ /* Resolve target host right on */ - rc = Curl_resolv_timeout(conn, conn->host.name, (int)conn->port, + rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port, &hostaddr, timeout_ms); if(rc == CURLRESOLV_PENDING) *async = TRUE; @@ -5224,7 +5617,7 @@ static CURLcode resolve_server(struct SessionHandle *data, result = CURLE_OPERATION_TIMEDOUT; else if(!hostaddr) { - failf(data, "Couldn't resolve host '%s'", conn->host.dispname); + failf(data, "Couldn't resolve host '%s'", connhost->dispname); result = CURLE_COULDNT_RESOLVE_HOST; /* don't return yet, we need to clean up the timeout first */ } @@ -5232,9 +5625,6 @@ static CURLcode resolve_server(struct SessionHandle *data, else { /* This is a proxy that hasn't been resolved yet. */ - /* IDN-fix the proxy name */ - fix_hostname(data, conn, &conn->proxy); - /* resolve proxy */ rc = Curl_resolv_timeout(conn, conn->proxy.name, (int)conn->port, &hostaddr, timeout_ms); @@ -5266,6 +5656,7 @@ static CURLcode resolve_server(struct SessionHandle *data, static void reuse_conn(struct connectdata *old_conn, struct connectdata *conn) { + free_fixed_hostname(&old_conn->proxy); free(old_conn->proxy.rawalloc); /* free the SSL config struct from this connection struct as this was @@ -5300,12 +5691,22 @@ static void reuse_conn(struct connectdata *old_conn, /* host can change, when doing keepalive with a proxy or if the case is different this time etc */ + free_fixed_hostname(&conn->host); + free_fixed_hostname(&conn->conn_to_host); Curl_safefree(conn->host.rawalloc); + Curl_safefree(conn->conn_to_host.rawalloc); conn->host=old_conn->host; + conn->bits.conn_to_host = old_conn->bits.conn_to_host; + conn->conn_to_host = old_conn->conn_to_host; + conn->bits.conn_to_port = old_conn->bits.conn_to_port; + conn->conn_to_port = old_conn->conn_to_port; /* persist connection info in session handle */ Curl_persistconninfo(conn); + conn_reset_all_postponed_data(old_conn); /* free buffers */ + conn_reset_all_postponed_data(conn); /* reset unprocessed data */ + /* re-use init */ conn->bits.reuse = TRUE; /* yes, we're re-using here */ @@ -5340,7 +5741,7 @@ static void reuse_conn(struct connectdata *old_conn, * *NOTE* this function assigns the conn->data pointer! */ -static CURLcode create_conn(struct SessionHandle *data, +static CURLcode create_conn(struct Curl_easy *data, struct connectdata **in_connect, bool *async) { @@ -5448,6 +5849,7 @@ static CURLcode create_conn(struct SessionHandle *data, we're gonna follow a Location: later or... then we need the protocol part added so that we have a valid URL. */ char *reurl; + char *ch_lower; reurl = aprintf("%s://%s", conn->handler->scheme, data->change.url); @@ -5456,6 +5858,10 @@ static CURLcode create_conn(struct SessionHandle *data, goto out; } + /* Change protocol prefix to lower-case */ + for(ch_lower = reurl; *ch_lower != ':'; ch_lower++) + *ch_lower = (char)TOLOWER(*ch_lower); + if(data->change.url_alloc) { Curl_safefree(data->change.url); data->change.url_alloc = FALSE; @@ -5484,8 +5890,8 @@ static CURLcode create_conn(struct SessionHandle *data, } if(data->set.str[STRING_BEARER]) { - conn->xoauth2_bearer = strdup(data->set.str[STRING_BEARER]); - if(!conn->xoauth2_bearer) { + conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]); + if(!conn->oauth_bearer) { result = CURLE_OUT_OF_MEMORY; goto out; } @@ -5605,6 +6011,48 @@ static CURLcode create_conn(struct SessionHandle *data, goto out; /************************************************************* + * Process the "connect to" linked list of hostname/port mappings. + * Do this after the remote port number has been fixed in the URL. + *************************************************************/ + result = parse_connect_to_slist(data, conn, data->set.connect_to); + if(result) + goto out; + + /************************************************************* + * IDN-fix the hostnames + *************************************************************/ + fix_hostname(data, conn, &conn->host); + if(conn->bits.conn_to_host) + fix_hostname(data, conn, &conn->conn_to_host); + if(conn->proxy.name && *conn->proxy.name) + fix_hostname(data, conn, &conn->proxy); + + /************************************************************* + * Check whether the host and the "connect to host" are equal. + * Do this after the hostnames have been IDN-fixed . + *************************************************************/ + if(conn->bits.conn_to_host && + Curl_raw_equal(conn->conn_to_host.name, conn->host.name)) { + conn->bits.conn_to_host = FALSE; + } + + /************************************************************* + * Check whether the port and the "connect to port" are equal. + * Do this after the remote port number has been fixed in the URL. + *************************************************************/ + if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) { + conn->bits.conn_to_port = FALSE; + } + + /************************************************************* + * If the "connect to" feature is used with an HTTP proxy, + * we set the tunnel_proxy bit. + *************************************************************/ + if((conn->bits.conn_to_host || conn->bits.conn_to_port) && + conn->bits.httpproxy) + conn->bits.tunnel_proxy = TRUE; + + /************************************************************* * Setup internals depending on protocol. Needs to be done after * we figured out what/if proxy to use. *************************************************************/ @@ -5617,6 +6065,8 @@ static CURLcode create_conn(struct SessionHandle *data, conn->recv[SECONDARYSOCKET] = Curl_recv_plain; conn->send[SECONDARYSOCKET] = Curl_send_plain; + conn->bits.tcp_fastopen = data->set.tcp_fastopen; + /*********************************************************************** * file: is a special case in that it doesn't need a network connection ***********************************************************************/ @@ -5663,7 +6113,7 @@ static CURLcode create_conn(struct SessionHandle *data, strings in the session handle strings array! Keep in mind that the pointers in the master copy are pointing to strings - that will be freed as part of the SessionHandle struct, but all cloned + that will be freed as part of the Curl_easy struct, but all cloned copies will be separately allocated. */ data->set.ssl.CApath = data->set.str[STRING_SSL_CAPATH]; @@ -5673,6 +6123,7 @@ static CURLcode create_conn(struct SessionHandle *data, data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST]; + data->set.ssl.clientcert = data->set.str[STRING_CERT]; #ifdef USE_TLS_SRP data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME]; data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD]; @@ -5732,9 +6183,6 @@ static CURLcode create_conn(struct SessionHandle *data, conn = conn_temp; *in_connect = conn; - /* set a pointer to the hostname we display */ - fix_hostname(data, conn, &conn->host); - infof(data, "Re-using existing connection! (#%ld) with %s %s\n", conn->connection_id, conn->bits.proxy?"proxy":"host", @@ -5746,6 +6194,15 @@ static CURLcode create_conn(struct SessionHandle *data, connections we are allowed to open. */ struct connectbundle *bundle = NULL; + if(conn->handler->flags & PROTOPT_ALPN_NPN) { + /* The protocol wants it, so set the bits if enabled in the easy handle + (default) */ + if(data->set.ssl_enable_alpn) + conn->bits.tls_enable_alpn = TRUE; + if(data->set.ssl_enable_npn) + conn->bits.tls_enable_npn = TRUE; + } + if(waitpipe) /* There is a connection that *might* become usable for pipelining "soon", and we wait for that */ @@ -5778,7 +6235,7 @@ static CURLcode create_conn(struct SessionHandle *data, struct connectdata *conn_candidate; /* The cache is full. Let's see if we can kill a connection. */ - conn_candidate = find_oldest_idle_connection(data); + conn_candidate = Curl_oldest_idle_connection(data); if(conn_candidate) { /* Set the connection's owner correctly, then kill it */ @@ -5816,12 +6273,14 @@ static CURLcode create_conn(struct SessionHandle *data, data->state.authhost.done) { infof(data, "NTLM picked AND auth done set, clear picked!\n"); data->state.authhost.picked = CURLAUTH_NONE; + data->state.authhost.done = FALSE; } if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && data->state.authproxy.done) { infof(data, "NTLM-proxy picked AND auth done set, clear picked!\n"); data->state.authproxy.picked = CURLAUTH_NONE; + data->state.authproxy.done = FALSE; } #endif } @@ -5874,7 +6333,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn, bool *protocol_done) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; Curl_pgrsTime(data, TIMER_NAMELOOKUP); @@ -5948,7 +6407,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn, return result; } -CURLcode Curl_connect(struct SessionHandle *data, +CURLcode Curl_connect(struct Curl_easy *data, struct connectdata **in_connect, bool *asyncp, bool *protocol_done) @@ -5988,140 +6447,17 @@ CURLcode Curl_connect(struct SessionHandle *data, return result; } -CURLcode Curl_done(struct connectdata **connp, - CURLcode status, /* an error if this is called after an - error was detected */ - bool premature) -{ - CURLcode result; - struct connectdata *conn; - struct SessionHandle *data; - - DEBUGASSERT(*connp); - - conn = *connp; - data = conn->data; - - DEBUGF(infof(data, "Curl_done\n")); - - if(data->state.done) - /* Stop if Curl_done() has already been called */ - return CURLE_OK; - - Curl_getoff_all_pipelines(data, conn); - - /* Cleanup possible redirect junk */ - free(data->req.newurl); - data->req.newurl = NULL; - free(data->req.location); - data->req.location = NULL; - - switch(status) { - case CURLE_ABORTED_BY_CALLBACK: - case CURLE_READ_ERROR: - case CURLE_WRITE_ERROR: - /* When we're aborted due to a callback return code it basically have to - be counted as premature as there is trouble ahead if we don't. We have - many callbacks and protocols work differently, we could potentially do - this more fine-grained in the future. */ - premature = TRUE; - default: - break; - } - - /* this calls the protocol-specific function pointer previously set */ - if(conn->handler->done) - result = conn->handler->done(conn, status, premature); - else - result = status; - - if(!result && Curl_pgrsDone(conn)) - result = CURLE_ABORTED_BY_CALLBACK; - - if((conn->send_pipe->size + conn->recv_pipe->size != 0 && - !data->set.reuse_forbid && - !conn->bits.close)) { - /* Stop if pipeline is not empty and we do not have to close - connection. */ - DEBUGF(infof(data, "Connection still in use, no more Curl_done now!\n")); - return CURLE_OK; - } - - data->state.done = TRUE; /* called just now! */ - Curl_resolver_cancel(conn); - - if(conn->dns_entry) { - Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ - conn->dns_entry = NULL; - } - - /* if the transfer was completed in a paused state there can be buffered - data left to write and then kill */ - free(data->state.tempwrite); - data->state.tempwrite = NULL; - - /* if data->set.reuse_forbid is TRUE, it means the libcurl client has - forced us to close this connection. This is ignored for requests taking - place in a NTLM authentication handshake - - if conn->bits.close is TRUE, it means that the connection should be - closed in spite of all our efforts to be nice, due to protocol - restrictions in our or the server's end - - if premature is TRUE, it means this connection was said to be DONE before - the entire request operation is complete and thus we can't know in what - state it is for re-using, so we're forced to close it. In a perfect world - we can add code that keep track of if we really must close it here or not, - but currently we have no such detail knowledge. - */ - - if((data->set.reuse_forbid -#if defined(USE_NTLM) - && !(conn->ntlm.state == NTLMSTATE_TYPE2 || - conn->proxyntlm.state == NTLMSTATE_TYPE2) -#endif - ) || conn->bits.close || premature) { - CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */ - - /* If we had an error already, make sure we return that one. But - if we got a new error, return that. */ - if(!result && res2) - result = res2; - } - else { - /* the connection is no longer in use */ - if(ConnectionDone(data, conn)) { - /* remember the most recently used connection */ - data->state.lastconnect = conn; - - infof(data, "Connection #%ld to host %s left intact\n", - conn->connection_id, - conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname); - } - else - data->state.lastconnect = NULL; - } - - *connp = NULL; /* to make the caller of this function better detect that - this was either closed or handed over to the connection - cache here, and therefore cannot be used from this point on - */ - Curl_free_request_state(data); - - return result; -} - /* * Curl_init_do() inits the readwrite session. This is inited each time (in * the DO function before the protocol-specific DO functions are invoked) for - * a transfer, sometimes multiple times on the same SessionHandle. Make sure + * a transfer, sometimes multiple times on the same Curl_easy. Make sure * nothing in here depends on stuff that are setup dynamically for the * transfer. * * Allow this function to get called with 'conn' set to NULL. */ -CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn) +CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn) { struct SingleRequest *k = &data->req; @@ -6129,7 +6465,7 @@ CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn) conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to * use */ - data->state.done = FALSE; /* Curl_done() is not called yet */ + data->state.done = FALSE; /* *_done() is not called yet */ data->state.expect100header = FALSE; if(data->set.opt_no_body) @@ -6163,80 +6499,111 @@ CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn) } /* - * do_complete is called when the DO actions are complete. - * - * We init chunking and trailer bits to their default values here immediately - * before receiving any header data for the current request in the pipeline. - */ -static void do_complete(struct connectdata *conn) -{ - conn->data->req.chunk=FALSE; - conn->data->req.maxfd = (conn->sockfd>conn->writesockfd? - conn->sockfd:conn->writesockfd)+1; - Curl_pgrsTime(conn->data, TIMER_PRETRANSFER); -} +* get_protocol_family() +* +* This is used to return the protocol family for a given protocol. +* +* Parameters: +* +* protocol [in] - A single bit protocol identifier such as HTTP or HTTPS. +* +* Returns the family as a single bit protocol identifier. +*/ -CURLcode Curl_do(struct connectdata **connp, bool *done) +unsigned int get_protocol_family(unsigned int protocol) { - CURLcode result=CURLE_OK; - struct connectdata *conn = *connp; - struct SessionHandle *data = conn->data; + unsigned int family; - if(conn->handler->do_it) { - /* generic protocol-specific function pointer set in curl_connect() */ - result = conn->handler->do_it(conn, done); + switch(protocol) { + case CURLPROTO_HTTP: + case CURLPROTO_HTTPS: + family = CURLPROTO_HTTP; + break; - /* This was formerly done in transfer.c, but we better do it here */ - if((CURLE_SEND_ERROR == result) && conn->bits.reuse) { - /* - * If the connection is using an easy handle, call reconnect - * to re-establish the connection. Otherwise, let the multi logic - * figure out how to re-establish the connection. - */ - if(!data->multi) { - result = Curl_reconnect_request(connp); - - if(!result) { - /* ... finally back to actually retry the DO phase */ - conn = *connp; /* re-assign conn since Curl_reconnect_request - creates a new connection */ - result = conn->handler->do_it(conn, done); - } - } - else - return result; - } + case CURLPROTO_FTP: + case CURLPROTO_FTPS: + family = CURLPROTO_FTP; + break; - if(!result && *done) - /* do_complete must be called after the protocol-specific DO function */ - do_complete(conn); - } - return result; -} + case CURLPROTO_SCP: + family = CURLPROTO_SCP; + break; -/* - * Curl_do_more() is called during the DO_MORE multi state. It is basically a - * second stage DO state which (wrongly) was introduced to support FTP's - * second connection. - * - * TODO: A future libcurl should be able to work away this state. - * - * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to - * DOING state there's more work to do! - */ + case CURLPROTO_SFTP: + family = CURLPROTO_SFTP; + break; -CURLcode Curl_do_more(struct connectdata *conn, int *complete) -{ - CURLcode result=CURLE_OK; + case CURLPROTO_TELNET: + family = CURLPROTO_TELNET; + break; - *complete = 0; + case CURLPROTO_LDAP: + case CURLPROTO_LDAPS: + family = CURLPROTO_LDAP; + break; - if(conn->handler->do_more) - result = conn->handler->do_more(conn, complete); + case CURLPROTO_DICT: + family = CURLPROTO_DICT; + break; - if(!result && (*complete == 1)) - /* do_complete must be called after the protocol-specific DO function */ - do_complete(conn); + case CURLPROTO_FILE: + family = CURLPROTO_FILE; + break; - return result; + case CURLPROTO_TFTP: + family = CURLPROTO_TFTP; + break; + + case CURLPROTO_IMAP: + case CURLPROTO_IMAPS: + family = CURLPROTO_IMAP; + break; + + case CURLPROTO_POP3: + case CURLPROTO_POP3S: + family = CURLPROTO_POP3; + break; + + case CURLPROTO_SMTP: + case CURLPROTO_SMTPS: + family = CURLPROTO_SMTP; + break; + + case CURLPROTO_RTSP: + family = CURLPROTO_RTSP; + break; + + case CURLPROTO_RTMP: + case CURLPROTO_RTMPS: + family = CURLPROTO_RTMP; + break; + + case CURLPROTO_RTMPT: + case CURLPROTO_RTMPTS: + family = CURLPROTO_RTMPT; + break; + + case CURLPROTO_RTMPE: + family = CURLPROTO_RTMPE; + break; + + case CURLPROTO_RTMPTE: + family = CURLPROTO_RTMPTE; + break; + + case CURLPROTO_GOPHER: + family = CURLPROTO_GOPHER; + break; + + case CURLPROTO_SMB: + case CURLPROTO_SMBS: + family = CURLPROTO_SMB; + break; + + default: + family = 0; + break; + } + + return family; } diff --git a/lib/url.h b/lib/url.h index f9667cb..90d9db3 100644 --- a/lib/url.h +++ b/lib/url.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -27,26 +27,23 @@ * Prototypes for library-wide functions provided by url.c */ -CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn); -CURLcode Curl_open(struct SessionHandle **curl); +CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn); +CURLcode Curl_open(struct Curl_easy **curl); CURLcode Curl_init_userdefined(struct UserDefined *set); -CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, +CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, va_list arg); -CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src); -void Curl_freeset(struct SessionHandle * data); -CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */ -CURLcode Curl_connect(struct SessionHandle *, struct connectdata **, +CURLcode Curl_dupset(struct Curl_easy * dst, struct Curl_easy * src); +void Curl_freeset(struct Curl_easy * data); +CURLcode Curl_close(struct Curl_easy *data); /* opposite of curl_open() */ +CURLcode Curl_connect(struct Curl_easy *, struct connectdata **, bool *async, bool *protocol_connect); -CURLcode Curl_do(struct connectdata **, bool *done); -CURLcode Curl_do_more(struct connectdata *, int *completed); -CURLcode Curl_done(struct connectdata **, CURLcode, bool premature); CURLcode Curl_disconnect(struct connectdata *, bool dead_connection); CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done); CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done); CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done); CURLcode Curl_setup_conn(struct connectdata *conn, bool *protocol_done); -void Curl_free_request_state(struct SessionHandle *data); +void Curl_free_request_state(struct Curl_easy *data); int Curl_protocol_getsock(struct connectdata *conn, curl_socket_t *socks, @@ -55,24 +52,21 @@ int Curl_doing_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks); -bool Curl_isPipeliningEnabled(const struct SessionHandle *handle); -CURLcode Curl_addHandleToPipeline(struct SessionHandle *handle, +bool Curl_isPipeliningEnabled(const struct Curl_easy *handle); +CURLcode Curl_addHandleToPipeline(struct Curl_easy *handle, struct curl_llist *pipeline); -int Curl_removeHandleFromPipeline(struct SessionHandle *handle, +int Curl_removeHandleFromPipeline(struct Curl_easy *handle, struct curl_llist *pipeline); +struct connectdata * +Curl_oldest_idle_connection(struct Curl_easy *data); /* remove the specified connection from all (possible) pipelines and related queues */ -void Curl_getoff_all_pipelines(struct SessionHandle *data, +void Curl_getoff_all_pipelines(struct Curl_easy *data, struct connectdata *conn); -void Curl_close_connections(struct SessionHandle *data); +void Curl_close_connections(struct Curl_easy *data); #define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */ -#define CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE "rcmd" /* default socks5 gssapi - service */ -#define CURL_DEFAULT_PROXY_SERVICE_NAME "HTTP" /* default negotiate proxy - service */ -#define CURL_DEFAULT_SERVICE_NAME "HTTP" /* default negotiate service */ CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex); diff --git a/lib/urldata.h b/lib/urldata.h index b1c2056..3cf7ed9 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -93,7 +93,15 @@ #include #endif -#ifdef USE_POLARSSL +#ifdef USE_MBEDTLS + +#include +#include +#include +#include + +#elif defined USE_POLARSSL + #include #include #if POLARSSL_VERSION_NUMBER<0x01010000 @@ -102,6 +110,7 @@ #include #include #endif /* POLARSSL_VERSION_NUMBER<0x01010000 */ + #endif /* USE_POLARSSL */ #ifdef USE_CYASSL @@ -199,14 +208,13 @@ #define CURLEASY_MAGIC_NUMBER 0xc0dedbadU #define GOOD_EASY_HANDLE(x) \ - ((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER)) + ((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER)) /* Some convenience macros to get the larger/smaller value out of two given. We prefix with CURL to prevent name collisions. */ #define CURLMAX(x,y) ((x)>(y)?(x):(y)) #define CURLMIN(x,y) ((x)<(y)?(x):(y)) - #ifdef HAVE_GSSAPI /* Types needed for krb5-ftp connections */ struct krb5buffer { @@ -233,7 +241,6 @@ struct curl_schannel_cred { CredHandle cred_handle; TimeStamp time_stamp; int refcount; - bool cached; }; struct curl_schannel_ctxt { @@ -265,61 +272,57 @@ struct ssl_connect_data { current state of the connection. */ bool use; ssl_connection_state state; -#ifdef USE_OPENSSL + ssl_connect_state connecting_state; +#if defined(USE_OPENSSL) /* these ones requires specific SSL-types */ SSL_CTX* ctx; SSL* handle; X509* server_cert; - ssl_connect_state connecting_state; -#endif /* USE_OPENSSL */ -#ifdef USE_GNUTLS +#elif defined(USE_GNUTLS) gnutls_session_t session; gnutls_certificate_credentials_t cred; #ifdef USE_TLS_SRP gnutls_srp_client_credentials_t srp_client_cred; #endif - ssl_connect_state connecting_state; -#endif /* USE_GNUTLS */ -#ifdef USE_POLARSSL +#elif defined(USE_MBEDTLS) + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_entropy_context entropy; + mbedtls_ssl_context ssl; + int server_fd; + mbedtls_x509_crt cacert; + mbedtls_x509_crt clicert; + mbedtls_x509_crl crl; + mbedtls_pk_context pk; + mbedtls_ssl_config config; + const char *protocols[3]; +#elif defined(USE_POLARSSL) ctr_drbg_context ctr_drbg; entropy_context entropy; ssl_context ssl; - ssl_session ssn; int server_fd; x509_crt cacert; x509_crt clicert; x509_crl crl; rsa_context rsa; - ssl_connect_state connecting_state; -#endif /* USE_POLARSSL */ -#ifdef USE_CYASSL +#elif defined(USE_CYASSL) SSL_CTX* ctx; SSL* handle; - ssl_connect_state connecting_state; -#endif /* USE_CYASSL */ -#ifdef USE_NSS +#elif defined(USE_NSS) PRFileDesc *handle; char *client_nickname; - struct SessionHandle *data; + struct Curl_easy *data; struct curl_llist *obj_list; PK11GenericObject *obj_clicert; - ssl_connect_state connecting_state; -#endif /* USE_NSS */ -#ifdef USE_GSKIT +#elif defined(USE_GSKIT) gsk_handle handle; int iocport; - ssl_connect_state connecting_state; -#endif -#ifdef USE_AXTLS +#elif defined(USE_AXTLS) SSL_CTX* ssl_ctx; SSL* ssl; - ssl_connect_state connecting_state; -#endif /* USE_AXTLS */ -#ifdef USE_SCHANNEL +#elif defined(USE_SCHANNEL) struct curl_schannel_cred *cred; struct curl_schannel_ctxt *ctxt; SecPkgContext_StreamSizes stream_sizes; - ssl_connect_state connecting_state; size_t encdata_length, decdata_length; size_t encdata_offset, decdata_offset; unsigned char *encdata_buffer, *decdata_buffer; @@ -327,14 +330,14 @@ struct ssl_connect_data { CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ bool recv_sspi_close_notify; /* true if connection closed by close_notify */ bool recv_connection_closed; /* true if connection closed, regardless how */ -#endif /* USE_SCHANNEL */ -#ifdef USE_DARWINSSL +#elif defined(USE_DARWINSSL) SSLContextRef ssl_ctx; curl_socket_t ssl_sockfd; - ssl_connect_state connecting_state; bool ssl_direction; /* true if writing, false if reading */ size_t ssl_write_buffered_length; -#endif /* USE_DARWINSSL */ +#elif defined(USE_SSL) +#error "SSL backend specific information missing from ssl_connect_data" +#endif }; struct ssl_config_data { @@ -348,6 +351,7 @@ struct ssl_config_data { char *CAfile; /* certificate to verify peer against */ const char *CRLfile; /* CRL to check certificate revocation */ const char *issuercert;/* optional issuer certificate filename */ + char *clientcert; char *random_file; /* path to file containing "random" data */ char *egdsocket; /* path to file containing the EGD daemon socket */ char *cipher_list; /* list of ciphers to use */ @@ -368,10 +372,12 @@ struct ssl_config_data { /* information stored about one single SSL session */ struct curl_ssl_session { char *name; /* host name for which this ID was used */ + char *conn_to_host; /* host name for the connection (may be NULL) */ void *sessionid; /* as returned from the SSL layer */ size_t idsize; /* if known, otherwise 0 */ long age; /* just a number, the higher the more recent */ - int remote_port; /* remote port to connect to */ + int remote_port; /* remote port */ + int conn_to_port; /* remote port for the connection (may be -1) */ struct ssl_config_data ssl_config; /* setup for this session */ }; @@ -457,7 +463,7 @@ struct negotiatedata { #ifdef HAVE_GSSAPI OM_uint32 status; gss_ctx_id_t context; - gss_name_t server_name; + gss_name_t spn; gss_buffer_desc output_token; #else #ifdef USE_WINDOWS_SSPI @@ -466,7 +472,7 @@ struct negotiatedata { CtxtHandle *context; SEC_WINNT_AUTH_IDENTITY identity; SEC_WINNT_AUTH_IDENTITY *p_identity; - TCHAR *server_name; + TCHAR *spn; size_t token_max; BYTE *output_token; size_t output_token_length; @@ -483,6 +489,10 @@ struct ConnectBits { /* always modify bits.close with the connclose() and connkeep() macros! */ bool close; /* if set, we close the connection after this request */ bool reuse; /* if set, this is a re-used connection */ + bool conn_to_host; /* if set, this connection has a "connect to host" + that overrides the host in the URL */ + bool conn_to_port; /* if set, this connection has a "connect to port" + that overrides the port in the URL (remote port) */ bool proxy; /* if set, this transfer is done through a proxy - any type */ bool httpproxy; /* if set, this transfer is done through a http proxy */ bool user_passwd; /* do we use user+password for this connection? */ @@ -531,6 +541,10 @@ struct ConnectBits { connection */ bool type_set; /* type= was used in the URL */ bool multiplex; /* connection is multiplexed */ + + bool tcp_fastopen; /* use TCP Fast Open */ + bool tls_enable_npn; /* TLS NPN extension? */ + bool tls_enable_alpn; /* TLS ALPN extension? */ }; struct hostname { @@ -604,9 +618,9 @@ enum upgrade101 { }; /* - * Request specific data in the easy handle (SessionHandle). Previously, + * Request specific data in the easy handle (Curl_easy). Previously, * these members were on the connectdata struct but since a conn struct may - * now be shared between different SessionHandles, we store connection-specific + * now be shared between different Curl_easys, we store connection-specific * data here. This struct only keeps stuff that's interesting for *this* * request, as it will be cleared between multiple ones */ @@ -777,7 +791,7 @@ struct Curl_handler { /* If used, this function gets called from transfer.c:readwrite_data() to allow the protocol to do extra reads/writes */ - CURLcode (*readwrite)(struct SessionHandle *data, struct connectdata *conn, + CURLcode (*readwrite)(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *readmore); long defport; /* Default port. */ @@ -802,7 +816,7 @@ struct Curl_handler { url query strings (?foo=bar) ! */ #define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per request instead of per connection */ - +#define PROTOPT_ALPN_NPN (1<<8) /* set ALPN and/or NPN for this */ /* return the count of bytes sent, or -1 on error */ typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */ @@ -818,15 +832,29 @@ typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */ size_t len, /* max amount to read */ CURLcode *err); /* error to return */ +#ifdef USE_RECV_BEFORE_SEND_WORKAROUND +struct postponed_data { + char *buffer; /* Temporal store for received data during + sending, must be freed */ + size_t allocated_size; /* Size of temporal store */ + size_t recv_size; /* Size of received data during sending */ + size_t recv_processed; /* Size of processed part of postponed data */ +#ifdef DEBUGBUILD + curl_socket_t bindsock;/* Structure must be bound to specific socket, + used only for DEBUGASSERT */ +#endif /* DEBUGBUILD */ +}; +#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */ + /* * The connectdata struct contains all fields and variables that should be * unique for an entire connection. */ struct connectdata { - /* 'data' is the CURRENT SessionHandle using this connection -- take great + /* 'data' is the CURRENT Curl_easy using this connection -- take great caution that this might very well vary between different times this connection is used! */ - struct SessionHandle *data; + struct Curl_easy *data; /* chunk is for HTTP chunked encoding, but is in the general connectdata struct only because we can do just about any protocol through a HTTP proxy @@ -867,10 +895,14 @@ struct connectdata { int socktype; /* SOCK_STREAM or SOCK_DGRAM */ struct hostname host; + struct hostname conn_to_host; /* the host to connect to. valid only if + bits.conn_to_host is set */ struct hostname proxy; long port; /* which port to use locally */ - int remote_port; /* what remote port to connect to, not the proxy port! */ + int remote_port; /* the remote port, not the proxy port! */ + int conn_to_port; /* the remote port to connect to. valid only if + bits.conn_to_port is set */ /* 'primary_ip' and 'primary_port' get filled with peer's numerical ip address and port number whenever an outgoing connection is @@ -893,7 +925,7 @@ struct connectdata { char *passwd; /* password string, allocated */ char *options; /* options string, allocated */ - char *xoauth2_bearer; /* bearer token for xoauth2, allocated */ + char *oauth_bearer; /* bearer token for OAuth 2.0, allocated */ char *proxyuser; /* proxy user name string, allocated */ char *proxypasswd; /* proxy password string, allocated */ @@ -912,8 +944,12 @@ struct connectdata { Curl_recv *recv[2]; Curl_send *send[2]; +#ifdef USE_RECV_BEFORE_SEND_WORKAROUND + struct postponed_data postponed[2]; /* two buffers for two sockets */ +#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */ struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */ struct ssl_config_data ssl_config; + bool tls_upgraded; struct ConnectBits bits; /* various state-flags for this connection */ @@ -929,7 +965,7 @@ struct connectdata { const struct Curl_handler *handler; /* Connection's protocol handler */ const struct Curl_handler *given; /* The protocol first given */ - long ip_version; /* copied from the SessionHandle at creation time */ + long ip_version; /* copied from the Curl_easy at creation time */ /**** curl_get() phase fields */ @@ -1172,7 +1208,7 @@ typedef enum { /* * Values that are generated, temporary or calculated internally for a * "session handle" must be defined within the 'struct UrlState'. This struct - * will be used within the SessionHandle struct. When the 'SessionHandle' + * will be used within the Curl_easy struct. When the 'Curl_easy' * struct is cloned, this data MUST NOT be copied. * * Remember that any "state" information goes globally for the curl handle. @@ -1218,11 +1254,13 @@ struct UrlState { bytes / second */ bool this_is_a_follow; /* this is a followed Location: request */ - char *first_host; /* if set, this should be the host name that we will + char *first_host; /* host name of the first (not followed) request. + if set, this should be the host name that we will sent authorization to, no else. Used to make Location: following not keep sending user+password... This is strdup() data. */ + int first_remote_port; /* remote port of the first (not followed) request */ struct curl_ssl_session *session; /* array of 'max_ssl_sessions' size */ long sessionage; /* number of the most recent session */ char *tempwrite; /* allocated buffer to keep data in when a write @@ -1306,12 +1344,19 @@ struct UrlState { curl_off_t infilesize; /* size of file to upload, -1 means unknown. Copied from set.filesize at start of operation */ - int drain; /* Increased when this stream has data to read, even if its - socket not necessarily is readable. Decreased when - checked. */ - bool done; /* set to FALSE when Curl_do() is called and set to TRUE when - Curl_done() is called, to prevent Curl_done() to get invoked - twice when the multi interface is used. */ + size_t drain; /* Increased when this stream has data to read, even if its + socket is not necessarily is readable. Decreased when + checked. */ + bool done; /* set to FALSE when Curl_init_do() is called and set to TRUE + when multi_done() is called, to prevent multi_done() to get + invoked twice when the multi interface is used. */ + + curl_read_callback fread_func; /* read callback/function */ + void *in; /* CURLOPT_READDATA */ + + struct Curl_easy *stream_depends_on; + bool stream_depends_e; /* set or don't set the Exclusive bit */ + int stream_weight; }; @@ -1350,6 +1395,7 @@ enum dupstring { STRING_COOKIE, /* HTTP cookie string to send */ STRING_COOKIEJAR, /* dump all cookies to this file */ STRING_CUSTOMREQUEST, /* HTTP/FTP/RTSP request/method to use */ + STRING_DEFAULT_PROTOCOL, /* Protocol to use when the URL doesn't specify */ STRING_DEVICE, /* local network interface/address to use */ STRING_ENCODING, /* Accept-Encoding string */ STRING_FTP_ACCOUNT, /* ftp account data */ @@ -1391,8 +1437,10 @@ enum dupstring { STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */ #endif #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - STRING_SOCKS5_GSSAPI_SERVICE, /* GSSAPI service name */ STRING_PROXY_SERVICE_NAME, /* Proxy service name */ +#endif +#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \ + defined(USE_SPNEGO) STRING_SERVICE_NAME, /* Service name */ #endif STRING_MAIL_FROM, @@ -1427,7 +1475,7 @@ struct UserDefined { proxy string features a ":[port]" that one will override this. */ void *out; /* CURLOPT_WRITEDATA */ - void *in; /* CURLOPT_READDATA */ + void *in_set; /* CURLOPT_READDATA */ void *writeheader; /* write the header to this if non-NULL */ void *rtp_out; /* write RTP to this if non-NULL */ long use_port; /* which port to use (when not using default) */ @@ -1452,7 +1500,7 @@ struct UserDefined { curl_write_callback fwrite_func; /* function that stores the output */ curl_write_callback fwrite_header; /* function that stores headers */ curl_write_callback fwrite_rtp; /* function that stores interleaved RTP */ - curl_read_callback fread_func; /* function that reads the input */ + curl_read_callback fread_func_set; /* function that reads the input */ int is_fread_set; /* boolean, has read callback been set to non-NULL? */ int is_fwrite_set; /* boolean, has write callback been set to non-NULL? */ curl_progress_callback fprogress; /* OLD and deprecated progress callback */ @@ -1484,7 +1532,8 @@ struct UserDefined { long connecttimeout; /* in milliseconds, 0 means no timeout */ long accepttimeout; /* in milliseconds, 0 means no timeout */ long server_response_timeout; /* in milliseconds, 0 means no timeout */ - long tftp_blksize ; /* in bytes, 0 means use default */ + long tftp_blksize; /* in bytes, 0 means use default */ + bool tftp_no_options; /* do not send TFTP options requests */ curl_off_t filesize; /* size of file to upload, -1 means unknown */ long low_speed_limit; /* bytes/second */ long low_speed_time; /* number of seconds */ @@ -1509,6 +1558,8 @@ struct UserDefined { struct curl_slist *telnet_options; /* linked list of telnet options */ struct curl_slist *resolve; /* list of names to add/remove from DNS cache */ + struct curl_slist *connect_to; /* list of host:port mappings to override + the hostname and port to connect to */ curl_TimeCond timecondition; /* kind of time/date comparison */ time_t timevalue; /* what time to compare with */ Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */ @@ -1556,7 +1607,6 @@ struct UserDefined { bool http_set_referer; /* is a custom referer used */ bool http_auto_referer; /* set "correct" referer when following location: */ bool opt_no_body; /* as set with CURLOPT_NOBODY */ - bool set_port; /* custom port number used */ bool upload; /* upload request */ enum CURL_NETRC_OPTION use_netrc; /* defined in include/curl.h */ @@ -1596,7 +1646,7 @@ struct UserDefined { long allowed_protocols; long redir_protocols; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - long socks5_gssapi_nec; /* flag to support nec socks5 server */ + bool socks5_gssapi_nec; /* Flag to support NEC SOCKS5 server */ #endif struct curl_slist *mail_rcpt; /* linked list of mail recipients */ bool sasl_ir; /* Enable/disable SASL initial response */ @@ -1618,15 +1668,20 @@ struct UserDefined { bool tcp_keepalive; /* use TCP keepalives */ long tcp_keepidle; /* seconds in idle before sending keepalive probe */ long tcp_keepintvl; /* seconds between TCP keepalive probes */ + bool tcp_fastopen; /* use TCP Fast Open */ size_t maxconnects; /* Max idle connections in the connection cache */ - bool ssl_enable_npn; /* TLS NPN extension? */ - bool ssl_enable_alpn; /* TLS ALPN extension? */ + bool ssl_enable_npn; /* TLS NPN extension? */ + bool ssl_enable_alpn; /* TLS ALPN extension? */ bool path_as_is; /* allow dotdots? */ bool pipewait; /* wait for pipe/multiplex status before starting a new connection */ long expect_100_timeout; /* in milliseconds */ + + struct Curl_easy *stream_depends_on; + bool stream_depends_e; /* set or don't set the Exclusive bit */ + int stream_weight; }; struct Names { @@ -1649,10 +1704,10 @@ struct Names { * 'struct UrlState' instead. */ -struct SessionHandle { +struct Curl_easy { /* first, two fields for the linked list of these */ - struct SessionHandle *next; - struct SessionHandle *prev; + struct Curl_easy *next; + struct Curl_easy *prev; struct connectdata *easy_conn; /* the "unit's" connection */ diff --git a/lib/vauth/cleartext.c b/lib/vauth/cleartext.c new file mode 100644 index 0000000..4e906bc --- /dev/null +++ b/lib/vauth/cleartext.c @@ -0,0 +1,157 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * RFC4616 PLAIN authentication + * Draft LOGIN SASL Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include +#include "urldata.h" + +#include "vauth/vauth.h" +#include "curl_base64.h" +#include "curl_md5.h" +#include "warnless.h" +#include "strtok.h" +#include "strequal.h" +#include "rawstr.h" +#include "sendf.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_create_plain_message() + * + * This is used to generate an already encoded PLAIN message ready + * for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name. + * passdwp [in] - The user's password. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_plain_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + char **outptr, size_t *outlen) +{ + CURLcode result; + char *plainauth; + size_t ulen; + size_t plen; + + ulen = strlen(userp); + plen = strlen(passwdp); + + plainauth = malloc(2 * ulen + plen + 2); + if(!plainauth) { + *outlen = 0; + *outptr = NULL; + return CURLE_OUT_OF_MEMORY; + } + + /* Calculate the reply */ + memcpy(plainauth, userp, ulen); + plainauth[ulen] = '\0'; + memcpy(plainauth + ulen + 1, userp, ulen); + plainauth[2 * ulen + 1] = '\0'; + memcpy(plainauth + 2 * ulen + 2, passwdp, plen); + + /* Base64 encode the reply */ + result = Curl_base64_encode(data, plainauth, 2 * ulen + plen + 2, outptr, + outlen); + free(plainauth); + + return result; +} + +/* + * Curl_auth_create_login_message() + * + * This is used to generate an already encoded LOGIN message containing the + * user name or password ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * valuep [in] - The user name or user's password. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_login_message(struct Curl_easy *data, + const char *valuep, char **outptr, + size_t *outlen) +{ + size_t vlen = strlen(valuep); + + if(!vlen) { + /* Calculate an empty reply */ + *outptr = strdup("="); + if(*outptr) { + *outlen = (size_t) 1; + return CURLE_OK; + } + + *outlen = 0; + return CURLE_OUT_OF_MEMORY; + } + + /* Base64 encode the value */ + return Curl_base64_encode(data, valuep, vlen, outptr, outlen); +} + +/* + * Curl_auth_create_external_message() + * + * This is used to generate an already encoded EXTERNAL message containing + * the user name ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * user [in] - The user name. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_external_message(struct Curl_easy *data, + const char *user, char **outptr, + size_t *outlen) +{ + /* This is the same formatting as the login message */ + return Curl_auth_create_login_message(data, user, outptr, outlen); +} diff --git a/lib/vauth/cram.c b/lib/vauth/cram.c new file mode 100644 index 0000000..3074a16 --- /dev/null +++ b/lib/vauth/cram.c @@ -0,0 +1,138 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * RFC2195 CRAM-MD5 authentication + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) + +#include +#include "urldata.h" + +#include "vauth/vauth.h" +#include "curl_base64.h" +#include "curl_hmac.h" +#include "curl_md5.h" +#include "warnless.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_decode_cram_md5_message() + * + * This is used to decode an already encoded CRAM-MD5 challenge message. + * + * Parameters: + * + * chlg64 [in] - The base64 encoded challenge message. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr, + size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t chlg64len = strlen(chlg64); + + *outptr = NULL; + *outlen = 0; + + /* Decode the challenge if necessary */ + if(chlg64len && *chlg64 != '=') + result = Curl_base64_decode(chlg64, (unsigned char **) outptr, outlen); + + return result; +} + +/* + * Curl_auth_create_cram_md5_message() + * + * This is used to generate an already encoded CRAM-MD5 response message ready + * for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg [in] - The challenge. + * userp [in] - The user name. + * passdwp [in] - The user's password. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data, + const char *chlg, + const char *userp, + const char *passwdp, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + HMAC_context *ctxt; + unsigned char digest[MD5_DIGEST_LEN]; + char *response; + + if(chlg) + chlglen = strlen(chlg); + + /* Compute the digest using the password as the key */ + ctxt = Curl_HMAC_init(Curl_HMAC_MD5, + (const unsigned char *) passwdp, + curlx_uztoui(strlen(passwdp))); + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + /* Update the digest with the given challenge */ + if(chlglen > 0) + Curl_HMAC_update(ctxt, (const unsigned char *) chlg, + curlx_uztoui(chlglen)); + + /* Finalise the digest */ + Curl_HMAC_final(ctxt, digest); + + /* Generate the response */ + response = aprintf( + "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + userp, digest[0], digest[1], digest[2], digest[3], digest[4], + digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], + digest[11], digest[12], digest[13], digest[14], digest[15]); + if(!response) + return CURLE_OUT_OF_MEMORY; + + /* Base64 encode the response */ + result = Curl_base64_encode(data, response, 0, outptr, outlen); + + free(response); + + return result; +} + +#endif /* !CURL_DISABLE_CRYPTO_AUTH */ diff --git a/lib/vauth/digest.c b/lib/vauth/digest.c new file mode 100644 index 0000000..26ea7b5 --- /dev/null +++ b/lib/vauth/digest.c @@ -0,0 +1,883 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * RFC2831 DIGEST-MD5 authentication + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) + +#include + +#include "vauth/vauth.h" +#include "vauth/digest.h" +#include "urldata.h" +#include "curl_base64.h" +#include "curl_hmac.h" +#include "curl_md5.h" +#include "vtls/vtls.h" +#include "warnless.h" +#include "strtok.h" +#include "rawstr.h" +#include "non-ascii.h" /* included for Curl_convert_... prototypes */ +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#if !defined(USE_WINDOWS_SSPI) +#define DIGEST_QOP_VALUE_AUTH (1 << 0) +#define DIGEST_QOP_VALUE_AUTH_INT (1 << 1) +#define DIGEST_QOP_VALUE_AUTH_CONF (1 << 2) + +#define DIGEST_QOP_VALUE_STRING_AUTH "auth" +#define DIGEST_QOP_VALUE_STRING_AUTH_INT "auth-int" +#define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf" + +/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines. + It converts digest text to ASCII so the MD5 will be correct for + what ultimately goes over the network. +*/ +#define CURL_OUTPUT_DIGEST_CONV(a, b) \ + result = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \ + if(result) { \ + free(b); \ + return result; \ + } +#endif /* !USE_WINDOWS_SSPI */ + +bool Curl_auth_digest_get_pair(const char *str, char *value, char *content, + const char **endptr) +{ + int c; + bool starts_with_quote = FALSE; + bool escape = FALSE; + + for(c = DIGEST_MAX_VALUE_LENGTH - 1; (*str && (*str != '=') && c--);) + *value++ = *str++; + *value = 0; + + if('=' != *str++) + /* eek, no match */ + return FALSE; + + if('\"' == *str) { + /* This starts with a quote so it must end with one as well! */ + str++; + starts_with_quote = TRUE; + } + + for(c = DIGEST_MAX_CONTENT_LENGTH - 1; *str && c--; str++) { + switch(*str) { + case '\\': + if(!escape) { + /* possibly the start of an escaped quote */ + escape = TRUE; + *content++ = '\\'; /* Even though this is an escape character, we still + store it as-is in the target buffer */ + continue; + } + break; + + case ',': + if(!starts_with_quote) { + /* This signals the end of the content if we didn't get a starting + quote and then we do "sloppy" parsing */ + c = 0; /* the end */ + continue; + } + break; + + case '\r': + case '\n': + /* end of string */ + c = 0; + continue; + + case '\"': + if(!escape && starts_with_quote) { + /* end of string */ + c = 0; + continue; + } + break; + } + + escape = FALSE; + *content++ = *str; + } + + *content = 0; + *endptr = str; + + return TRUE; +} + +#if !defined(USE_WINDOWS_SSPI) +/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/ +static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */ + unsigned char *dest) /* 33 bytes */ +{ + int i; + for(i = 0; i < 16; i++) + snprintf((char *) &dest[i * 2], 3, "%02x", source[i]); +} + +/* Perform quoted-string escaping as described in RFC2616 and its errata */ +static char *auth_digest_string_quoted(const char *source) +{ + char *dest, *d; + const char *s = source; + size_t n = 1; /* null terminator */ + + /* Calculate size needed */ + while(*s) { + ++n; + if(*s == '"' || *s == '\\') { + ++n; + } + ++s; + } + + dest = malloc(n); + if(dest) { + s = source; + d = dest; + while(*s) { + if(*s == '"' || *s == '\\') { + *d++ = '\\'; + } + *d++ = *s++; + } + *d = 0; + } + + return dest; +} + +/* Retrieves the value for a corresponding key from the challenge string + * returns TRUE if the key could be found, FALSE if it does not exists + */ +static bool auth_digest_get_key_value(const char *chlg, + const char *key, + char *value, + size_t max_val_len, + char end_char) +{ + char *find_pos; + size_t i; + + find_pos = strstr(chlg, key); + if(!find_pos) + return FALSE; + + find_pos += strlen(key); + + for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i) + value[i] = *find_pos++; + value[i] = '\0'; + + return TRUE; +} + +static CURLcode auth_digest_get_qop_values(const char *options, int *value) +{ + char *tmp; + char *token; + char *tok_buf; + + /* Initialise the output */ + *value = 0; + + /* Tokenise the list of qop values. Use a temporary clone of the buffer since + strtok_r() ruins it. */ + tmp = strdup(options); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + token = strtok_r(tmp, ",", &tok_buf); + while(token != NULL) { + if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) + *value |= DIGEST_QOP_VALUE_AUTH; + else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) + *value |= DIGEST_QOP_VALUE_AUTH_INT; + else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF)) + *value |= DIGEST_QOP_VALUE_AUTH_CONF; + + token = strtok_r(NULL, ",", &tok_buf); + } + + free(tmp); + + return CURLE_OK; +} + +/* + * auth_decode_digest_md5_message() + * + * This is used internally to decode an already encoded DIGEST-MD5 challenge + * message into the seperate attributes. + * + * Parameters: + * + * chlg64 [in] - The base64 encoded challenge message. + * nonce [in/out] - The buffer where the nonce will be stored. + * nlen [in] - The length of the nonce buffer. + * realm [in/out] - The buffer where the realm will be stored. + * rlen [in] - The length of the realm buffer. + * alg [in/out] - The buffer where the algorithm will be stored. + * alen [in] - The length of the algorithm buffer. + * qop [in/out] - The buffer where the qop-options will be stored. + * qlen [in] - The length of the qop buffer. + * + * Returns CURLE_OK on success. + */ +static CURLcode auth_decode_digest_md5_message(const char *chlg64, + char *nonce, size_t nlen, + char *realm, size_t rlen, + char *alg, size_t alen, + char *qop, size_t qlen) +{ + CURLcode result = CURLE_OK; + unsigned char *chlg = NULL; + size_t chlglen = 0; + size_t chlg64len = strlen(chlg64); + + /* Decode the base-64 encoded challenge message */ + if(chlg64len && *chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) + return CURLE_BAD_CONTENT_ENCODING; + + /* Retrieve nonce string from the challenge */ + if(!auth_digest_get_key_value((char *) chlg, "nonce=\"", nonce, nlen, + '\"')) { + free(chlg); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Retrieve realm string from the challenge */ + if(!auth_digest_get_key_value((char *) chlg, "realm=\"", realm, rlen, + '\"')) { + /* Challenge does not have a realm, set empty string [RFC2831] page 6 */ + strcpy(realm, ""); + } + + /* Retrieve algorithm string from the challenge */ + if(!auth_digest_get_key_value((char *) chlg, "algorithm=", alg, alen, ',')) { + free(chlg); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Retrieve qop-options string from the challenge */ + if(!auth_digest_get_key_value((char *) chlg, "qop=\"", qop, qlen, '\"')) { + free(chlg); + return CURLE_BAD_CONTENT_ENCODING; + } + + free(chlg); + + return CURLE_OK; +} + +/* + * Curl_auth_create_digest_md5_message() + * + * This is used to generate an already encoded DIGEST-MD5 response message + * ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg64 [in] - The base64 encoded challenge message. + * userp [in] - The user name. + * passdwp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, + const char *chlg64, + const char *userp, + const char *passwdp, + const char *service, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t i; + MD5_context *ctxt; + char *response = NULL; + unsigned char digest[MD5_DIGEST_LEN]; + char HA1_hex[2 * MD5_DIGEST_LEN + 1]; + char HA2_hex[2 * MD5_DIGEST_LEN + 1]; + char resp_hash_hex[2 * MD5_DIGEST_LEN + 1]; + char nonce[64]; + char realm[128]; + char algorithm[64]; + char qop_options[64]; + int qop_values; + char cnonce[33]; + unsigned int entropy[4]; + char nonceCount[] = "00000001"; + char method[] = "AUTHENTICATE"; + char qop[] = DIGEST_QOP_VALUE_STRING_AUTH; + char *spn = NULL; + + /* Decode the challange message */ + result = auth_decode_digest_md5_message(chlg64, nonce, sizeof(nonce), + realm, sizeof(realm), + algorithm, sizeof(algorithm), + qop_options, sizeof(qop_options)); + if(result) + return result; + + /* We only support md5 sessions */ + if(strcmp(algorithm, "md5-sess") != 0) + return CURLE_BAD_CONTENT_ENCODING; + + /* Get the qop-values from the qop-options */ + result = auth_digest_get_qop_values(qop_options, &qop_values); + if(result) + return result; + + /* We only support auth quality-of-protection */ + if(!(qop_values & DIGEST_QOP_VALUE_AUTH)) + return CURLE_BAD_CONTENT_ENCODING; + + /* Generate 16 bytes of random data */ + entropy[0] = Curl_rand(data); + entropy[1] = Curl_rand(data); + entropy[2] = Curl_rand(data); + entropy[3] = Curl_rand(data); + + /* Convert the random data into a 32 byte hex string */ + snprintf(cnonce, sizeof(cnonce), "%08x%08x%08x%08x", + entropy[0], entropy[1], entropy[2], entropy[3]); + + /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */ + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + Curl_MD5_update(ctxt, (const unsigned char *) userp, + curlx_uztoui(strlen(userp))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) realm, + curlx_uztoui(strlen(realm))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) passwdp, + curlx_uztoui(strlen(passwdp))); + Curl_MD5_final(ctxt, digest); + + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) nonce, + curlx_uztoui(strlen(nonce))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) cnonce, + curlx_uztoui(strlen(cnonce))); + Curl_MD5_final(ctxt, digest); + + /* Convert calculated 16 octet hex into 32 bytes string */ + for(i = 0; i < MD5_DIGEST_LEN; i++) + snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]); + + /* Generate our SPN */ + spn = Curl_auth_build_spn(service, realm, NULL); + if(!spn) + return CURLE_OUT_OF_MEMORY; + + /* Calculate H(A2) */ + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) { + free(spn); + + return CURLE_OUT_OF_MEMORY; + } + + Curl_MD5_update(ctxt, (const unsigned char *) method, + curlx_uztoui(strlen(method))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) spn, + curlx_uztoui(strlen(spn))); + Curl_MD5_final(ctxt, digest); + + for(i = 0; i < MD5_DIGEST_LEN; i++) + snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]); + + /* Now calculate the response hash */ + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) { + free(spn); + + return CURLE_OUT_OF_MEMORY; + } + + Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) nonce, + curlx_uztoui(strlen(nonce))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + + Curl_MD5_update(ctxt, (const unsigned char *) nonceCount, + curlx_uztoui(strlen(nonceCount))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) cnonce, + curlx_uztoui(strlen(cnonce))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) qop, + curlx_uztoui(strlen(qop))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + + Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN); + Curl_MD5_final(ctxt, digest); + + for(i = 0; i < MD5_DIGEST_LEN; i++) + snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]); + + /* Generate the response */ + response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\"," + "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s," + "qop=%s", + userp, realm, nonce, + cnonce, nonceCount, spn, resp_hash_hex, qop); + free(spn); + if(!response) + return CURLE_OUT_OF_MEMORY; + + /* Base64 encode the response */ + result = Curl_base64_encode(data, response, 0, outptr, outlen); + + free(response); + + return result; +} + +/* + * Curl_auth_decode_digest_http_message() + * + * This is used to decode a HTTP DIGEST challenge message into the seperate + * attributes. + * + * Parameters: + * + * chlg [in] - The challenge message. + * digest [in/out] - The digest data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_digest_http_message(const char *chlg, + struct digestdata *digest) +{ + bool before = FALSE; /* got a nonce before */ + bool foundAuth = FALSE; + bool foundAuthInt = FALSE; + char *token = NULL; + char *tmp = NULL; + + /* If we already have received a nonce, keep that in mind */ + if(digest->nonce) + before = TRUE; + + /* Clean up any former leftovers and initialise to defaults */ + Curl_auth_digest_cleanup(digest); + + for(;;) { + char value[DIGEST_MAX_VALUE_LENGTH]; + char content[DIGEST_MAX_CONTENT_LENGTH]; + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Extract a value=content pair */ + if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { + if(Curl_raw_equal(value, "nonce")) { + free(digest->nonce); + digest->nonce = strdup(content); + if(!digest->nonce) + return CURLE_OUT_OF_MEMORY; + } + else if(Curl_raw_equal(value, "stale")) { + if(Curl_raw_equal(content, "true")) { + digest->stale = TRUE; + digest->nc = 1; /* we make a new nonce now */ + } + } + else if(Curl_raw_equal(value, "realm")) { + free(digest->realm); + digest->realm = strdup(content); + if(!digest->realm) + return CURLE_OUT_OF_MEMORY; + } + else if(Curl_raw_equal(value, "opaque")) { + free(digest->opaque); + digest->opaque = strdup(content); + if(!digest->opaque) + return CURLE_OUT_OF_MEMORY; + } + else if(Curl_raw_equal(value, "qop")) { + char *tok_buf; + /* Tokenize the list and choose auth if possible, use a temporary + clone of the buffer since strtok_r() ruins it */ + tmp = strdup(content); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + token = strtok_r(tmp, ",", &tok_buf); + while(token != NULL) { + if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) { + foundAuth = TRUE; + } + else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) { + foundAuthInt = TRUE; + } + token = strtok_r(NULL, ",", &tok_buf); + } + + free(tmp); + + /* Select only auth or auth-int. Otherwise, ignore */ + if(foundAuth) { + free(digest->qop); + digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH); + if(!digest->qop) + return CURLE_OUT_OF_MEMORY; + } + else if(foundAuthInt) { + free(digest->qop); + digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH_INT); + if(!digest->qop) + return CURLE_OUT_OF_MEMORY; + } + } + else if(Curl_raw_equal(value, "algorithm")) { + free(digest->algorithm); + digest->algorithm = strdup(content); + if(!digest->algorithm) + return CURLE_OUT_OF_MEMORY; + + if(Curl_raw_equal(content, "MD5-sess")) + digest->algo = CURLDIGESTALGO_MD5SESS; + else if(Curl_raw_equal(content, "MD5")) + digest->algo = CURLDIGESTALGO_MD5; + else + return CURLE_BAD_CONTENT_ENCODING; + } + else { + /* Unknown specifier, ignore it! */ + } + } + else + break; /* We're done here */ + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Allow the list to be comma-separated */ + if(',' == *chlg) + chlg++; + } + + /* We had a nonce since before, and we got another one now without + 'stale=true'. This means we provided bad credentials in the previous + request */ + if(before && !digest->stale) + return CURLE_BAD_CONTENT_ENCODING; + + /* We got this header without a nonce, that's a bad Digest line! */ + if(!digest->nonce) + return CURLE_BAD_CONTENT_ENCODING; + + return CURLE_OK; +} + +/* + * Curl_auth_create_digest_http_message() + * + * This is used to generate a HTTP DIGEST response message ready for sending + * to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name. + * passdwp [in] - The user's password. + * request [in] - The HTTP request. + * uripath [in] - The path of the HTTP uri. + * digest [in/out] - The digest data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uripath, + struct digestdata *digest, + char **outptr, size_t *outlen) +{ + CURLcode result; + unsigned char md5buf[16]; /* 16 bytes/128 bits */ + unsigned char request_digest[33]; + unsigned char *md5this; + unsigned char ha1[33]; /* 32 digits and 1 zero byte */ + unsigned char ha2[33]; /* 32 digits and 1 zero byte */ + char cnoncebuf[33]; + char *cnonce = NULL; + size_t cnonce_sz = 0; + char *userp_quoted; + char *response = NULL; + char *tmp = NULL; + + if(!digest->nc) + digest->nc = 1; + + if(!digest->cnonce) { + snprintf(cnoncebuf, sizeof(cnoncebuf), "%08x%08x%08x%08x", + Curl_rand(data), Curl_rand(data), + Curl_rand(data), Curl_rand(data)); + + result = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), + &cnonce, &cnonce_sz); + if(result) + return result; + + digest->cnonce = cnonce; + } + + /* + If the algorithm is "MD5" or unspecified (which then defaults to MD5): + + A1 = unq(username-value) ":" unq(realm-value) ":" passwd + + If the algorithm is "MD5-sess" then: + + A1 = H(unq(username-value) ":" unq(realm-value) ":" passwd) ":" + unq(nonce-value) ":" unq(cnonce-value) + */ + + md5this = (unsigned char *) + aprintf("%s:%s:%s", userp, digest->realm, passwdp); + if(!md5this) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, md5this); + free(md5this); + auth_digest_md5_to_ascii(md5buf, ha1); + + if(digest->algo == CURLDIGESTALGO_MD5SESS) { + /* nonce and cnonce are OUTSIDE the hash */ + tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, tmp); /* Convert on non-ASCII machines */ + Curl_md5it(md5buf, (unsigned char *) tmp); + free(tmp); + auth_digest_md5_to_ascii(md5buf, ha1); + } + + /* + If the "qop" directive's value is "auth" or is unspecified, then A2 is: + + A2 = Method ":" digest-uri-value + + If the "qop" value is "auth-int", then A2 is: + + A2 = Method ":" digest-uri-value ":" H(entity-body) + + (The "Method" value is the HTTP request method as specified in section + 5.1.1 of RFC 2616) + */ + + md5this = (unsigned char *) aprintf("%s:%s", request, uripath); + + if(digest->qop && Curl_raw_equal(digest->qop, "auth-int")) { + /* We don't support auth-int for PUT or POST at the moment. + TODO: replace md5 of empty string with entity-body for PUT/POST */ + unsigned char *md5this2 = (unsigned char *) + aprintf("%s:%s", md5this, "d41d8cd98f00b204e9800998ecf8427e"); + free(md5this); + md5this = md5this2; + } + + if(!md5this) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, md5this); + free(md5this); + auth_digest_md5_to_ascii(md5buf, ha2); + + if(digest->qop) { + md5this = (unsigned char *) aprintf("%s:%s:%08x:%s:%s:%s", + ha1, + digest->nonce, + digest->nc, + digest->cnonce, + digest->qop, + ha2); + } + else { + md5this = (unsigned char *) aprintf("%s:%s:%s", + ha1, + digest->nonce, + ha2); + } + + if(!md5this) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, md5this); + free(md5this); + auth_digest_md5_to_ascii(md5buf, request_digest); + + /* For test case 64 (snooped from a Mozilla 1.3a request) + + Authorization: Digest username="testuser", realm="testrealm", \ + nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca" + + Digest parameters are all quoted strings. Username which is provided by + the user will need double quotes and backslashes within it escaped. For + the other fields, this shouldn't be an issue. realm, nonce, and opaque + are copied as is from the server, escapes and all. cnonce is generated + with web-safe characters. uri is already percent encoded. nc is 8 hex + characters. algorithm and qop with standard values only contain web-safe + characters. + */ + userp_quoted = auth_digest_string_quoted(userp); + if(!userp_quoted) + return CURLE_OUT_OF_MEMORY; + + if(digest->qop) { + response = aprintf("username=\"%s\", " + "realm=\"%s\", " + "nonce=\"%s\", " + "uri=\"%s\", " + "cnonce=\"%s\", " + "nc=%08x, " + "qop=%s, " + "response=\"%s\"", + userp_quoted, + digest->realm, + digest->nonce, + uripath, + digest->cnonce, + digest->nc, + digest->qop, + request_digest); + + if(Curl_raw_equal(digest->qop, "auth")) + digest->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 + padded which tells to the server how many times you are + using the same nonce in the qop=auth mode */ + } + else { + response = aprintf("username=\"%s\", " + "realm=\"%s\", " + "nonce=\"%s\", " + "uri=\"%s\", " + "response=\"%s\"", + userp_quoted, + digest->realm, + digest->nonce, + uripath, + request_digest); + } + free(userp_quoted); + if(!response) + return CURLE_OUT_OF_MEMORY; + + /* Add the optional fields */ + if(digest->opaque) { + /* Append the opaque */ + tmp = aprintf("%s, opaque=\"%s\"", response, digest->opaque); + free(response); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + response = tmp; + } + + if(digest->algorithm) { + /* Append the algorithm */ + tmp = aprintf("%s, algorithm=\"%s\"", response, digest->algorithm); + free(response); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + response = tmp; + } + + /* Return the output */ + *outptr = response; + *outlen = strlen(response); + + return CURLE_OK; +} + +/* + * Curl_auth_digest_cleanup() + * + * This is used to clean up the digest specific data. + * + * Parameters: + * + * digest [in/out] - The digest data struct being cleaned up. + * + */ +void Curl_auth_digest_cleanup(struct digestdata *digest) +{ + Curl_safefree(digest->nonce); + Curl_safefree(digest->cnonce); + Curl_safefree(digest->realm); + Curl_safefree(digest->opaque); + Curl_safefree(digest->qop); + Curl_safefree(digest->algorithm); + + digest->nc = 0; + digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */ + digest->stale = FALSE; /* default means normal, not stale */ +} +#endif /* !USE_WINDOWS_SSPI */ + +#endif /* CURL_DISABLE_CRYPTO_AUTH */ diff --git a/lib/strequal.h b/lib/vauth/digest.h similarity index 59% copy from lib/strequal.h copy to lib/vauth/digest.h index 117a305..5722dce 100644 --- a/lib/strequal.h +++ b/lib/vauth/digest.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_STREQUAL_H -#define HEADER_CURL_STREQUAL_H +#ifndef HEADER_CURL_DIGEST_H +#define HEADER_CURL_DIGEST_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -24,8 +24,20 @@ #include -#define strequal(a,b) curl_strequal(a,b) -#define strnequal(a,b,c) curl_strnequal(a,b,c) +#if !defined(CURL_DISABLE_CRYPTO_AUTH) -#endif /* HEADER_CURL_STREQUAL_H */ +#define DIGEST_MAX_VALUE_LENGTH 256 +#define DIGEST_MAX_CONTENT_LENGTH 1024 +enum { + CURLDIGESTALGO_MD5, + CURLDIGESTALGO_MD5SESS +}; + +/* This is used to extract the realm from a challenge message */ +bool Curl_auth_digest_get_pair(const char *str, char *value, char *content, + const char **endptr); + +#endif + +#endif /* HEADER_CURL_DIGEST_H */ diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c new file mode 100644 index 0000000..6a7315e --- /dev/null +++ b/lib/vauth/digest_sspi.c @@ -0,0 +1,533 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2014 - 2016, Steve Holme, . + * Copyright (C) 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * RFC2831 DIGEST-MD5 authentication + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_CRYPTO_AUTH) + +#include + +#include "vauth/vauth.h" +#include "vauth/digest.h" +#include "urldata.h" +#include "curl_base64.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" +#include "strdup.h" +#include "rawstr.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_create_digest_md5_message() + * + * This is used to generate an already encoded DIGEST-MD5 response message + * ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg64 [in] - The base64 encoded challenge message. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, + const char *chlg64, + const char *userp, + const char *passwdp, + const char *service, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + TCHAR *spn = NULL; + size_t chlglen = 0; + size_t token_max = 0; + unsigned char *input_token = NULL; + unsigned char *output_token = NULL; + CredHandle credentials; + CtxtHandle context; + PSecPkgInfo SecurityPackage; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + SecBuffer chlg_buf; + SecBuffer resp_buf; + SecBufferDesc chlg_desc; + SecBufferDesc resp_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + /* Decode the base-64 encoded challenge message */ + if(strlen(chlg64) && *chlg64 != '=') { + result = Curl_base64_decode(chlg64, &input_token, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!input_token) { + infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Query the security package for DigestSSP */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), + &SecurityPackage); + if(status != SEC_E_OK) { + free(input_token); + + return CURLE_NOT_BUILT_IN; + } + + token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our response buffer */ + output_token = malloc(token_max); + if(!output_token) { + free(input_token); + + return CURLE_OUT_OF_MEMORY; + } + + /* Generate our SPN */ + spn = Curl_auth_build_spn(service, data->easy_conn->host.name, NULL); + if(!spn) { + free(output_token); + free(input_token); + + return CURLE_OUT_OF_MEMORY; + } + + if(userp && *userp) { + /* Populate our identity structure */ + result = Curl_create_sspi_identity(userp, passwdp, &identity); + if(result) { + free(spn); + free(output_token); + free(input_token); + + return result; + } + + /* Allow proper cleanup of the identity structure */ + p_identity = &identity; + } + else + /* Use the current Windows user */ + p_identity = NULL; + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_DIGEST), + SECPKG_CRED_OUTBOUND, NULL, + p_identity, NULL, NULL, + &credentials, &expiry); + + if(status != SEC_E_OK) { + Curl_sspi_free_identity(p_identity); + free(spn); + free(output_token); + free(input_token); + + return CURLE_LOGIN_DENIED; + } + + /* Setup the challenge "input" security buffer */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 1; + chlg_desc.pBuffers = &chlg_buf; + chlg_buf.BufferType = SECBUFFER_TOKEN; + chlg_buf.pvBuffer = input_token; + chlg_buf.cbBuffer = curlx_uztoul(chlglen); + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = output_token; + resp_buf.cbBuffer = curlx_uztoul(token_max); + + /* Generate our response message */ + status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, + 0, 0, 0, &chlg_desc, 0, + &context, &resp_desc, &attrs, + &expiry); + + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { + s_pSecFn->FreeCredentialsHandle(&credentials); + Curl_sspi_free_identity(p_identity); + free(spn); + free(output_token); + free(input_token); + + return CURLE_RECV_ERROR; + } + + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer, + outptr, outlen); + + /* Free our handles */ + s_pSecFn->DeleteSecurityContext(&context); + s_pSecFn->FreeCredentialsHandle(&credentials); + + /* Free the identity structure */ + Curl_sspi_free_identity(p_identity); + + /* Free the SPN */ + free(spn); + + /* Free the response buffer */ + free(output_token); + + /* Free the decoded challenge message */ + free(input_token); + + return result; +} + +/* + * Curl_override_sspi_http_realm() + * + * This is used to populate the domain in a SSPI identity structure + * The realm is extracted from the challenge message and used as the + * domain if it is not already explicitly set. + * + * Parameters: + * + * chlg [in] - The challenge message. + * identity [in/out] - The identity structure. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_override_sspi_http_realm(const char *chlg, + SEC_WINNT_AUTH_IDENTITY *identity) +{ + xcharp_u domain, dup_domain; + + /* If domain is blank or unset, check challenge message for realm */ + if(!identity->Domain || !identity->DomainLength) { + for(;;) { + char value[DIGEST_MAX_VALUE_LENGTH]; + char content[DIGEST_MAX_CONTENT_LENGTH]; + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Extract a value=content pair */ + if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { + if(Curl_raw_equal(value, "realm")) { + + /* Setup identity's domain and length */ + domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *) content); + if(!domain.tchar_ptr) + return CURLE_OUT_OF_MEMORY; + + dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr); + if(!dup_domain.tchar_ptr) { + Curl_unicodefree(domain.tchar_ptr); + return CURLE_OUT_OF_MEMORY; + } + + free(identity->Domain); + identity->Domain = dup_domain.tbyte_ptr; + identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr)); + dup_domain.tchar_ptr = NULL; + + Curl_unicodefree(domain.tchar_ptr); + } + else { + /* Unknown specifier, ignore it! */ + } + } + else + break; /* We're done here */ + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Allow the list to be comma-separated */ + if(',' == *chlg) + chlg++; + } + } + + return CURLE_OK; +} + +/* + * Curl_auth_decode_digest_http_message() + * + * This is used to decode a HTTP DIGEST challenge message into the seperate + * attributes. + * + * Parameters: + * + * chlg [in] - The challenge message. + * digest [in/out] - The digest data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_digest_http_message(const char *chlg, + struct digestdata *digest) +{ + size_t chlglen = strlen(chlg); + + /* We had an input token before and we got another one now. This means we + provided bad credentials in the previous request. */ + if(digest->input_token) + return CURLE_BAD_CONTENT_ENCODING; + + /* Simply store the challenge for use later */ + digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen); + if(!digest->input_token) + return CURLE_OUT_OF_MEMORY; + + digest->input_token_len = chlglen; + + return CURLE_OK; +} + +/* + * Curl_auth_create_digest_http_message() + * + * This is used to generate a HTTP DIGEST response message ready for sending + * to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * request [in] - The HTTP request. + * uripath [in] - The path of the HTTP uri. + * digest [in/out] - The digest data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uripath, + struct digestdata *digest, + char **outptr, size_t *outlen) +{ + size_t token_max; + CredHandle credentials; + CtxtHandle context; + char *resp; + BYTE *output_token; + PSecPkgInfo SecurityPackage; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + SecBuffer chlg_buf[3]; + SecBuffer resp_buf; + SecBufferDesc chlg_desc; + SecBufferDesc resp_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + TCHAR *spn; + + (void) data; + + /* Query the security package for DigestSSP */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), + &SecurityPackage); + if(status != SEC_E_OK) + return CURLE_NOT_BUILT_IN; + + token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + if(userp && *userp) { + /* Populate our identity structure */ + if(Curl_create_sspi_identity(userp, passwdp, &identity)) + return CURLE_OUT_OF_MEMORY; + + /* Populate our identity domain */ + if(Curl_override_sspi_http_realm((const char*) digest->input_token, + &identity)) + return CURLE_OUT_OF_MEMORY; + + /* Allow proper cleanup of the identity structure */ + p_identity = &identity; + } + else + /* Use the current Windows user */ + p_identity = NULL; + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_DIGEST), + SECPKG_CRED_OUTBOUND, NULL, + p_identity, NULL, NULL, + &credentials, &expiry); + if(status != SEC_E_OK) { + Curl_sspi_free_identity(p_identity); + + return CURLE_LOGIN_DENIED; + } + + /* Allocate the output buffer according to the max token size as indicated + by the security package */ + output_token = malloc(token_max); + if(!output_token) { + s_pSecFn->FreeCredentialsHandle(&credentials); + + Curl_sspi_free_identity(p_identity); + + return CURLE_OUT_OF_MEMORY; + } + + /* Setup the challenge "input" security buffer if present */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 3; + chlg_desc.pBuffers = chlg_buf; + chlg_buf[0].BufferType = SECBUFFER_TOKEN; + chlg_buf[0].pvBuffer = digest->input_token; + chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len); + chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[1].pvBuffer = (void *) request; + chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); + chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[2].pvBuffer = NULL; + chlg_buf[2].cbBuffer = 0; + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = output_token; + resp_buf.cbBuffer = curlx_uztoul(token_max); + + spn = Curl_convert_UTF8_to_tchar((char *) uripath); + if(!spn) { + s_pSecFn->FreeCredentialsHandle(&credentials); + + Curl_sspi_free_identity(p_identity); + free(output_token); + + return CURLE_OUT_OF_MEMORY; + } + + /* Generate our reponse message */ + status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, + spn, + ISC_REQ_USE_HTTP_STYLE, 0, 0, + &chlg_desc, 0, &context, + &resp_desc, &attrs, &expiry); + Curl_unicodefree(spn); + + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { + s_pSecFn->FreeCredentialsHandle(&credentials); + + Curl_sspi_free_identity(p_identity); + free(output_token); + + return CURLE_OUT_OF_MEMORY; + } + + resp = malloc(resp_buf.cbBuffer + 1); + if(!resp) { + s_pSecFn->DeleteSecurityContext(&context); + s_pSecFn->FreeCredentialsHandle(&credentials); + + Curl_sspi_free_identity(p_identity); + free(output_token); + + return CURLE_OUT_OF_MEMORY; + } + + /* Copy the generated reponse */ + memcpy(resp, resp_buf.pvBuffer, resp_buf.cbBuffer); + resp[resp_buf.cbBuffer] = 0x00; + + /* Return the response */ + *outptr = resp; + *outlen = resp_buf.cbBuffer; + + /* Free our handles */ + s_pSecFn->DeleteSecurityContext(&context); + s_pSecFn->FreeCredentialsHandle(&credentials); + + /* Free the identity structure */ + Curl_sspi_free_identity(p_identity); + + /* Free the response buffer */ + free(output_token); + + return CURLE_OK; +} + +/* + * Curl_auth_digest_cleanup() + * + * This is used to clean up the digest specific data. + * + * Parameters: + * + * digest [in/out] - The digest data struct being cleaned up. + * + */ +void Curl_auth_digest_cleanup(struct digestdata *digest) +{ + /* Free the input token */ + Curl_safefree(digest->input_token); + + /* Reset any variables */ + digest->input_token_len = 0; +} + +#endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_CRYPTO_AUTH */ diff --git a/lib/curl_sasl_gssapi.c b/lib/vauth/krb5_gssapi.c similarity index 66% rename from lib/curl_sasl_gssapi.c rename to lib/vauth/krb5_gssapi.c index 3c6f3ce..31c8c7d 100644 --- a/lib/curl_sasl_gssapi.c +++ b/lib/vauth/krb5_gssapi.c @@ -5,12 +5,12 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2014 - 2015, Steve Holme, . + * Copyright (C) 2014 - 2016, Steve Holme, . * Copyright (C) 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -29,6 +29,7 @@ #include +#include "vauth/vauth.h" #include "curl_sasl.h" #include "urldata.h" #include "curl_base64.h" @@ -41,25 +42,7 @@ #include "memdebug.h" /* -* Curl_sasl_build_gssapi_spn() -* -* This is used to build a SPN string in the format service at host. -* -* Parameters: -* -* serivce [in] - The service type such as www, smtp, pop or imap. -* host [in] - The host name or realm. -* -* Returns a pointer to the newly allocated SPN. -*/ -char *Curl_sasl_build_gssapi_spn(const char *service, const char *host) -{ - /* Generate and return our SPN */ - return aprintf("%s@%s", service, host); -} - -/* - * Curl_sasl_create_gssapi_user_message() + * Curl_auth_create_gssapi_user_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) user token * message ready for sending to the recipient. @@ -69,22 +52,24 @@ char *Curl_sasl_build_gssapi_spn(const char *service, const char *host) * data [in] - The session handle. * userp [in] - The user name. * passdwp [in] - The user's password. - * service [in] - The service type such as www, smtp, pop or imap. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in[ - The host name. * mutual_auth [in] - Flag specifing whether or not mutual authentication * is enabled. * chlg64 [in] - Pointer to the optional base64 encoded challenge * message. - * krb5 [in/out] - The gssapi data struct being used and modified. + * krb5 [in/out] - The Kerberos 5 data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, +CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, const char *userp, const char *passwdp, const char *service, + const char *host, const bool mutual_auth, const char *chlg64, struct kerberos5data *krb5, @@ -93,9 +78,9 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, CURLcode result = CURLE_OK; size_t chlglen = 0; unsigned char *chlg = NULL; - OM_uint32 gss_status; - OM_uint32 gss_major_status; - OM_uint32 gss_minor_status; + OM_uint32 major_status; + OM_uint32 minor_status; + OM_uint32 unused_status; gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; @@ -103,10 +88,9 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, (void) userp; (void) passwdp; - if(krb5->context == GSS_C_NO_CONTEXT) { + if(!krb5->spn) { /* Generate our SPN */ - char *spn = Curl_sasl_build_gssapi_spn(service, - data->easy_conn->host.name); + char *spn = Curl_auth_build_spn(service, NULL, host); if(!spn) return CURLE_OUT_OF_MEMORY; @@ -115,10 +99,11 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, spn_token.length = strlen(spn); /* Import the SPN */ - gss_major_status = gss_import_name(&gss_minor_status, &spn_token, - GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn); - if(GSS_ERROR(gss_major_status)) { - Curl_gss_log_error(data, gss_minor_status, "gss_import_name() failed: "); + major_status = gss_import_name(&minor_status, &spn_token, + GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_import_name() failed: ", + major_status, minor_status); free(spn); @@ -127,9 +112,10 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, free(spn); } - else { + + if(chlg64 && *chlg64) { /* Decode the base-64 encoded challenge message */ - if(strlen(chlg64) && *chlg64 != '=') { + if(*chlg64 != '=') { result = Curl_base64_decode(chlg64, &chlg, &chlglen); if(result) return result; @@ -147,25 +133,26 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, input_token.length = chlglen; } - gss_major_status = Curl_gss_init_sec_context(data, - &gss_minor_status, - &krb5->context, - krb5->spn, - &Curl_krb5_mech_oid, - GSS_C_NO_CHANNEL_BINDINGS, - &input_token, - &output_token, - mutual_auth, - NULL); - + major_status = Curl_gss_init_sec_context(data, + &minor_status, + &krb5->context, + krb5->spn, + &Curl_krb5_mech_oid, + GSS_C_NO_CHANNEL_BINDINGS, + &input_token, + &output_token, + mutual_auth, + NULL); + + /* Free the decoded challenge as it is not required anymore */ free(input_token.value); - if(GSS_ERROR(gss_major_status)) { + if(GSS_ERROR(major_status)) { if(output_token.value) - gss_release_buffer(&gss_status, &output_token); + gss_release_buffer(&unused_status, &output_token); - Curl_gss_log_error(data, gss_minor_status, - "gss_init_sec_context() failed: "); + Curl_gss_log_error(data, "gss_init_sec_context() failed: ", + major_status, minor_status); return CURLE_RECV_ERROR; } @@ -175,14 +162,19 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, result = Curl_base64_encode(data, (char *) output_token.value, output_token.length, outptr, outlen); - gss_release_buffer(&gss_status, &output_token); + gss_release_buffer(&unused_status, &output_token); + } + else if(mutual_auth) { + *outptr = strdup(""); + if(!*outptr) + result = CURLE_OUT_OF_MEMORY; } return result; } /* - * Curl_sasl_create_gssapi_security_message() + * Curl_auth_create_gssapi_security_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) security * token message ready for sending to the recipient. @@ -191,14 +183,14 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, * * data [in] - The session handle. * chlg64 [in] - Pointer to the optional base64 encoded challenge message. - * krb5 [in/out] - The gssapi data struct being used and modified. + * krb5 [in/out] - The Kerberos 5 data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, +CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, const char *chlg64, struct kerberos5data *krb5, char **outptr, @@ -209,9 +201,9 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, size_t messagelen = 0; unsigned char *chlg = NULL; unsigned char *message = NULL; - OM_uint32 gss_status; - OM_uint32 gss_major_status; - OM_uint32 gss_minor_status; + OM_uint32 major_status; + OM_uint32 minor_status; + OM_uint32 unused_status; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; unsigned int indata = 0; @@ -237,12 +229,12 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, } /* Get the fully qualified username back from the context */ - gss_major_status = gss_inquire_context(&gss_minor_status, krb5->context, - &username, NULL, NULL, NULL, NULL, - NULL, NULL); - if(GSS_ERROR(gss_major_status)) { - Curl_gss_log_error(data, gss_minor_status, - "gss_inquire_context() failed: "); + major_status = gss_inquire_context(&minor_status, krb5->context, + &username, NULL, NULL, NULL, NULL, + NULL, NULL); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_inquire_context() failed: ", + major_status, minor_status); free(chlg); @@ -250,10 +242,11 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, } /* Convert the username from internal format to a displayable token */ - gss_major_status = gss_display_name(&gss_minor_status, username, - &username_token, NULL); - if(GSS_ERROR(gss_major_status)) { - Curl_gss_log_error(data, gss_minor_status, "gss_display_name() failed: "); + major_status = gss_display_name(&minor_status, username, + &username_token, NULL); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_display_name() failed: ", + major_status, minor_status); free(chlg); @@ -265,12 +258,13 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, input_token.length = chlglen; /* Decrypt the inbound challenge and obtain the qop */ - gss_major_status = gss_unwrap(&gss_minor_status, krb5->context, &input_token, - &output_token, NULL, &qop); - if(GSS_ERROR(gss_major_status)) { - Curl_gss_log_error(data, gss_minor_status, "gss_unwrap() failed: "); + major_status = gss_unwrap(&minor_status, krb5->context, &input_token, + &output_token, NULL, &qop); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_unwrap() failed: ", + major_status, minor_status); - gss_release_buffer(&gss_status, &username_token); + gss_release_buffer(&unused_status, &username_token); free(chlg); return CURLE_BAD_CONTENT_ENCODING; @@ -280,7 +274,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, if(output_token.length != 4) { infof(data, "GSSAPI handshake failure (invalid security data)\n"); - gss_release_buffer(&gss_status, &username_token); + gss_release_buffer(&unused_status, &username_token); free(chlg); return CURLE_BAD_CONTENT_ENCODING; @@ -288,7 +282,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, /* Copy the data out and free the challenge as it is not required anymore */ memcpy(&indata, output_token.value, 4); - gss_release_buffer(&gss_status, &output_token); + gss_release_buffer(&unused_status, &output_token); free(chlg); /* Extract the security layer */ @@ -296,7 +290,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, if(!(sec_layer & GSSAUTH_P_NONE)) { infof(data, "GSSAPI handshake failure (invalid security layer)\n"); - gss_release_buffer(&gss_status, &username_token); + gss_release_buffer(&unused_status, &username_token); return CURLE_BAD_CONTENT_ENCODING; } @@ -314,14 +308,14 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, messagelen = sizeof(outdata) + username_token.length + 1; message = malloc(messagelen); if(!message) { - gss_release_buffer(&gss_status, &username_token); + gss_release_buffer(&unused_status, &username_token); return CURLE_OUT_OF_MEMORY; } /* Populate the message with the security layer, client supported receive message size and authorization identity including the 0x00 based - terminator. Note: Dispite RFC4752 Section 3.1 stating "The authorization + terminator. Note: Despite RFC4752 Section 3.1 stating "The authorization identity is not terminated with the zero-valued (%x00) octet." it seems necessary to include it. */ outdata = htonl(max_size) | sec_layer; @@ -331,18 +325,19 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, message[messagelen - 1] = '\0'; /* Free the username token as it is not required anymore */ - gss_release_buffer(&gss_status, &username_token); + gss_release_buffer(&unused_status, &username_token); /* Setup the "authentication data" security buffer */ input_token.value = message; input_token.length = messagelen; /* Encrypt the data */ - gss_major_status = gss_wrap(&gss_minor_status, krb5->context, 0, - GSS_C_QOP_DEFAULT, &input_token, NULL, - &output_token); - if(GSS_ERROR(gss_major_status)) { - Curl_gss_log_error(data, gss_minor_status, "gss_wrap() failed: "); + major_status = gss_wrap(&minor_status, krb5->context, 0, + GSS_C_QOP_DEFAULT, &input_token, NULL, + &output_token); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_wrap() failed: ", + major_status, minor_status); free(message); @@ -354,7 +349,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, output_token.length, outptr, outlen); /* Free the output buffer */ - gss_release_buffer(&gss_status, &output_token); + gss_release_buffer(&unused_status, &output_token); /* Free the message buffer */ free(message); @@ -363,16 +358,16 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, } /* - * Curl_sasl_gssapi_cleanup() + * Curl_auth_gssapi_cleanup() * - * This is used to clean up the gssapi specific data. + * This is used to clean up the GSSAPI (Kerberos V5) specific data. * * Parameters: * - * krb5 [in/out] - The kerberos 5 data struct being cleaned up. + * krb5 [in/out] - The Kerberos 5 data struct being cleaned up. * */ -void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5) +void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5) { OM_uint32 minor_status; diff --git a/lib/vauth/krb5_sspi.c b/lib/vauth/krb5_sspi.c new file mode 100644 index 0000000..08774f6 --- /dev/null +++ b/lib/vauth/krb5_sspi.c @@ -0,0 +1,496 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2014 - 2016, Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_WINDOWS_SSPI) && defined(USE_KERBEROS5) + +#include + +#include "vauth/vauth.h" +#include "urldata.h" +#include "curl_base64.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_create_gssapi_user_message() + * + * This is used to generate an already encoded GSSAPI (Kerberos V5) user token + * message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. + * mutual_auth [in] - Flag specifing whether or not mutual authentication + * is enabled. + * chlg64 [in] - The optional base64 encoded challenge message. + * krb5 [in/out] - The Kerberos 5 data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + const char *service, + const char *host, + const bool mutual_auth, + const char *chlg64, + struct kerberos5data *krb5, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + unsigned char *chlg = NULL; + CtxtHandle context; + PSecPkgInfo SecurityPackage; + SecBuffer chlg_buf; + SecBuffer resp_buf; + SecBufferDesc chlg_desc; + SecBufferDesc resp_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + if(!krb5->spn) { + /* Generate our SPN */ + krb5->spn = Curl_auth_build_spn(service, host, NULL); + if(!krb5->spn) + return CURLE_OUT_OF_MEMORY; + } + + if(!krb5->output_token) { + /* Query the security package for Kerberos */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_KERBEROS), + &SecurityPackage); + if(status != SEC_E_OK) { + return CURLE_NOT_BUILT_IN; + } + + krb5->token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our response buffer */ + krb5->output_token = malloc(krb5->token_max); + if(!krb5->output_token) + return CURLE_OUT_OF_MEMORY; + } + + if(!krb5->credentials) { + /* Do we have credientials to use or are we using single sign-on? */ + if(userp && *userp) { + /* Populate our identity structure */ + result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity); + if(result) + return result; + + /* Allow proper cleanup of the identity structure */ + krb5->p_identity = &krb5->identity; + } + else + /* Use the current Windows user */ + krb5->p_identity = NULL; + + /* Allocate our credentials handle */ + krb5->credentials = malloc(sizeof(CredHandle)); + if(!krb5->credentials) + return CURLE_OUT_OF_MEMORY; + + memset(krb5->credentials, 0, sizeof(CredHandle)); + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) + TEXT(SP_NAME_KERBEROS), + SECPKG_CRED_OUTBOUND, NULL, + krb5->p_identity, NULL, NULL, + krb5->credentials, &expiry); + if(status != SEC_E_OK) + return CURLE_LOGIN_DENIED; + + /* Allocate our new context handle */ + krb5->context = malloc(sizeof(CtxtHandle)); + if(!krb5->context) + return CURLE_OUT_OF_MEMORY; + + memset(krb5->context, 0, sizeof(CtxtHandle)); + } + + if(chlg64 && *chlg64) { + /* Decode the base-64 encoded challenge message */ + if(*chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "GSSAPI handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Setup the challenge "input" security buffer */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 1; + chlg_desc.pBuffers = &chlg_buf; + chlg_buf.BufferType = SECBUFFER_TOKEN; + chlg_buf.pvBuffer = chlg; + chlg_buf.cbBuffer = curlx_uztoul(chlglen); + } + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = krb5->output_token; + resp_buf.cbBuffer = curlx_uztoul(krb5->token_max); + + /* Generate our challenge-response message */ + status = s_pSecFn->InitializeSecurityContext(krb5->credentials, + chlg ? krb5->context : NULL, + krb5->spn, + (mutual_auth ? + ISC_REQ_MUTUAL_AUTH : 0), + 0, SECURITY_NATIVE_DREP, + chlg ? &chlg_desc : NULL, 0, + &context, + &resp_desc, &attrs, + &expiry); + + /* Free the decoded challenge as it is not required anymore */ + free(chlg); + + if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { + return CURLE_RECV_ERROR; + } + + if(memcmp(&context, krb5->context, sizeof(context))) { + s_pSecFn->DeleteSecurityContext(krb5->context); + + memcpy(krb5->context, &context, sizeof(context)); + } + + if(resp_buf.cbBuffer) { + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) resp_buf.pvBuffer, + resp_buf.cbBuffer, outptr, outlen); + } + else if(mutual_auth) { + *outptr = strdup(""); + if(!*outptr) + result = CURLE_OUT_OF_MEMORY; + } + + return result; +} + +/* + * Curl_auth_create_gssapi_security_message() + * + * This is used to generate an already encoded GSSAPI (Kerberos V5) security + * token message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg64 [in] - The optional base64 encoded challenge message. + * krb5 [in/out] - The Kerberos 5 data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, + const char *chlg64, + struct kerberos5data *krb5, + char **outptr, + size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t offset = 0; + size_t chlglen = 0; + size_t messagelen = 0; + size_t appdatalen = 0; + unsigned char *chlg = NULL; + unsigned char *trailer = NULL; + unsigned char *message = NULL; + unsigned char *padding = NULL; + unsigned char *appdata = NULL; + SecBuffer input_buf[2]; + SecBuffer wrap_buf[3]; + SecBufferDesc input_desc; + SecBufferDesc wrap_desc; + unsigned long indata = 0; + unsigned long outdata = 0; + unsigned long qop = 0; + unsigned long sec_layer = 0; + unsigned long max_size = 0; + SecPkgContext_Sizes sizes; + SecPkgCredentials_Names names; + SECURITY_STATUS status; + char *user_name; + + /* Decode the base-64 encoded input message */ + if(strlen(chlg64) && *chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "GSSAPI handshake failure (empty security message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Get our response size information */ + status = s_pSecFn->QueryContextAttributes(krb5->context, + SECPKG_ATTR_SIZES, + &sizes); + if(status != SEC_E_OK) { + free(chlg); + + return CURLE_OUT_OF_MEMORY; + } + + /* Get the fully qualified username back from the context */ + status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials, + SECPKG_CRED_ATTR_NAMES, + &names); + if(status != SEC_E_OK) { + free(chlg); + + return CURLE_RECV_ERROR; + } + + /* Setup the "input" security buffer */ + input_desc.ulVersion = SECBUFFER_VERSION; + input_desc.cBuffers = 2; + input_desc.pBuffers = input_buf; + input_buf[0].BufferType = SECBUFFER_STREAM; + input_buf[0].pvBuffer = chlg; + input_buf[0].cbBuffer = curlx_uztoul(chlglen); + input_buf[1].BufferType = SECBUFFER_DATA; + input_buf[1].pvBuffer = NULL; + input_buf[1].cbBuffer = 0; + + /* Decrypt the inbound challenge and obtain the qop */ + status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop); + if(status != SEC_E_OK) { + infof(data, "GSSAPI handshake failure (empty security message)\n"); + + free(chlg); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ + if(input_buf[1].cbBuffer != 4) { + infof(data, "GSSAPI handshake failure (invalid security data)\n"); + + free(chlg); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Copy the data out and free the challenge as it is not required anymore */ + memcpy(&indata, input_buf[1].pvBuffer, 4); + s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer); + free(chlg); + + /* Extract the security layer */ + sec_layer = indata & 0x000000FF; + if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) { + infof(data, "GSSAPI handshake failure (invalid security layer)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Extract the maximum message size the server can receive */ + max_size = ntohl(indata & 0xFFFFFF00); + if(max_size > 0) { + /* The server has told us it supports a maximum receive buffer, however, as + we don't require one unless we are encrypting data, we tell the server + our receive buffer is zero. */ + max_size = 0; + } + + /* Allocate the trailer */ + trailer = malloc(sizes.cbSecurityTrailer); + if(!trailer) + return CURLE_OUT_OF_MEMORY; + + /* Convert the user name to UTF8 when operating with Unicode */ + user_name = Curl_convert_tchar_to_UTF8(names.sUserName); + if(!user_name) { + free(trailer); + + return CURLE_OUT_OF_MEMORY; + } + + /* Allocate our message */ + messagelen = sizeof(outdata) + strlen(user_name) + 1; + message = malloc(messagelen); + if(!message) { + free(trailer); + Curl_unicodefree(user_name); + + return CURLE_OUT_OF_MEMORY; + } + + /* Populate the message with the security layer, client supported receive + message size and authorization identity including the 0x00 based + terminator. Note: Despite RFC4752 Section 3.1 stating "The authorization + identity is not terminated with the zero-valued (%x00) octet." it seems + necessary to include it. */ + outdata = htonl(max_size) | sec_layer; + memcpy(message, &outdata, sizeof(outdata)); + strcpy((char *) message + sizeof(outdata), user_name); + Curl_unicodefree(user_name); + + /* Allocate the padding */ + padding = malloc(sizes.cbBlockSize); + if(!padding) { + free(message); + free(trailer); + + return CURLE_OUT_OF_MEMORY; + } + + /* Setup the "authentication data" security buffer */ + wrap_desc.ulVersion = SECBUFFER_VERSION; + wrap_desc.cBuffers = 3; + wrap_desc.pBuffers = wrap_buf; + wrap_buf[0].BufferType = SECBUFFER_TOKEN; + wrap_buf[0].pvBuffer = trailer; + wrap_buf[0].cbBuffer = sizes.cbSecurityTrailer; + wrap_buf[1].BufferType = SECBUFFER_DATA; + wrap_buf[1].pvBuffer = message; + wrap_buf[1].cbBuffer = curlx_uztoul(messagelen); + wrap_buf[2].BufferType = SECBUFFER_PADDING; + wrap_buf[2].pvBuffer = padding; + wrap_buf[2].cbBuffer = sizes.cbBlockSize; + + /* Encrypt the data */ + status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT, + &wrap_desc, 0); + if(status != SEC_E_OK) { + free(padding); + free(message); + free(trailer); + + return CURLE_OUT_OF_MEMORY; + } + + /* Allocate the encryption (wrap) buffer */ + appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer + + wrap_buf[2].cbBuffer; + appdata = malloc(appdatalen); + if(!appdata) { + free(padding); + free(message); + free(trailer); + + return CURLE_OUT_OF_MEMORY; + } + + /* Populate the encryption buffer */ + memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer); + offset += wrap_buf[0].cbBuffer; + memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer); + offset += wrap_buf[1].cbBuffer; + memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer); + + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) appdata, appdatalen, outptr, + outlen); + + /* Free all of our local buffers */ + free(appdata); + free(padding); + free(message); + free(trailer); + + return result; +} + +/* + * Curl_auth_gssapi_cleanup() + * + * This is used to clean up the GSSAPI (Kerberos V5) specific data. + * + * Parameters: + * + * krb5 [in/out] - The Kerberos 5 data struct being cleaned up. + * + */ +void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5) +{ + /* Free our security context */ + if(krb5->context) { + s_pSecFn->DeleteSecurityContext(krb5->context); + free(krb5->context); + krb5->context = NULL; + } + + /* Free our credentials handle */ + if(krb5->credentials) { + s_pSecFn->FreeCredentialsHandle(krb5->credentials); + free(krb5->credentials); + krb5->credentials = NULL; + } + + /* Free our identity */ + Curl_sspi_free_identity(krb5->p_identity); + krb5->p_identity = NULL; + + /* Free the SPN and output token */ + Curl_safefree(krb5->spn); + Curl_safefree(krb5->output_token); + + /* Reset any variables */ + krb5->token_max = 0; +} + +#endif /* USE_WINDOWS_SSPI && USE_KERBEROS5*/ diff --git a/lib/curl_ntlm_msgs.c b/lib/vauth/ntlm.c similarity index 94% rename from lib/curl_ntlm_msgs.c rename to lib/vauth/ntlm.c index 7f07dec..c85fe42 100644 --- a/lib/curl_ntlm_msgs.c +++ b/lib/vauth/ntlm.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -28,7 +28,7 @@ * NTLM details: * * http://davenport.sourceforge.net/ntlm.html - * http://www.innovation.ch/java/ntlm.html + * https://www.innovation.ch/java/ntlm.html */ #define DEBUG_ME 0 @@ -49,8 +49,8 @@ #endif #define BUILDING_CURL_NTLM_MSGS_C -#include "curl_ntlm_msgs.h" -#include "curl_sasl.h" +#include "vauth/vauth.h" +#include "vauth/ntlm.h" #include "curl_endian.h" #include "curl_printf.h" @@ -138,7 +138,9 @@ static void ntlm_print_flags(FILE *handle, unsigned long flags) static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) { const char *p = buf; - (void)handle; + + (void) handle; + fprintf(stderr, "0x"); while(len-- > 0) fprintf(stderr, "%02.2x", (unsigned int)*p++); @@ -150,7 +152,7 @@ static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) /* * ntlm_decode_type2_target() * - * This is used to decode the "target info" in the ntlm type-2 message + * This is used to decode the "target info" in the NTLM type-2 message * received. * * Parameters: @@ -158,11 +160,11 @@ static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) * data [in] - The session handle. * buffer [in] - The decoded type-2 message. * size [in] - The input buffer size, at least 32 bytes. - * ntlm [in/out] - The ntlm data struct being used and modified. + * ntlm [in/out] - The NTLM data struct being used and modified. * * Returns CURLE_OK on success. */ -static CURLcode ntlm_decode_type2_target(struct SessionHandle *data, +static CURLcode ntlm_decode_type2_target(struct Curl_easy *data, unsigned char *buffer, size_t size, struct ntlmdata *ntlm) @@ -170,6 +172,10 @@ static CURLcode ntlm_decode_type2_target(struct SessionHandle *data, unsigned short target_info_len = 0; unsigned int target_info_offset = 0; +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + if(size >= 48) { target_info_len = Curl_read16_le(&buffer[40]); target_info_offset = Curl_read32_le(&buffer[44]); @@ -211,7 +217,7 @@ static CURLcode ntlm_decode_type2_target(struct SessionHandle *data, */ /* - * Curl_sasl_decode_ntlm_type2_message() + * Curl_auth_decode_ntlm_type2_message() * * This is used to decode an already encoded NTLM type-2 message. The message * is first decoded from a base64 string into a raw NTLM message and checked @@ -222,11 +228,11 @@ static CURLcode ntlm_decode_type2_target(struct SessionHandle *data, * * data [in] - The session handle. * type2msg [in] - The base64 encoded type-2 message. - * ntlm [in/out] - The ntlm data struct being used and modified. + * ntlm [in/out] - The NTLM data struct being used and modified. * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data, +CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, const char *type2msg, struct ntlmdata *ntlm) { @@ -323,7 +329,7 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length) } /* - * Curl_sasl_create_ntlm_type1_message() + * Curl_auth_create_ntlm_type1_message() * * This is used to generate an already encoded NTLM type-1 message ready for * sending to the recipient using the appropriate compile time crypto API. @@ -332,14 +338,14 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length) * * userp [in] - The user name in the format User or Domain\User. * passdwp [in] - The user's password. - * ntlm [in/out] - The ntlm data struct being used and modified. + * ntlm [in/out] - The NTLM data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, +CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, const char *passwdp, struct ntlmdata *ntlm, char **outptr, size_t *outlen) @@ -372,7 +378,7 @@ CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, (void)passwdp; /* Clean up any former leftovers and initialise to defaults */ - Curl_sasl_ntlm_cleanup(ntlm); + Curl_auth_ntlm_cleanup(ntlm); #if USE_NTRESPONSES && USE_NTLM2SESSION #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY @@ -442,7 +448,7 @@ CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, } /* - * Curl_sasl_create_ntlm_type3_message() + * Curl_auth_create_ntlm_type3_message() * * This is used to generate an already encoded NTLM type-3 message ready for * sending to the recipient using the appropriate compile time crypto API. @@ -452,14 +458,14 @@ CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, * data [in] - The session handle. * userp [in] - The user name in the format User or Domain\User. * passdwp [in] - The user's password. - * ntlm [in/out] - The ntlm data struct being used and modified. + * ntlm [in/out] - The NTLM data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, +CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, const char *userp, const char *passwdp, struct ntlmdata *ntlm, @@ -809,9 +815,28 @@ CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, /* Return with binary blob encoded into base64 */ result = Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); - Curl_sasl_ntlm_cleanup(ntlm); + Curl_auth_ntlm_cleanup(ntlm); return result; } +/* +* Curl_auth_ntlm_cleanup() +* +* This is used to clean up the NTLM specific data. +* +* Parameters: +* +* ntlm [in/out] - The NTLM data struct being cleaned up. +* +*/ +void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm) +{ + /* Free the target info */ + Curl_safefree(ntlm->target_info); + + /* Reset any variables */ + ntlm->target_info_len = 0; +} + #endif /* USE_NTLM && !USE_WINDOWS_SSPI */ diff --git a/lib/curl_ntlm_msgs.h b/lib/vauth/ntlm.h similarity index 95% rename from lib/curl_ntlm_msgs.h rename to lib/vauth/ntlm.h index 2a71431..b14e7a5 100644 --- a/lib/curl_ntlm_msgs.h +++ b/lib/vauth/ntlm.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_NTLM_MSGS_H -#define HEADER_CURL_NTLM_MSGS_H +#ifndef HEADER_CURL_NTLM_H +#define HEADER_CURL_NTLM_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -140,4 +140,4 @@ #endif /* USE_NTLM */ -#endif /* HEADER_CURL_NTLM_MSGS_H */ +#endif /* HEADER_CURL_NTLM_H */ diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c new file mode 100644 index 0000000..982a9d3 --- /dev/null +++ b/lib/vauth/ntlm_sspi.c @@ -0,0 +1,314 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_WINDOWS_SSPI) && defined(USE_NTLM) + +#include + +#include "vauth/vauth.h" +#include "urldata.h" +#include "curl_base64.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_create_ntlm_type1_message() + * + * This is used to generate an already encoded NTLM type-1 message ready for + * sending to the recipient. + * + * Parameters: + * + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * ntlm [in/out] - The NTLM data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, size_t *outlen) +{ + PSecPkgInfo SecurityPackage; + SecBuffer type_1_buf; + SecBufferDesc type_1_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + /* Clean up any former leftovers and initialise to defaults */ + Curl_auth_ntlm_cleanup(ntlm); + + /* Query the security package for NTLM */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), + &SecurityPackage); + if(status != SEC_E_OK) + return CURLE_NOT_BUILT_IN; + + ntlm->token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our output buffer */ + ntlm->output_token = malloc(ntlm->token_max); + if(!ntlm->output_token) + return CURLE_OUT_OF_MEMORY; + + if(userp && *userp) { + CURLcode result; + + /* Populate our identity structure */ + result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity); + if(result) + return result; + + /* Allow proper cleanup of the identity structure */ + ntlm->p_identity = &ntlm->identity; + } + else + /* Use the current Windows user */ + ntlm->p_identity = NULL; + + /* Allocate our credentials handle */ + ntlm->credentials = malloc(sizeof(CredHandle)); + if(!ntlm->credentials) + return CURLE_OUT_OF_MEMORY; + + memset(ntlm->credentials, 0, sizeof(CredHandle)); + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_NTLM), + SECPKG_CRED_OUTBOUND, NULL, + ntlm->p_identity, NULL, NULL, + ntlm->credentials, &expiry); + if(status != SEC_E_OK) + return CURLE_LOGIN_DENIED; + + /* Allocate our new context handle */ + ntlm->context = malloc(sizeof(CtxtHandle)); + if(!ntlm->context) + return CURLE_OUT_OF_MEMORY; + + memset(ntlm->context, 0, sizeof(CtxtHandle)); + + /* Setup the type-1 "output" security buffer */ + type_1_desc.ulVersion = SECBUFFER_VERSION; + type_1_desc.cBuffers = 1; + type_1_desc.pBuffers = &type_1_buf; + type_1_buf.BufferType = SECBUFFER_TOKEN; + type_1_buf.pvBuffer = ntlm->output_token; + type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max); + + /* Generate our type-1 message */ + status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL, + (TCHAR *) TEXT(""), + 0, 0, SECURITY_NETWORK_DREP, + NULL, 0, + ntlm->context, &type_1_desc, + &attrs, &expiry); + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) + return CURLE_RECV_ERROR; + + /* Base64 encode the response */ + return Curl_base64_encode(NULL, (char *) ntlm->output_token, + type_1_buf.cbBuffer, outptr, outlen); +} + +/* + * Curl_auth_decode_ntlm_type2_message() + * + * This is used to decode an already encoded NTLM type-2 message. + * + * Parameters: + * + * data [in] - The session handle. + * type2msg [in] - The base64 encoded type-2 message. + * ntlm [in/out] - The NTLM data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, + const char *type2msg, + struct ntlmdata *ntlm) +{ + CURLcode result = CURLE_OK; + unsigned char *type2 = NULL; + size_t type2_len = 0; + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + + /* Decode the base-64 encoded type-2 message */ + if(strlen(type2msg) && *type2msg != '=') { + result = Curl_base64_decode(type2msg, &type2, &type2_len); + if(result) + return result; + } + + /* Ensure we have a valid type-2 message */ + if(!type2) { + infof(data, "NTLM handshake failure (empty type-2 message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Simply store the challenge for use later */ + ntlm->input_token = type2; + ntlm->input_token_len = type2_len; + + return result; +} + +/* +* Curl_auth_create_ntlm_type3_message() + * Curl_auth_create_ntlm_type3_message() + * + * This is used to generate an already encoded NTLM type-3 message ready for + * sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * ntlm [in/out] - The NTLM data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + SecBuffer type_2_buf; + SecBuffer type_3_buf; + SecBufferDesc type_2_desc; + SecBufferDesc type_3_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + (void) passwdp; + (void) userp; + + /* Setup the type-2 "input" security buffer */ + type_2_desc.ulVersion = SECBUFFER_VERSION; + type_2_desc.cBuffers = 1; + type_2_desc.pBuffers = &type_2_buf; + type_2_buf.BufferType = SECBUFFER_TOKEN; + type_2_buf.pvBuffer = ntlm->input_token; + type_2_buf.cbBuffer = curlx_uztoul(ntlm->input_token_len); + + /* Setup the type-3 "output" security buffer */ + type_3_desc.ulVersion = SECBUFFER_VERSION; + type_3_desc.cBuffers = 1; + type_3_desc.pBuffers = &type_3_buf; + type_3_buf.BufferType = SECBUFFER_TOKEN; + type_3_buf.pvBuffer = ntlm->output_token; + type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max); + + /* Generate our type-3 message */ + status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, + ntlm->context, + (TCHAR *) TEXT(""), + 0, 0, SECURITY_NETWORK_DREP, + &type_2_desc, + 0, ntlm->context, + &type_3_desc, + &attrs, &expiry); + if(status != SEC_E_OK) { + infof(data, "NTLM handshake failure (type-3 message): Status=%x\n", + status); + + return CURLE_RECV_ERROR; + } + + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) ntlm->output_token, + type_3_buf.cbBuffer, outptr, outlen); + + Curl_auth_ntlm_cleanup(ntlm); + + return result; +} + +/* + * Curl_auth_ntlm_cleanup() + * + * This is used to clean up the NTLM specific data. + * + * Parameters: + * + * ntlm [in/out] - The NTLM data struct being cleaned up. + * + */ +void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm) +{ + /* Free our security context */ + if(ntlm->context) { + s_pSecFn->DeleteSecurityContext(ntlm->context); + free(ntlm->context); + ntlm->context = NULL; + } + + /* Free our credentials handle */ + if(ntlm->credentials) { + s_pSecFn->FreeCredentialsHandle(ntlm->credentials); + free(ntlm->credentials); + ntlm->credentials = NULL; + } + + /* Free our identity */ + Curl_sspi_free_identity(ntlm->p_identity); + ntlm->p_identity = NULL; + + /* Free the input and output tokens */ + Curl_safefree(ntlm->input_token); + Curl_safefree(ntlm->output_token); + + /* Reset any variables */ + ntlm->token_max = 0; +} + +#endif /* USE_WINDOWS_SSPI && USE_NTLM */ diff --git a/lib/vauth/oauth2.c b/lib/vauth/oauth2.c new file mode 100644 index 0000000..6288f89 --- /dev/null +++ b/lib/vauth/oauth2.c @@ -0,0 +1,86 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * RFC6749 OAuth 2.0 Authorization Framework + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include +#include "urldata.h" + +#include "vauth/vauth.h" +#include "curl_base64.h" +#include "warnless.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_create_oauth_bearer_message() + * + * This is used to generate an already encoded OAuth 2.0 message ready for + * sending to the recipient. + * + * Parameters: + * + * data[in] - The session handle. + * user[in] - The user name. + * host[in] - The host name(for OAUTHBEARER). + * port[in] - The port(for OAUTHBEARER when not Port 80). + * bearer[in] - The bearer token. + * outptr[in / out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen[out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data, + const char *user, + const char *host, + const long port, + const char *bearer, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + char *oauth = NULL; + + /* Generate the message */ + if(host == NULL && (port == 0 || port == 80)) + oauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer); + else if(port == 0 || port == 80) + oauth = aprintf("user=%s\1host=%s\1auth=Bearer %s\1\1", user, host, + bearer); + else + oauth = aprintf("user=%s\1host=%s\1port=%ld\1auth=Bearer %s\1\1", user, + host, port, bearer); + if(!oauth) + return CURLE_OUT_OF_MEMORY; + + /* Base64 encode the reply */ + result = Curl_base64_encode(data, oauth, strlen(oauth), outptr, outlen); + + free(oauth); + + return result; +} diff --git a/lib/vauth/spnego_gssapi.c b/lib/vauth/spnego_gssapi.c new file mode 100644 index 0000000..b256ee6 --- /dev/null +++ b/lib/vauth/spnego_gssapi.c @@ -0,0 +1,260 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * RFC4178 Simple and Protected GSS-API Negotiation Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(HAVE_GSSAPI) && defined(USE_SPNEGO) + +#include + +#include "vauth/vauth.h" +#include "urldata.h" +#include "curl_base64.h" +#include "curl_gssapi.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_decode_spnego_message() + * + * This is used to decode an already encoded SPNEGO (Negotiate) challenge + * message. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. + * chlg64 [in] - The optional base64 encoded challenge message. + * nego [in/out] - The Negotiate data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, + const char *user, + const char *password, + const char *service, + const char *host, + const char *chlg64, + struct negotiatedata *nego) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + unsigned char *chlg = NULL; + OM_uint32 major_status; + OM_uint32 minor_status; + OM_uint32 unused_status; + gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + + (void) user; + (void) password; + + if(nego->context && nego->status == GSS_S_COMPLETE) { + /* We finished successfully our part of authentication, but server + * rejected it (since we're again here). Exit with an error since we + * can't invent anything better */ + Curl_auth_spnego_cleanup(nego); + return CURLE_LOGIN_DENIED; + } + + if(!nego->spn) { + /* Generate our SPN */ + char *spn = Curl_auth_build_spn(service, NULL, host); + if(!spn) + return CURLE_OUT_OF_MEMORY; + + /* Populate the SPN structure */ + spn_token.value = spn; + spn_token.length = strlen(spn); + + /* Import the SPN */ + major_status = gss_import_name(&minor_status, &spn_token, + GSS_C_NT_HOSTBASED_SERVICE, + &nego->spn); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_import_name() failed: ", + major_status, minor_status); + + free(spn); + + return CURLE_OUT_OF_MEMORY; + } + + free(spn); + } + + if(chlg64 && *chlg64) { + /* Decode the base-64 encoded challenge message */ + if(*chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "SPNEGO handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Setup the challenge "input" security buffer */ + input_token.value = chlg; + input_token.length = chlglen; + } + + /* Generate our challenge-response message */ + major_status = Curl_gss_init_sec_context(data, + &minor_status, + &nego->context, + nego->spn, + &Curl_spnego_mech_oid, + GSS_C_NO_CHANNEL_BINDINGS, + &input_token, + &output_token, + TRUE, + NULL); + + /* Free the decoded challenge as it is not required anymore */ + Curl_safefree(input_token.value); + + nego->status = major_status; + if(GSS_ERROR(major_status)) { + if(output_token.value) + gss_release_buffer(&unused_status, &output_token); + + Curl_gss_log_error(data, "gss_init_sec_context() failed: ", + major_status, minor_status); + + return CURLE_OUT_OF_MEMORY; + } + + if(!output_token.value || !output_token.length) { + if(output_token.value) + gss_release_buffer(&unused_status, &output_token); + + return CURLE_OUT_OF_MEMORY; + } + + nego->output_token = output_token; + + return CURLE_OK; +} + +/* + * Curl_auth_create_spnego_message() + * + * This is used to generate an already encoded SPNEGO (Negotiate) response + * message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * nego [in/out] - The Negotiate data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data, + struct negotiatedata *nego, + char **outptr, size_t *outlen) +{ + CURLcode result; + OM_uint32 minor_status; + + /* Base64 encode the already generated response */ + result = Curl_base64_encode(data, + nego->output_token.value, + nego->output_token.length, + outptr, outlen); + + if(result) { + gss_release_buffer(&minor_status, &nego->output_token); + nego->output_token.value = NULL; + nego->output_token.length = 0; + + return result; + } + + if(!*outptr || !*outlen) { + gss_release_buffer(&minor_status, &nego->output_token); + nego->output_token.value = NULL; + nego->output_token.length = 0; + + return CURLE_REMOTE_ACCESS_DENIED; + } + + return CURLE_OK; +} + +/* + * Curl_auth_spnego_cleanup() + * + * This is used to clean up the SPNEGO (Negotiate) specific data. + * + * Parameters: + * + * nego [in/out] - The Negotiate data struct being cleaned up. + * + */ +void Curl_auth_spnego_cleanup(struct negotiatedata *nego) +{ + OM_uint32 minor_status; + + /* Free our security context */ + if(nego->context != GSS_C_NO_CONTEXT) { + gss_delete_sec_context(&minor_status, &nego->context, GSS_C_NO_BUFFER); + nego->context = GSS_C_NO_CONTEXT; + } + + /* Free the output token */ + if(nego->output_token.value) { + gss_release_buffer(&minor_status, &nego->output_token); + nego->output_token.value = NULL; + nego->output_token.length = 0; + + } + + /* Free the SPN */ + if(nego->spn != GSS_C_NO_NAME) { + gss_release_name(&minor_status, &nego->spn); + nego->spn = GSS_C_NO_NAME; + } + + /* Reset any variables */ + nego->status = 0; +} + +#endif /* HAVE_GSSAPI && USE_SPNEGO */ diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c new file mode 100644 index 0000000..b6176ec --- /dev/null +++ b/lib/vauth/spnego_sspi.c @@ -0,0 +1,297 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * RFC4178 Simple and Protected GSS-API Negotiation Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_WINDOWS_SSPI) && defined(USE_SPNEGO) + +#include + +#include "vauth/vauth.h" +#include "urldata.h" +#include "curl_base64.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_decode_spnego_message() + * + * This is used to decode an already encoded SPNEGO (Negotiate) challenge + * message. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. + * chlg64 [in] - The optional base64 encoded challenge message. + * nego [in/out] - The Negotiate data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, + const char *user, + const char *password, + const char *service, + const char *host, + const char *chlg64, + struct negotiatedata *nego) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + unsigned char *chlg = NULL; + PSecPkgInfo SecurityPackage; + SecBuffer chlg_buf; + SecBuffer resp_buf; + SecBufferDesc chlg_desc; + SecBufferDesc resp_desc; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + + if(nego->context && nego->status == SEC_E_OK) { + /* We finished successfully our part of authentication, but server + * rejected it (since we're again here). Exit with an error since we + * can't invent anything better */ + Curl_auth_spnego_cleanup(nego); + return CURLE_LOGIN_DENIED; + } + + if(!nego->spn) { + /* Generate our SPN */ + nego->spn = Curl_auth_build_spn(service, host, NULL); + if(!nego->spn) + return CURLE_OUT_OF_MEMORY; + } + + if(!nego->output_token) { + /* Query the security package for Negotiate */ + nego->status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_NEGOTIATE), + &SecurityPackage); + if(nego->status != SEC_E_OK) + return CURLE_NOT_BUILT_IN; + + nego->token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our output buffer */ + nego->output_token = malloc(nego->token_max); + if(!nego->output_token) + return CURLE_OUT_OF_MEMORY; + } + + if(!nego->credentials) { + /* Do we have credientials to use or are we using single sign-on? */ + if(user && *user) { + /* Populate our identity structure */ + result = Curl_create_sspi_identity(user, password, &nego->identity); + if(result) + return result; + + /* Allow proper cleanup of the identity structure */ + nego->p_identity = &nego->identity; + } + else + /* Use the current Windows user */ + nego->p_identity = NULL; + + /* Allocate our credentials handle */ + nego->credentials = malloc(sizeof(CredHandle)); + if(!nego->credentials) + return CURLE_OUT_OF_MEMORY; + + memset(nego->credentials, 0, sizeof(CredHandle)); + + /* Acquire our credentials handle */ + nego->status = + s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *)TEXT(SP_NAME_NEGOTIATE), + SECPKG_CRED_OUTBOUND, NULL, + nego->p_identity, NULL, NULL, + nego->credentials, &expiry); + if(nego->status != SEC_E_OK) + return CURLE_LOGIN_DENIED; + + /* Allocate our new context handle */ + nego->context = malloc(sizeof(CtxtHandle)); + if(!nego->context) + return CURLE_OUT_OF_MEMORY; + + memset(nego->context, 0, sizeof(CtxtHandle)); + } + + if(chlg64 && *chlg64) { + /* Decode the base-64 encoded challenge message */ + if(*chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "SPNEGO handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Setup the challenge "input" security buffer */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 1; + chlg_desc.pBuffers = &chlg_buf; + chlg_buf.BufferType = SECBUFFER_TOKEN; + chlg_buf.pvBuffer = chlg; + chlg_buf.cbBuffer = curlx_uztoul(chlglen); + } + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = nego->output_token; + resp_buf.cbBuffer = curlx_uztoul(nego->token_max); + + /* Generate our challenge-response message */ + nego->status = s_pSecFn->InitializeSecurityContext(nego->credentials, + chlg ? nego->context : + NULL, + nego->spn, + ISC_REQ_CONFIDENTIALITY, + 0, SECURITY_NATIVE_DREP, + chlg ? &chlg_desc : NULL, + 0, nego->context, + &resp_desc, &attrs, + &expiry); + + /* Free the decoded challenge as it is not required anymore */ + free(chlg); + + if(GSS_ERROR(nego->status)) { + return CURLE_OUT_OF_MEMORY; + } + + if(nego->status == SEC_I_COMPLETE_NEEDED || + nego->status == SEC_I_COMPLETE_AND_CONTINUE) { + nego->status = s_pSecFn->CompleteAuthToken(nego->context, &resp_desc); + if(GSS_ERROR(nego->status)) { + return CURLE_RECV_ERROR; + } + } + + nego->output_token_length = resp_buf.cbBuffer; + + return result; +} + +/* + * Curl_auth_create_spnego_message() + * + * This is used to generate an already encoded SPNEGO (Negotiate) response + * message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * nego [in/out] - The Negotiate data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data, + struct negotiatedata *nego, + char **outptr, size_t *outlen) +{ + CURLcode result; + + /* Base64 encode the already generated response */ + result = Curl_base64_encode(data, + (const char*) nego->output_token, + nego->output_token_length, + outptr, outlen); + + if(result) + return result; + + if(!*outptr || !*outlen) + return CURLE_REMOTE_ACCESS_DENIED; + + return CURLE_OK; +} + +/* + * Curl_auth_spnego_cleanup() + * + * This is used to clean up the SPNEGO (Negotiate) specific data. + * + * Parameters: + * + * nego [in/out] - The Negotiate data struct being cleaned up. + * + */ +void Curl_auth_spnego_cleanup(struct negotiatedata *nego) +{ + /* Free our security context */ + if(nego->context) { + s_pSecFn->DeleteSecurityContext(nego->context); + free(nego->context); + nego->context = NULL; + } + + /* Free our credentials handle */ + if(nego->credentials) { + s_pSecFn->FreeCredentialsHandle(nego->credentials); + free(nego->credentials); + nego->credentials = NULL; + } + + /* Free our identity */ + Curl_sspi_free_identity(nego->p_identity); + nego->p_identity = NULL; + + /* Free the SPN and output token */ + Curl_safefree(nego->spn); + Curl_safefree(nego->output_token); + + /* Reset any variables */ + nego->status = 0; + nego->token_max = 0; +} + +#endif /* USE_WINDOWS_SSPI && USE_SPNEGO */ diff --git a/lib/vauth/vauth.c b/lib/vauth/vauth.c new file mode 100644 index 0000000..702e2d4 --- /dev/null +++ b/lib/vauth/vauth.c @@ -0,0 +1,106 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2014 - 2016, Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "vauth.h" +#include "curl_multibyte.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_build_spn() + * + * This is used to build a SPN string in the following formats: + * + * service/host at realm (Not currently used) + * service/host (Not used by GSS-API) + * service at realm (Not used by Windows SSPI) + * + * Parameters: + * + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. + * realm [in] - The realm. + * + * Returns a pointer to the newly allocated SPN. + */ +#if !defined(USE_WINDOWS_SSPI) +char *Curl_auth_build_spn(const char *service, const char *host, + const char *realm) +{ + char *spn = NULL; + + /* Generate our SPN */ + if(host && realm) + spn = aprintf("%s/%s@%s", service, host, realm); + else if(host) + spn = aprintf("%s/%s", service, host); + else if(realm) + spn = aprintf("%s@%s", service, realm); + + /* Return our newly allocated SPN */ + return spn; +} +#else +TCHAR *Curl_auth_build_spn(const char *service, const char *host, + const char *realm) +{ + char *utf8_spn = NULL; + TCHAR *tchar_spn = NULL; + + (void) realm; + + /* Note: We could use DsMakeSPN() or DsClientMakeSpnForTargetServer() rather + than doing this ourselves but the first is only available in Windows XP + and Windows Server 2003 and the latter is only available in Windows 2000 + but not Windows95/98/ME or Windows NT4.0 unless the Active Directory + Client Extensions are installed. As such it is far simpler for us to + formulate the SPN instead. */ + + /* Generate our UTF8 based SPN */ + utf8_spn = aprintf("%s/%s", service, host); + if(!utf8_spn) { + return NULL; + } + + /* Allocate our TCHAR based SPN */ + tchar_spn = Curl_convert_UTF8_to_tchar(utf8_spn); + if(!tchar_spn) { + free(utf8_spn); + + return NULL; + } + + /* Release the UTF8 variant when operating with Unicode */ + Curl_unicodefree(utf8_spn); + + /* Return our newly allocated SPN */ + return tchar_spn; +} +#endif /* USE_WINDOWS_SSPI */ + diff --git a/lib/vauth/vauth.h b/lib/vauth/vauth.h new file mode 100644 index 0000000..38806ee --- /dev/null +++ b/lib/vauth/vauth.h @@ -0,0 +1,189 @@ +#ifndef HEADER_CURL_VAUTH_H +#define HEADER_CURL_VAUTH_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2014 - 2016, Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include + +struct Curl_easy; + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) +struct digestdata; +#endif + +#if defined(USE_NTLM) +struct ntlmdata; +#endif + +#if defined(USE_KERBEROS5) +struct kerberos5data; +#endif + +#if (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) && defined(USE_SPNEGO) +struct negotiatedata; +#endif + +#if defined(USE_WINDOWS_SSPI) +#define GSS_ERROR(status) (status & 0x80000000) +#endif + +/* This is used to build a SPN string */ +#if !defined(USE_WINDOWS_SSPI) +char *Curl_auth_build_spn(const char *service, const char *host, + const char *realm); +#else +TCHAR *Curl_auth_build_spn(const char *service, const char *host, + const char *realm); +#endif + +/* This is used to generate a base64 encoded PLAIN cleartext message */ +CURLcode Curl_auth_create_plain_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + char **outptr, size_t *outlen); + +/* This is used to generate a base64 encoded LOGIN cleartext message */ +CURLcode Curl_auth_create_login_message(struct Curl_easy *data, + const char *valuep, char **outptr, + size_t *outlen); + +/* This is used to generate a base64 encoded EXTERNAL cleartext message */ +CURLcode Curl_auth_create_external_message(struct Curl_easy *data, + const char *user, char **outptr, + size_t *outlen); + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) +/* This is used to decode a CRAM-MD5 challenge message */ +CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr, + size_t *outlen); + +/* This is used to generate a CRAM-MD5 response message */ +CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data, + const char *chlg, + const char *userp, + const char *passwdp, + char **outptr, size_t *outlen); + +/* This is used to generate a base64 encoded DIGEST-MD5 response message */ +CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, + const char *chlg64, + const char *userp, + const char *passwdp, + const char *service, + char **outptr, size_t *outlen); + +/* This is used to decode a HTTP DIGEST challenge message */ +CURLcode Curl_auth_decode_digest_http_message(const char *chlg, + struct digestdata *digest); + +/* This is used to generate a HTTP DIGEST response message */ +CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uri, + struct digestdata *digest, + char **outptr, size_t *outlen); + +/* This is used to clean up the digest specific data */ +void Curl_auth_digest_cleanup(struct digestdata *digest); +#endif /* !CURL_DISABLE_CRYPTO_AUTH */ + +#if defined(USE_NTLM) +/* This is used to generate a base64 encoded NTLM type-1 message */ +CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, + size_t *outlen); + +/* This is used to decode a base64 encoded NTLM type-2 message */ +CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, + const char *type2msg, + struct ntlmdata *ntlm); + +/* This is used to generate a base64 encoded NTLM type-3 message */ +CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, size_t *outlen); + +/* This is used to clean up the NTLM specific data */ +void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm); +#endif /* USE_NTLM */ + +/* This is used to generate a base64 encoded OAuth 2.0 message */ +CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data, + const char *user, + const char *host, + const long port, + const char *bearer, + char **outptr, size_t *outlen); +#if defined(USE_KERBEROS5) +/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token + message */ +CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, + const char *userp, + const char *passwdp, + const char *service, + const char *host, + const bool mutual, + const char *chlg64, + struct kerberos5data *krb5, + char **outptr, size_t *outlen); + +/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security + token message */ +CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, + const char *input, + struct kerberos5data *krb5, + char **outptr, + size_t *outlen); + +/* This is used to clean up the GSSAPI specific data */ +void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5); +#endif /* USE_KERBEROS5 */ + +#if defined(USE_SPNEGO) +/* This is used to decode a base64 encoded SPNEGO (Negotiate) challenge + message */ +CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, + const char *user, + const char *passwood, + const char *service, + const char *host, + const char *chlg64, + struct negotiatedata *nego); + +/* This is used to generate a base64 encoded SPNEGO (Negotiate) response + message */ +CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data, + struct negotiatedata *nego, + char **outptr, size_t *outlen); + +/* This is used to clean up the SPNEGO specifiec data */ +void Curl_auth_spnego_cleanup(struct negotiatedata *nego); + +#endif /* USE_SPNEGO */ + +#endif /* HEADER_CURL_VAUTH_H */ diff --git a/lib/version.c b/lib/version.c index 1727c5a..1292445 100644 --- a/lib/version.c +++ b/lib/version.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -40,6 +40,10 @@ #include #endif +#ifdef USE_LIBPSL +#include +#endif + #if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) #include #endif @@ -60,13 +64,27 @@ #define CURL_LIBSSH2_VERSION LIBSSH2_VERSION #endif +void Curl_version_init(void); + +/* For thread safety purposes this function is called by global_init so that + the static data in both version functions is initialized. */ +void Curl_version_init(void) +{ + curl_version(); + curl_version_info(CURLVERSION_NOW); +} + char *curl_version(void) { + static bool initialized; static char version[200]; char *ptr = version; size_t len; size_t left = sizeof(version); + if(initialized) + return version; + strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION); len = strlen(ptr); left -= len; @@ -100,6 +118,11 @@ char *curl_version(void) ptr += len; } #endif +#ifdef USE_LIBPSL + len = snprintf(ptr, left, " libpsl/%s", psl_get_version()); + left -= len; + ptr += len; +#endif #ifdef USE_WIN32_IDN len = snprintf(ptr, left, " WinIDN"); left -= len; @@ -151,6 +174,7 @@ char *curl_version(void) } #endif + initialized = true; return version; } @@ -297,6 +321,9 @@ static curl_version_info_data version_info = { #if defined(USE_UNIX_SOCKETS) | CURL_VERSION_UNIX_SOCKETS #endif +#if defined(USE_LIBPSL) + | CURL_VERSION_PSL +#endif , NULL, /* ssl_version */ 0, /* ssl_version_num, this is kept at zero */ @@ -311,12 +338,18 @@ static curl_version_info_data version_info = { curl_version_info_data *curl_version_info(CURLversion stamp) { + static bool initialized; #ifdef USE_LIBSSH2 static char ssh_buffer[80]; #endif - #ifdef USE_SSL static char ssl_buffer[80]; +#endif + + if(initialized) + return &version_info; + +#ifdef USE_SSL Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer)); version_info.ssl_version = ssl_buffer; #endif @@ -358,5 +391,6 @@ curl_version_info_data *curl_version_info(CURLversion stamp) (void)stamp; /* avoid compiler warnings, we don't use this */ + initialized = true; return &version_info; } diff --git a/lib/vtls/axtls.c b/lib/vtls/axtls.c index 1038432..b6c69ad 100644 --- a/lib/vtls/axtls.c +++ b/lib/vtls/axtls.c @@ -6,11 +6,11 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010, DirecTV, Contact: Eric Hu, . - * Copyright (C) 2010 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2010 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -137,14 +137,12 @@ static void free_ssl_structs(struct ssl_connect_data *connssl) */ static CURLcode connect_prep(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; SSL_CTX *ssl_ctx; SSL *ssl = NULL; int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0}; int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0}; int i, ssl_fcn_return; - const uint8_t *ssl_sessionid; - size_t ssl_idsize; /* Assuming users will not compile in custom key/cert to axTLS. * Also, even for blocking connects, use axTLS non-blocking feature. @@ -258,14 +256,22 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) * 2) setting up callbacks. these seem gnutls specific */ - /* In axTLS, handshaking happens inside ssl_client_new. */ - if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)) { - /* we got a session id, use it! */ - infof (data, "SSL re-using session ID\n"); - ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], - ssl_sessionid, (uint8_t)ssl_idsize); + if(conn->ssl_config.sessionid) { + const uint8_t *ssl_sessionid; + size_t ssl_idsize; + + /* In axTLS, handshaking happens inside ssl_client_new. */ + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)) { + /* we got a session id, use it! */ + infof (data, "SSL re-using session ID\n"); + ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], + ssl_sessionid, (uint8_t)ssl_idsize); + } + Curl_ssl_sessionid_unlock(conn); } - else + + if(!ssl) ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0); conn->ssl[sockindex].ssl = ssl; @@ -278,10 +284,8 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) */ static CURLcode connect_finish(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; SSL *ssl = conn->ssl[sockindex].ssl; - const uint8_t *ssl_sessionid; - size_t ssl_idsize; const char *peer_CN; uint32_t dns_altname_index; const char *dns_altname; @@ -379,11 +383,15 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex) conn->send[sockindex] = axtls_send; /* Put our freshly minted SSL session in cache */ - ssl_idsize = ssl_get_session_id_size(ssl); - ssl_sessionid = ssl_get_session_id(ssl); - if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize) - != CURLE_OK) - infof (data, "failed to add session to cache\n"); + if(conn->ssl_config.sessionid) { + const uint8_t *ssl_sessionid = ssl_get_session_id_size(ssl); + size_t ssl_idsize = ssl_get_session_id(ssl); + Curl_ssl_sessionid_lock(conn); + if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize) + != CURLE_OK) + infof (data, "failed to add session to cache\n"); + Curl_ssl_sessionid_unlock(conn); + } return CURLE_OK; } @@ -464,7 +472,7 @@ Curl_axtls_connect(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode conn_step = connect_prep(conn, sockindex); int ssl_fcn_return; SSL *ssl = conn->ssl[sockindex].ssl; @@ -493,7 +501,7 @@ Curl_axtls_connect(struct connectdata *conn, return map_error_to_curl(ssl_fcn_return); } /* TODO: avoid polling */ - usleep(10000); + Curl_wait_ms(10); } infof (conn->data, "handshake completed successfully\n"); @@ -518,7 +526,7 @@ static ssize_t axtls_send(struct connectdata *conn, infof(conn->data, " axtls_send\n"); - if(rc < 0 ) { + if(rc < 0) { *err = map_error_to_curl(rc); rc = -1; /* generic error code for send failure */ } @@ -554,7 +562,7 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) */ int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; uint8_t *buf; ssize_t nread; @@ -670,7 +678,7 @@ size_t Curl_axtls_version(char *buffer, size_t size) return snprintf(buffer, size, "axTLS/%s", ssl_version()); } -int Curl_axtls_random(struct SessionHandle *data, +int Curl_axtls_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { diff --git a/lib/vtls/axtls.h b/lib/vtls/axtls.h index 223ecb8..b16d051 100644 --- a/lib/vtls/axtls.h +++ b/lib/vtls/axtls.h @@ -12,7 +12,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -42,7 +42,7 @@ void Curl_axtls_session_free(void *ptr); size_t Curl_axtls_version(char *buffer, size_t size); int Curl_axtls_shutdown(struct connectdata *conn, int sockindex); int Curl_axtls_check_cxn(struct connectdata *conn); -int Curl_axtls_random(struct SessionHandle *data, +int Curl_axtls_random(struct Curl_easy *data, unsigned char *entropy, size_t length); diff --git a/lib/vtls/cyassl.c b/lib/vtls/cyassl.c index 3ded7f1..7994b3e 100644 --- a/lib/vtls/cyassl.c +++ b/lib/vtls/cyassl.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -33,7 +33,7 @@ #define WOLFSSL_OPTIONS_IGNORE_SYS /* CyaSSL's version.h, which should contain only the version, should come before all other CyaSSL includes and be immediately followed by build config -aka options.h. http://curl.haxx.se/mail/lib-2015-04/0069.html */ +aka options.h. https://curl.haxx.se/mail/lib-2015-04/0069.html */ #include #if defined(HAVE_CYASSL_OPTIONS_H) && (LIBCYASSL_VERSION_HEX > 0x03004008) #if defined(CYASSL_API) || defined(WOLFSSL_API) @@ -51,7 +51,6 @@ and that's a problem since options.h hasn't been included yet. */ #include "urldata.h" #include "sendf.h" #include "inet_pton.h" -#include "cyassl.h" #include "vtls.h" #include "parsedate.h" #include "connect.h" /* for the connect timeout */ @@ -69,6 +68,8 @@ and that's a problem since options.h hasn't been included yet. */ #include #include +#include "cyassl.h" + /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -77,6 +78,38 @@ and that's a problem since options.h hasn't been included yet. */ #define CYASSL_MAX_ERROR_SZ 80 #endif +/* To determine what functions are available we rely on one or both of: + - the user's options.h generated by CyaSSL/wolfSSL + - the symbols detected by curl's configure + Since they are markedly different from one another, and one or the other may + not be available, we do some checking below to bring things in sync. */ + +/* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */ +#ifndef HAVE_ALPN +#ifdef HAVE_WOLFSSL_USEALPN +#define HAVE_ALPN +#endif +#endif + +/* WOLFSSL_ALLOW_SSLV3 is wolfSSL's build time symbol for enabling SSLv3 in + options.h, but is only seen in >= 3.6.6 since that's when they started + disabling SSLv3 by default. */ +#ifndef WOLFSSL_ALLOW_SSLV3 +#if (LIBCYASSL_VERSION_HEX < 0x03006006) || \ + defined(HAVE_WOLFSSLV3_CLIENT_METHOD) +#define WOLFSSL_ALLOW_SSLV3 +#endif +#endif + +/* HAVE_SUPPORTED_CURVES is wolfSSL's build time symbol for enabling the ECC + supported curve extension in options.h. Note ECC is enabled separately. */ +#ifndef HAVE_SUPPORTED_CURVES +#if defined(HAVE_CYASSL_CTX_USESUPPORTEDCURVE) || \ + defined(HAVE_WOLFSSL_CTX_USESUPPORTEDCURVE) +#define HAVE_SUPPORTED_CURVES +#endif +#endif + static Curl_recv cyassl_recv; static Curl_send cyassl_send; @@ -101,10 +134,9 @@ cyassl_connect_step1(struct connectdata *conn, int sockindex) { char error_buffer[CYASSL_MAX_ERROR_SZ]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data* conssl = &conn->ssl[sockindex]; SSL_METHOD* req_method = NULL; - void* ssl_sessionid = NULL; curl_socket_t sockfd = conn->sock[sockindex]; #ifdef HAVE_SNI bool sni = FALSE; @@ -143,8 +175,13 @@ cyassl_connect_step1(struct connectdata *conn, use_sni(TRUE); break; case CURL_SSLVERSION_SSLv3: +#ifdef WOLFSSL_ALLOW_SSLV3 req_method = SSLv3_client_method(); use_sni(FALSE); +#else + failf(data, "No support for SSLv3"); + return CURLE_NOT_BUILT_IN; +#endif break; case CURL_SSLVERSION_SSLv2: failf(data, "CyaSSL does not support SSLv2"); @@ -273,6 +310,16 @@ cyassl_connect_step1(struct connectdata *conn, } #endif +#ifdef HAVE_SUPPORTED_CURVES + /* CyaSSL/wolfSSL does not send the supported ECC curves ext automatically: + https://github.com/wolfSSL/wolfssl/issues/366 + The supported curves below are those also supported by OpenSSL 1.0.2 and + in the same order. */ + CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x17); /* secp256r1 */ + CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x19); /* secp521r1 */ + CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x18); /* secp384r1 */ +#endif + /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { CURLcode result = CURLE_OK; @@ -302,16 +349,51 @@ cyassl_connect_step1(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } - /* Check if there's a cached ID we can/should use here! */ - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { - /* we got a session id, use it! */ - if(!SSL_set_session(conssl->handle, ssl_sessionid)) { - failf(data, "SSL: SSL_set_session failed: %s", - ERR_error_string(SSL_get_error(conssl->handle, 0), error_buffer)); +#ifdef HAVE_ALPN + if(conn->bits.tls_enable_alpn) { + char protocols[128]; + *protocols = '\0'; + + /* wolfSSL's ALPN protocol name list format is a comma separated string of + protocols in descending order of preference, eg: "h2,http/1.1" */ + +#ifdef USE_NGHTTP2 + if(data->set.httpversion >= CURL_HTTP_VERSION_2) { + strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ","); + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); + } +#endif + + strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1); + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + if(wolfSSL_UseALPN(conssl->handle, protocols, + (unsigned)strlen(protocols), + WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) { + failf(data, "SSL: failed setting ALPN protocols"); return CURLE_SSL_CONNECT_ERROR; } - /* Informational message */ - infof (data, "SSL re-using session ID\n"); + } +#endif /* HAVE_ALPN */ + + /* Check if there's a cached ID we can/should use here! */ + if(conn->ssl_config.sessionid) { + void *ssl_sessionid = NULL; + + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { + /* we got a session id, use it! */ + if(!SSL_set_session(conssl->handle, ssl_sessionid)) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "SSL: SSL_set_session failed: %s", + ERR_error_string(SSL_get_error(conssl->handle, 0), + error_buffer)); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof (data, "SSL re-using session ID\n"); + } + Curl_ssl_sessionid_unlock(conn); } /* pass the raw socket into the SSL layer */ @@ -330,7 +412,7 @@ cyassl_connect_step2(struct connectdata *conn, int sockindex) { int ret = -1; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data* conssl = &conn->ssl[sockindex]; conn->recv[sockindex] = cyassl_recv; @@ -406,6 +488,7 @@ cyassl_connect_step2(struct connectdata *conn, } if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { +#ifdef KEEP_PEER_CERT X509 *x509; const char *x509_der; int x509_der_len; @@ -434,14 +517,54 @@ cyassl_connect_step2(struct connectdata *conn, return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } - result = Curl_pin_peer_pubkey(data->set.str[STRING_SSL_PINNEDPUBLICKEY], + result = Curl_pin_peer_pubkey(data, + data->set.str[STRING_SSL_PINNEDPUBLICKEY], (const unsigned char *)pubkey->header, (size_t)(pubkey->end - pubkey->header)); if(result) { failf(data, "SSL: public key does not match pinned public key!"); return result; } +#else + failf(data, "Library lacks pinning support built-in"); + return CURLE_NOT_BUILT_IN; +#endif + } + +#ifdef HAVE_ALPN + if(conn->bits.tls_enable_alpn) { + int rc; + char *protocol = NULL; + unsigned short protocol_len = 0; + + rc = wolfSSL_ALPN_GetProtocol(conssl->handle, &protocol, &protocol_len); + + if(rc == SSL_SUCCESS) { + infof(data, "ALPN, server accepted to use %.*s\n", protocol_len, + protocol); + + if(protocol_len == ALPN_HTTP_1_1_LENGTH && + !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) + conn->negnpn = CURL_HTTP_VERSION_1_1; +#ifdef USE_NGHTTP2 + else if(data->set.httpversion >= CURL_HTTP_VERSION_2 && + protocol_len == NGHTTP2_PROTO_VERSION_ID_LEN && + !memcmp(protocol, NGHTTP2_PROTO_VERSION_ID, + NGHTTP2_PROTO_VERSION_ID_LEN)) + conn->negnpn = CURL_HTTP_VERSION_2; +#endif + else + infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len, + protocol); + } + else if(rc == SSL_ALPN_NOT_FOUND) + infof(data, "ALPN, server did not agree to a protocol\n"); + else { + failf(data, "ALPN, failure getting protocol, error %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } } +#endif /* HAVE_ALPN */ conssl->connecting_state = ssl_connect_3; infof(data, "SSL connected\n"); @@ -455,32 +578,38 @@ cyassl_connect_step3(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; - void *old_ssl_sessionid=NULL; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - bool incache; - SSL_SESSION *our_ssl_sessionid; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - our_ssl_sessionid = SSL_get_session(connssl->handle); + if(conn->ssl_config.sessionid) { + bool incache; + SSL_SESSION *our_ssl_sessionid; + void *old_ssl_sessionid = NULL; + + our_ssl_sessionid = SSL_get_session(connssl->handle); - incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); - if(incache) { - if(old_ssl_sessionid != our_ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - incache = FALSE; + Curl_ssl_sessionid_lock(conn); + incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); + if(incache) { + if(old_ssl_sessionid != our_ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing\n"); + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + incache = FALSE; + } } - } - if(!incache) { - result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */); - if(result) { - failf(data, "failed to store ssl session"); - return result; + if(!incache) { + result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, + 0 /* unknown size */); + if(result) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "failed to store ssl session"); + return result; + } } + Curl_ssl_sessionid_unlock(conn); } connssl->connecting_state = ssl_connect_done; @@ -625,7 +754,7 @@ cyassl_connect_common(struct connectdata *conn, bool *done) { CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; long timeout_ms; @@ -756,7 +885,7 @@ Curl_cyassl_connect(struct connectdata *conn, return CURLE_OK; } -int Curl_cyassl_random(struct SessionHandle *data, +int Curl_cyassl_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { @@ -779,7 +908,7 @@ void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ Sha256 SHA256pw; (void)unused; InitSha256(&SHA256pw); - Sha256Update(&SHA256pw, tmp, tmplen); + Sha256Update(&SHA256pw, tmp, (word32)tmplen); Sha256Final(&SHA256pw, sha256sum); } diff --git a/lib/vtls/cyassl.h b/lib/vtls/cyassl.h index 167de74..508dfaa 100644 --- a/lib/vtls/cyassl.h +++ b/lib/vtls/cyassl.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -25,6 +25,18 @@ #ifdef USE_CYASSL +/* KEEP_PEER_CERT is a product of the presence of build time symbol + OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is + in wolfSSL's settings.h, and the latter two are build time symbols in + options.h. */ +#ifndef KEEP_PEER_CERT +#if defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) || \ + defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \ + (defined(OPENSSL_EXTRA) && !defined(NO_CERTS)) +#define KEEP_PEER_CERT +#endif +#endif + CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex); bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex); int Curl_cyassl_shutdown(struct connectdata* conn, int sockindex); @@ -39,7 +51,7 @@ int Curl_cyassl_init(void); CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done); -int Curl_cyassl_random(struct SessionHandle *data, +int Curl_cyassl_random(struct Curl_easy *data, unsigned char *entropy, size_t length); void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ @@ -53,6 +65,11 @@ void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ /* this backend supports CURLOPT_SSL_CTX_* */ #define have_curlssl_ssl_ctx 1 +#ifdef KEEP_PEER_CERT +/* this backend supports CURLOPT_PINNEDPUBLICKEY */ +#define have_curlssl_pinnedpubkey 1 +#endif + /* API setup for CyaSSL */ #define curlssl_init Curl_cyassl_init #define curlssl_cleanup() Curl_nop_stmt diff --git a/lib/vtls/darwinssl.c b/lib/vtls/darwinssl.c index 03adcef..ebb9e30 100644 --- a/lib/vtls/darwinssl.c +++ b/lib/vtls/darwinssl.c @@ -10,7 +10,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -28,7 +28,7 @@ #include "curl_setup.h" -#include "urldata.h" /* for the SessionHandle definition */ +#include "urldata.h" /* for the Curl_easy definition */ #include "curl_base64.h" #include "strtok.h" @@ -781,7 +781,7 @@ CF_INLINE void GetDarwinVersionNumber(int *major, int *minor) int mib[2]; char *os_version; size_t os_version_len; - char *os_version_major, *os_version_minor/*, *os_version_point*/; + char *os_version_major, *os_version_minor; char *tok_buf; /* Get the Darwin kernel version from the kernel using sysctl(): */ @@ -800,7 +800,6 @@ CF_INLINE void GetDarwinVersionNumber(int *major, int *minor) /* Parse the version: */ os_version_major = strtok_r(os_version, ".", &tok_buf); os_version_minor = strtok_r(NULL, ".", &tok_buf); - /*os_version_point = strtok_r(NULL, ".", &tok_buf);*/ *major = atoi(os_version_major); *minor = atoi(os_version_minor); free(os_version); @@ -1000,7 +999,7 @@ CF_INLINE bool is_file(const char *filename) static CURLcode darwinssl_connect_step1(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; #ifdef ENABLE_IPV6 @@ -1010,8 +1009,6 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #endif /* ENABLE_IPV6 */ size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i; SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL; - char *ssl_sessionid; - size_t ssl_sessionid_len; OSStatus err = noErr; #if CURL_BUILD_MAC int darwinver_maj = 0, darwinver_min = 0; @@ -1282,14 +1279,21 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS /* Snow Leopard introduced the SSLSetSessionOption() function, but due to a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag - works, it doesn't work as expected under Snow Leopard or Lion. + works, it doesn't work as expected under Snow Leopard, Lion or + Mountain Lion. So we need to call SSLSetEnableCertVerify() on those older cats in order to disable certificate validation if the user turned that off. (SecureTransport will always validate the certificate chain by - default.) */ - /* (Note: Darwin 12.x.x is Mountain Lion.) */ + default.) + Note: + Darwin 11.x.x is Lion (10.7) + Darwin 12.x.x is Mountain Lion (10.8) + Darwin 13.x.x is Mavericks (10.9) + Darwin 14.x.x is Yosemite (10.10) + Darwin 15.x.x is El Capitan (10.11) + */ #if CURL_BUILD_MAC - if(SSLSetSessionOption != NULL && darwinver_maj >= 12) { + if(SSLSetSessionOption != NULL && darwinver_maj >= 13) { #else if(SSLSetSessionOption != NULL) { #endif /* CURL_BUILD_MAC */ @@ -1468,37 +1472,46 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ /* Check if there's a cached ID we can/should use here! */ - if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid, - &ssl_sessionid_len)) { - /* we got a session id, use it! */ - err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len); - if(err != noErr) { - failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; - } - /* Informational message */ - infof(data, "SSL re-using session ID\n"); - } - /* If there isn't one, then let's make one up! This has to be done prior - to starting the handshake. */ - else { - CURLcode result; - ssl_sessionid = - aprintf("%s:%d:%d:%s:%hu", data->set.str[STRING_SSL_CAFILE], - data->set.ssl.verifypeer, data->set.ssl.verifyhost, - conn->host.name, conn->remote_port); - ssl_sessionid_len = strlen(ssl_sessionid); - - err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len); - if(err != noErr) { - failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; + if(conn->ssl_config.sessionid) { + char *ssl_sessionid; + size_t ssl_sessionid_len; + + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid, + &ssl_sessionid_len)) { + /* we got a session id, use it! */ + err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len); + Curl_ssl_sessionid_unlock(conn); + if(err != noErr) { + failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof(data, "SSL re-using session ID\n"); } + /* If there isn't one, then let's make one up! This has to be done prior + to starting the handshake. */ + else { + CURLcode result; + ssl_sessionid = + aprintf("%s:%d:%d:%s:%hu", data->set.str[STRING_SSL_CAFILE], + data->set.ssl.verifypeer, data->set.ssl.verifyhost, + conn->host.name, conn->remote_port); + ssl_sessionid_len = strlen(ssl_sessionid); + + err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len); + if(err != noErr) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } - result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len); - if(result) { - failf(data, "failed to store ssl session"); - return result; + result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len); + Curl_ssl_sessionid_unlock(conn); + if(result) { + failf(data, "failed to store ssl session"); + return result; + } } } @@ -1620,7 +1633,7 @@ static int read_cert(const char *file, unsigned char **out, size_t *outlen) return 0; } -static int sslerr_to_curlerr(struct SessionHandle *data, int err) +static int sslerr_to_curlerr(struct Curl_easy *data, int err) { switch(err) { case errSSLXCertChainInvalid: @@ -1649,7 +1662,7 @@ static int sslerr_to_curlerr(struct SessionHandle *data, int err) } } -static int append_cert_to_array(struct SessionHandle *data, +static int append_cert_to_array(struct Curl_easy *data, unsigned char *buf, size_t buflen, CFMutableArrayRef array) { @@ -1694,7 +1707,7 @@ static int append_cert_to_array(struct SessionHandle *data, return CURLE_OK; } -static int verify_cert(const char *cafile, struct SessionHandle *data, +static int verify_cert(const char *cafile, struct Curl_easy *data, SSLContextRef ctx) { int n = 0, rc; @@ -1814,7 +1827,7 @@ static int verify_cert(const char *cafile, struct SessionHandle *data, static CURLcode darwinssl_connect_step2(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; OSStatus err; SSLCipherSuite cipher; @@ -1954,7 +1967,7 @@ static CURLcode darwinssl_connect_step3(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CFStringRef server_cert_summary; char server_cert_summary_c[128]; @@ -2078,7 +2091,7 @@ darwinssl_connect_common(struct connectdata *conn, bool *done) { CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; long timeout_ms; @@ -2233,7 +2246,7 @@ void Curl_darwinssl_close(struct connectdata *conn, int sockindex) int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; ssize_t nread; int what; int rc; @@ -2381,7 +2394,7 @@ static ssize_t darwinssl_send(struct connectdata *conn, size_t len, CURLcode *curlcode) { - /*struct SessionHandle *data = conn->data;*/ + /*struct Curl_easy *data = conn->data;*/ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; size_t processed = 0UL; OSStatus err; @@ -2447,7 +2460,7 @@ static ssize_t darwinssl_recv(struct connectdata *conn, size_t buffersize, CURLcode *curlcode) { - /*struct SessionHandle *data = conn->data;*/ + /*struct Curl_easy *data = conn->data;*/ struct ssl_connect_data *connssl = &conn->ssl[num]; size_t processed = 0UL; OSStatus err = SSLRead(connssl->ssl_ctx, buf, buffersize, &processed); diff --git a/lib/vtls/darwinssl.h b/lib/vtls/darwinssl.h index 3bb69c0..8b185b6 100644 --- a/lib/vtls/darwinssl.h +++ b/lib/vtls/darwinssl.h @@ -12,7 +12,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/vtls/gskit.c b/lib/vtls/gskit.c index d884bd4..55a55ef 100644 --- a/lib/vtls/gskit.c +++ b/lib/vtls/gskit.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -163,7 +163,7 @@ static bool is_separator(char c) } -static CURLcode gskit_status(struct SessionHandle *data, int rc, +static CURLcode gskit_status(struct Curl_easy *data, int rc, const char *procname, CURLcode defcode) { /* Process GSKit status and map it to a CURLcode. */ @@ -206,7 +206,7 @@ static CURLcode gskit_status(struct SessionHandle *data, int rc, } -static CURLcode set_enum(struct SessionHandle *data, gsk_handle h, +static CURLcode set_enum(struct Curl_easy *data, gsk_handle h, GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok) { int rc = gsk_attribute_set_enum(h, id, value); @@ -228,7 +228,7 @@ static CURLcode set_enum(struct SessionHandle *data, gsk_handle h, } -static CURLcode set_buffer(struct SessionHandle *data, gsk_handle h, +static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h, GSK_BUF_ID id, const char *buffer, bool unsupported_ok) { int rc = gsk_attribute_set_buffer(h, id, buffer, 0); @@ -250,7 +250,7 @@ static CURLcode set_buffer(struct SessionHandle *data, gsk_handle h, } -static CURLcode set_numeric(struct SessionHandle *data, +static CURLcode set_numeric(struct Curl_easy *data, gsk_handle h, GSK_NUM_ID id, int value) { int rc = gsk_attribute_set_numeric_value(h, id, value); @@ -270,7 +270,7 @@ static CURLcode set_numeric(struct SessionHandle *data, } -static CURLcode set_callback(struct SessionHandle *data, +static CURLcode set_callback(struct Curl_easy *data, gsk_handle h, GSK_CALLBACK_ID id, void *info) { int rc = gsk_attribute_set_callback(h, id, info); @@ -289,7 +289,7 @@ static CURLcode set_callback(struct SessionHandle *data, } -static CURLcode set_ciphers(struct SessionHandle *data, +static CURLcode set_ciphers(struct Curl_easy *data, gsk_handle h, unsigned int *protoflags) { const char *cipherlist = data->set.str[STRING_SSL_CIPHER_LIST]; @@ -436,7 +436,7 @@ void Curl_gskit_cleanup(void) } -static CURLcode init_environment(struct SessionHandle *data, +static CURLcode init_environment(struct Curl_easy *data, gsk_handle *envir, const char *appid, const char *file, const char *label, const char *password) @@ -502,7 +502,7 @@ static void close_async_handshake(struct ssl_connect_data *connssl) static void close_one(struct ssl_connect_data *conn, - struct SessionHandle *data) + struct Curl_easy *data) { if(conn->handle) { gskit_status(data, gsk_secure_soc_close(&conn->handle), @@ -517,7 +517,7 @@ static void close_one(struct ssl_connect_data *conn, static ssize_t gskit_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *curlcode) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode cc; int written; @@ -536,7 +536,7 @@ static ssize_t gskit_send(struct connectdata *conn, int sockindex, static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf, size_t buffersize, CURLcode *curlcode) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int buffsize; int nread; CURLcode cc; @@ -555,7 +555,7 @@ static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf, static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; gsk_handle envir; CURLcode result; @@ -750,7 +750,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex, bool nonblocking) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; Qso_OverlappedIO_t cstat; long timeout_ms; @@ -801,7 +801,7 @@ static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex, static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; const gsk_cert_data_elem *cdev; int cdec; @@ -874,7 +874,7 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) return CURLE_SSL_PINNEDPUBKEYNOTMATCH; Curl_parseX509(&x509, cert, certend); p = &x509.subjectPublicKeyInfo; - result = Curl_pin_peer_pubkey(ptr, p->header, p->end - p->header); + result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header); if(result) { failf(data, "SSL: public key does not match pinned public key!"); return result; @@ -889,7 +889,7 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex, bool nonblocking, bool *done) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; long timeout_ms; Qso_OverlappedIO_t cstat; @@ -976,7 +976,7 @@ CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex) void Curl_gskit_close(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; if(connssl->use) @@ -987,7 +987,7 @@ void Curl_gskit_close(struct connectdata *conn, int sockindex) int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; ssize_t nread; int what; int rc; diff --git a/lib/vtls/gskit.h b/lib/vtls/gskit.h index af31faf..41483cb 100644 --- a/lib/vtls/gskit.h +++ b/lib/vtls/gskit.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index c54dfc1..1c3e6b1 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -62,7 +62,7 @@ /* Some hackish cast macros based on: - http://library.gnome.org/devel/glib/unstable/glib-Type-Conversion-Macros.html + https://developer.gnome.org/glib/unstable/glib-Type-Conversion-Macros.html */ #ifndef GNUTLS_POINTER_TO_INT_CAST #define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p)) @@ -201,7 +201,7 @@ int Curl_gtls_cleanup(void) return 1; } -static void showtime(struct SessionHandle *data, +static void showtime(struct Curl_easy *data, const char *text, time_t stamp) { @@ -262,7 +262,7 @@ static CURLcode handshake(struct connectdata *conn, bool duringconnect, bool nonblocking) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; gnutls_session_t session = conn->ssl[sockindex].session; curl_socket_t sockfd = conn->sock[sockindex]; @@ -367,11 +367,9 @@ static CURLcode gtls_connect_step1(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; gnutls_session_t session; int rc; - void *ssl_sessionid; - size_t ssl_idsize; bool sni = TRUE; /* default is SNI enabled */ #ifdef ENABLE_IPV6 struct in6_addr addr; @@ -487,6 +485,14 @@ gtls_connect_step1(struct connectdata *conn, } #endif +#ifdef CURL_CA_FALLBACK + /* use system ca certificate store as fallback */ + if(data->set.ssl.verifypeer && + !(data->set.ssl.CAfile || data->set.ssl.CApath)) { + gnutls_certificate_set_x509_system_trust(conn->ssl[sockindex].cred); + } +#endif + if(data->set.ssl.CRLfile) { /* set the CRL list file */ rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred, @@ -633,12 +639,12 @@ gtls_connect_step1(struct connectdata *conn, #endif #ifdef HAS_ALPN - if(data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_alpn) { int cur = 0; gnutls_datum_t protocols[2]; #ifdef USE_NGHTTP2 - if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { + if(data->set.httpversion >= CURL_HTTP_VERSION_2) { protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID; protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN; cur++; @@ -656,15 +662,44 @@ gtls_connect_step1(struct connectdata *conn, #endif if(data->set.str[STRING_CERT]) { - if(gnutls_certificate_set_x509_key_file( - conn->ssl[sockindex].cred, - data->set.str[STRING_CERT], - data->set.str[STRING_KEY] ? - data->set.str[STRING_KEY] : data->set.str[STRING_CERT], - do_file_type(data->set.str[STRING_CERT_TYPE]) ) != - GNUTLS_E_SUCCESS) { - failf(data, "error reading X.509 key or certificate file"); + if(data->set.str[STRING_KEY_PASSWD]) { +#if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 + const unsigned int supported_key_encryption_algorithms = + GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR | + GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES | + GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 | + GNUTLS_PKCS_USE_PBES2_AES_256; + rc = gnutls_certificate_set_x509_key_file2( + conn->ssl[sockindex].cred, + data->set.str[STRING_CERT], + data->set.str[STRING_KEY] ? + data->set.str[STRING_KEY] : data->set.str[STRING_CERT], + do_file_type(data->set.str[STRING_CERT_TYPE]), + data->set.str[STRING_KEY_PASSWD], + supported_key_encryption_algorithms); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, + "error reading X.509 potentially-encrypted key file: %s", + gnutls_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } +#else + failf(data, "gnutls lacks support for encrypted key files"); return CURLE_SSL_CONNECT_ERROR; +#endif + } + else { + rc = gnutls_certificate_set_x509_key_file( + conn->ssl[sockindex].cred, + data->set.str[STRING_CERT], + data->set.str[STRING_KEY] ? + data->set.str[STRING_KEY] : data->set.str[STRING_CERT], + do_file_type(data->set.str[STRING_CERT_TYPE]) ); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "error reading X.509 key or certificate file: %s", + gnutls_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } } } @@ -712,19 +747,26 @@ gtls_connect_step1(struct connectdata *conn, /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ + if(conn->ssl_config.sessionid) { + void *ssl_sessionid; + size_t ssl_idsize; - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) { - /* we got a session id, use it! */ - gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) { + /* we got a session id, use it! */ + gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); - /* Informational message */ - infof (data, "SSL re-using session ID\n"); + /* Informational message */ + infof (data, "SSL re-using session ID\n"); + } + Curl_ssl_sessionid_unlock(conn); } return CURLE_OK; } -static CURLcode pkp_pin_peer_pubkey(gnutls_x509_crt_t cert, +static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, + gnutls_x509_crt_t cert, const char *pinnedpubkey) { /* Scratch */ @@ -769,7 +811,7 @@ static CURLcode pkp_pin_peer_pubkey(gnutls_x509_crt_t cert, /* End Gyrations */ /* The one good exit point */ - result = Curl_pin_peer_pubkey(pinnedpubkey, buff1, len1); + result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); } while(0); if(NULL != key) @@ -798,11 +840,9 @@ gtls_connect_step3(struct connectdata *conn, unsigned int bits; time_t certclock; const char *ptr; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; gnutls_session_t session = conn->ssl[sockindex].session; int rc; - bool incache; - void *ssl_sessionid; #ifdef HAS_ALPN gnutls_datum_t proto; #endif @@ -1152,7 +1192,7 @@ gtls_connect_step3(struct connectdata *conn, ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; if(ptr) { - result = pkp_pin_peer_pubkey(x509_cert, ptr); + result = pkp_pin_peer_pubkey(data, x509_cert, ptr); if(result != CURLE_OK) { failf(data, "SSL: public key does not match pinned public key!"); gnutls_x509_crt_deinit(x509_cert); @@ -1202,7 +1242,7 @@ gtls_connect_step3(struct connectdata *conn, infof(data, "\t compression: %s\n", ptr); #ifdef HAS_ALPN - if(data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_alpn) { rc = gnutls_alpn_get_selected_protocol(session, &proto); if(rc == 0) { infof(data, "ALPN, server accepted to use %.*s\n", proto.size, @@ -1212,7 +1252,7 @@ gtls_connect_step3(struct connectdata *conn, if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN && !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data, NGHTTP2_PROTO_VERSION_ID_LEN)) { - conn->negnpn = CURL_HTTP_VERSION_2_0; + conn->negnpn = CURL_HTTP_VERSION_2; } else #endif @@ -1230,11 +1270,13 @@ gtls_connect_step3(struct connectdata *conn, conn->recv[sockindex] = gtls_recv; conn->send[sockindex] = gtls_send; - { + if(conn->ssl_config.sessionid) { /* we always unconditionally get the session id here, as even if we already got it from the cache and asked to use it in the connection, it might've been rejected and then a new one is in use now and we need to detect that. */ + bool incache; + void *ssl_sessionid; void *connect_sessionid; size_t connect_idsize = 0; @@ -1246,6 +1288,7 @@ gtls_connect_step3(struct connectdata *conn, /* extract session ID to the allocated buffer */ gnutls_session_get_data(session, connect_sessionid, &connect_idsize); + Curl_ssl_sessionid_lock(conn); incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)); if(incache) { /* there was one before in the cache, so instead of risking that the @@ -1255,6 +1298,7 @@ gtls_connect_step3(struct connectdata *conn, /* store this session id */ result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize); + Curl_ssl_sessionid_unlock(conn); if(result) { free(connect_sessionid); result = CURLE_OUT_OF_MEMORY; @@ -1343,7 +1387,7 @@ static ssize_t gtls_send(struct connectdata *conn, { ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len); - if(rc < 0 ) { + if(rc < 0) { *curlcode = (rc == GNUTLS_E_AGAIN) ? CURLE_AGAIN : CURLE_SEND_ERROR; @@ -1387,7 +1431,7 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) { ssize_t result; int retval = 0; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int done = 0; char buf[120]; @@ -1500,7 +1544,7 @@ size_t Curl_gtls_version(char *buffer, size_t size) } #ifndef USE_GNUTLS_NETTLE -static int Curl_gtls_seed(struct SessionHandle *data) +static int Curl_gtls_seed(struct Curl_easy *data) { /* we have the "SSL is seeded" boolean static to prevent multiple time-consuming seedings in vain */ @@ -1524,7 +1568,7 @@ static int Curl_gtls_seed(struct SessionHandle *data) #endif /* data might be NULL! */ -int Curl_gtls_random(struct SessionHandle *data, +int Curl_gtls_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { diff --git a/lib/vtls/gtls.h b/lib/vtls/gtls.h index 0afd9b9..e0a95a7 100644 --- a/lib/vtls/gtls.h +++ b/lib/vtls/gtls.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -41,7 +41,7 @@ void Curl_gtls_close(struct connectdata *conn, int sockindex); void Curl_gtls_session_free(void *ptr); size_t Curl_gtls_version(char *buffer, size_t size); int Curl_gtls_shutdown(struct connectdata *conn, int sockindex); -int Curl_gtls_random(struct SessionHandle *data, +int Curl_gtls_random(struct Curl_easy *data, unsigned char *entropy, size_t length); void Curl_gtls_md5sum(unsigned char *tmp, /* input */ @@ -64,6 +64,9 @@ bool Curl_gtls_cert_status_request(void); /* this backend supports CURLOPT_CERTINFO */ #define have_curlssl_certinfo 1 +/* this backend supports CURLOPT_PINNEDPUBLICKEY */ +#define have_curlssl_pinnedpubkey 1 + /* API setup for GnuTLS */ #define curlssl_init Curl_gtls_init #define curlssl_cleanup Curl_gtls_cleanup diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c new file mode 100644 index 0000000..a1e7d23 --- /dev/null +++ b/lib/vtls/mbedtls.c @@ -0,0 +1,871 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2010 - 2011, Hoi-Ho Chan, + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Source file for all mbedTLS-specific code for the TLS/SSL layer. No code + * but vtls.c should ever call or use these functions. + * + */ + +#include "curl_setup.h" + +#ifdef USE_MBEDTLS + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "urldata.h" +#include "sendf.h" +#include "inet_pton.h" +#include "mbedtls.h" +#include "vtls.h" +#include "parsedate.h" +#include "connect.h" /* for the connect timeout */ +#include "select.h" +#include "rawstr.h" +#include "polarssl_threadlock.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* apply threading? */ +#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) +#define THREADING_SUPPORT +#endif + +#if defined(THREADING_SUPPORT) +static mbedtls_entropy_context entropy; + +static int entropy_init_initialized = 0; + +/* start of entropy_init_mutex() */ +static void entropy_init_mutex(mbedtls_entropy_context *ctx) +{ + /* lock 0 = entropy_init_mutex() */ + Curl_polarsslthreadlock_lock_function(0); + if(entropy_init_initialized == 0) { + mbedtls_entropy_init(ctx); + entropy_init_initialized = 1; + } + Curl_polarsslthreadlock_unlock_function(0); +} +/* end of entropy_init_mutex() */ + +/* start of entropy_func_mutex() */ +static int entropy_func_mutex(void *data, unsigned char *output, size_t len) +{ + int ret; + /* lock 1 = entropy_func_mutex() */ + Curl_polarsslthreadlock_lock_function(1); + ret = mbedtls_entropy_func(data, output, len); + Curl_polarsslthreadlock_unlock_function(1); + + return ret; +} +/* end of entropy_func_mutex() */ + +#endif /* THREADING_SUPPORT */ + +/* Define this to enable lots of debugging for mbedTLS */ +#undef MBEDTLS_DEBUG + +#ifdef MBEDTLS_DEBUG +static void mbed_debug(void *context, int level, const char *f_name, + int line_nb, const char *line) +{ + struct Curl_easy *data = NULL; + + if(!context) + return; + + data = (struct Curl_easy *)context; + + infof(data, "%s", line); + (void) level; +} +#else +#endif + +/* ALPN for http2? */ +#ifdef USE_NGHTTP2 +# undef HAS_ALPN +# ifdef MBEDTLS_SSL_ALPN +# define HAS_ALPN +# endif +#endif + + +/* + * profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr = +{ + /* Hashes from SHA-1 and above */ + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512), + 0xFFFFFFF, /* Any PK alg */ + 0xFFFFFFF, /* Any curve */ + 1024, /* RSA min key len */ +}; + +/* See https://tls.mbed.org/discussions/generic/ + howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der +*/ +#define RSA_PUB_DER_MAX_BYTES (38 + 2 * MBEDTLS_MPI_MAX_SIZE) +#define ECP_PUB_DER_MAX_BYTES (30 + 2 * MBEDTLS_ECP_MAX_BYTES) + +#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ + RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES) + +static Curl_recv mbed_recv; +static Curl_send mbed_send; + +static CURLcode +mbed_connect_step1(struct connectdata *conn, + int sockindex) +{ + struct Curl_easy *data = conn->data; + struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + + int ret = -1; + char errorbuf[128]; + errorbuf[0]=0; + + /* mbedTLS only supports SSLv3 and TLSv1 */ + if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { + failf(data, "mbedTLS does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + } + +#ifdef THREADING_SUPPORT + entropy_init_mutex(&entropy); + mbedtls_ctr_drbg_init(&connssl->ctr_drbg); + + ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, entropy_func_mutex, + &entropy, NULL, 0); + if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n", + -ret, errorbuf); + } +#else + mbedtls_entropy_init(&connssl->entropy); + mbedtls_ctr_drbg_init(&connssl->ctr_drbg); + + ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, mbedtls_entropy_func, + &connssl->entropy, NULL, 0); + if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n", + -ret, errorbuf); + } +#endif /* THREADING_SUPPORT */ + + /* Load the trusted CA */ + mbedtls_x509_crt_init(&connssl->cacert); + + if(data->set.str[STRING_SSL_CAFILE]) { + ret = mbedtls_x509_crt_parse_file(&connssl->cacert, + data->set.str[STRING_SSL_CAFILE]); + + if(ret<0) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s", + data->set.str[STRING_SSL_CAFILE], -ret, errorbuf); + + if(data->set.ssl.verifypeer) + return CURLE_SSL_CACERT_BADFILE; + } + } + + if(data->set.str[STRING_SSL_CAPATH]) { + ret = mbedtls_x509_crt_parse_path(&connssl->cacert, + data->set.str[STRING_SSL_CAPATH]); + + if(ret<0) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s", + data->set.str[STRING_SSL_CAPATH], -ret, errorbuf); + + if(data->set.ssl.verifypeer) + return CURLE_SSL_CACERT_BADFILE; + } + } + + /* Load the client certificate */ + mbedtls_x509_crt_init(&connssl->clicert); + + if(data->set.str[STRING_CERT]) { + ret = mbedtls_x509_crt_parse_file(&connssl->clicert, + data->set.str[STRING_CERT]); + + if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s", + data->set.str[STRING_CERT], -ret, errorbuf); + + return CURLE_SSL_CERTPROBLEM; + } + } + + /* Load the client private key */ + mbedtls_pk_init(&connssl->pk); + + if(data->set.str[STRING_KEY]) { + ret = mbedtls_pk_parse_keyfile(&connssl->pk, data->set.str[STRING_KEY], + data->set.str[STRING_KEY_PASSWD]); + if(ret == 0 && !mbedtls_pk_can_do(&connssl->pk, MBEDTLS_PK_RSA)) + ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; + + if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s", + data->set.str[STRING_KEY], -ret, errorbuf); + + return CURLE_SSL_CERTPROBLEM; + } + } + + /* Load the CRL */ + mbedtls_x509_crl_init(&connssl->crl); + + if(data->set.str[STRING_SSL_CRLFILE]) { + ret = mbedtls_x509_crl_parse_file(&connssl->crl, + data->set.str[STRING_SSL_CRLFILE]); + + if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s", + data->set.str[STRING_SSL_CRLFILE], -ret, errorbuf); + + return CURLE_SSL_CRL_BADFILE; + } + } + + infof(data, "mbedTLS: Connecting to %s:%d\n", + conn->host.name, conn->remote_port); + + mbedtls_ssl_config_init(&connssl->config); + + mbedtls_ssl_init(&connssl->ssl); + if(mbedtls_ssl_setup(&connssl->ssl, &connssl->config)) { + failf(data, "mbedTLS: ssl_init failed"); + return CURLE_SSL_CONNECT_ERROR; + } + ret = mbedtls_ssl_config_defaults(&connssl->config, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT); + if(ret) { + failf(data, "mbedTLS: ssl_config failed"); + return CURLE_SSL_CONNECT_ERROR; + } + + /* new profile with RSA min key len = 1024 ... */ + mbedtls_ssl_conf_cert_profile(&connssl->config, + &mbedtls_x509_crt_profile_fr); + + switch(data->set.ssl.version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_1); + infof(data, "mbedTLS: Set min SSL version to TLS 1.0\n"); + break; + case CURL_SSLVERSION_SSLv3: + mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_0); + mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_0); + infof(data, "mbedTLS: Set SSL version to SSLv3\n"); + break; + case CURL_SSLVERSION_TLSv1_0: + mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_1); + mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_1); + infof(data, "mbedTLS: Set SSL version to TLS 1.0\n"); + break; + case CURL_SSLVERSION_TLSv1_1: + mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_2); + mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_2); + infof(data, "mbedTLS: Set SSL version to TLS 1.1\n"); + break; + case CURL_SSLVERSION_TLSv1_2: + mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_3); + mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_3); + infof(data, "mbedTLS: Set SSL version to TLS 1.2\n"); + break; + default: + failf(data, "mbedTLS: Unsupported SSL protocol version"); + return CURLE_SSL_CONNECT_ERROR; + } + + mbedtls_ssl_conf_authmode(&connssl->config, MBEDTLS_SSL_VERIFY_OPTIONAL); + + mbedtls_ssl_conf_rng(&connssl->config, mbedtls_ctr_drbg_random, + &connssl->ctr_drbg); + mbedtls_ssl_set_bio(&connssl->ssl, &conn->sock[sockindex], + mbedtls_net_send, + mbedtls_net_recv, + NULL /* rev_timeout() */); + + mbedtls_ssl_conf_ciphersuites(&connssl->config, + mbedtls_ssl_list_ciphersuites()); + + /* Check if there's a cached ID we can/should use here! */ + if(conn->ssl_config.sessionid) { + void *old_session = NULL; + + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) { + ret = mbedtls_ssl_set_session(&connssl->ssl, old_session); + if(ret) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret); + return CURLE_SSL_CONNECT_ERROR; + } + infof(data, "mbedTLS re-using session\n"); + } + Curl_ssl_sessionid_unlock(conn); + } + + mbedtls_ssl_conf_ca_chain(&connssl->config, + &connssl->cacert, + &connssl->crl); + + if(data->set.str[STRING_KEY]) { + mbedtls_ssl_conf_own_cert(&connssl->config, + &connssl->clicert, &connssl->pk); + } + if(mbedtls_ssl_set_hostname(&connssl->ssl, conn->host.name)) { + /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks *and* + the name to set in the SNI extension. So even if curl connects to a + host specified as an IP address, this function must be used. */ + failf(data, "couldn't set hostname in mbedTLS"); + return CURLE_SSL_CONNECT_ERROR; + } + +#ifdef HAS_ALPN + if(conn->bits.tls_enable_alpn) { + const char **p = &connssl->protocols[0]; +#ifdef USE_NGHTTP2 + if(data->set.httpversion >= CURL_HTTP_VERSION_2) + *p++ = NGHTTP2_PROTO_VERSION_ID; +#endif + *p++ = ALPN_HTTP_1_1; + *p = NULL; + /* this function doesn't clone the protocols array, which is why we need + to keep it around */ + if(mbedtls_ssl_conf_alpn_protocols(&connssl->config, + &connssl->protocols[0])) { + failf(data, "Failed setting ALPN protocols"); + return CURLE_SSL_CONNECT_ERROR; + } + for(p = &connssl->protocols[0]; *p; ++p) + infof(data, "ALPN, offering %s\n", *p); + } +#endif + +#ifdef MBEDTLS_DEBUG + mbedtls_ssl_conf_dbg(&connssl->config, mbed_debug, data); +#endif + + connssl->connecting_state = ssl_connect_2; + + return CURLE_OK; +} + +static CURLcode +mbed_connect_step2(struct connectdata *conn, + int sockindex) +{ + int ret; + struct Curl_easy *data = conn->data; + struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + const mbedtls_x509_crt *peercert; + +#ifdef HAS_ALPN + const char* next_protocol; +#endif + + char errorbuf[128]; + errorbuf[0] = 0; + + conn->recv[sockindex] = mbed_recv; + conn->send[sockindex] = mbed_send; + + ret = mbedtls_ssl_handshake(&connssl->ssl); + + if(ret == MBEDTLS_ERR_SSL_WANT_READ) { + connssl->connecting_state = ssl_connect_2_reading; + return CURLE_OK; + } + else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) { + connssl->connecting_state = ssl_connect_2_writing; + return CURLE_OK; + } + else if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s", + -ret, errorbuf); + return CURLE_SSL_CONNECT_ERROR; + } + + infof(data, "mbedTLS: Handshake complete, cipher is %s\n", + mbedtls_ssl_get_ciphersuite(&conn->ssl[sockindex].ssl) + ); + + ret = mbedtls_ssl_get_verify_result(&conn->ssl[sockindex].ssl); + + if(ret && data->set.ssl.verifypeer) { + if(ret & MBEDTLS_X509_BADCERT_EXPIRED) + failf(data, "Cert verify failed: BADCERT_EXPIRED"); + + if(ret & MBEDTLS_X509_BADCERT_REVOKED) { + failf(data, "Cert verify failed: BADCERT_REVOKED"); + return CURLE_SSL_CACERT; + } + + if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH) + failf(data, "Cert verify failed: BADCERT_CN_MISMATCH"); + + if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED) + failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED"); + + return CURLE_PEER_FAILED_VERIFICATION; + } + + peercert = mbedtls_ssl_get_peer_cert(&connssl->ssl); + + if(peercert && data->set.verbose) { + const size_t bufsize = 16384; + char *buffer = malloc(bufsize); + + if(!buffer) + return CURLE_OUT_OF_MEMORY; + + if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0) + infof(data, "Dumping cert info:\n%s\n", buffer); + else + infof(data, "Unable to dump certificate information.\n"); + + free(buffer); + } + + if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { + int size; + CURLcode result; + mbedtls_x509_crt *p; + unsigned char pubkey[PUB_DER_MAX_BYTES]; + + if(!peercert || !peercert->raw.p || !peercert->raw.len) { + failf(data, "Failed due to missing peer certificate"); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + p = calloc(1, sizeof(*p)); + + if(!p) + return CURLE_OUT_OF_MEMORY; + + mbedtls_x509_crt_init(p); + + /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der + needs a non-const key, for now. + https://github.com/ARMmbed/mbedtls/issues/396 */ + if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { + failf(data, "Failed copying peer certificate"); + mbedtls_x509_crt_free(p); + free(p); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); + + if(size <= 0) { + failf(data, "Failed copying public key from peer certificate"); + mbedtls_x509_crt_free(p); + free(p); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */ + result = Curl_pin_peer_pubkey(data, + data->set.str[STRING_SSL_PINNEDPUBLICKEY], + &pubkey[PUB_DER_MAX_BYTES - size], size); + if(result) { + mbedtls_x509_crt_free(p); + free(p); + return result; + } + + mbedtls_x509_crt_free(p); + free(p); + } + +#ifdef HAS_ALPN + if(conn->bits.tls_enable_alpn) { + next_protocol = mbedtls_ssl_get_alpn_protocol(&connssl->ssl); + + if(next_protocol) { + infof(data, "ALPN, server accepted to use %s\n", next_protocol); +#ifdef USE_NGHTTP2 + if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID, + NGHTTP2_PROTO_VERSION_ID_LEN) && + !next_protocol[NGHTTP2_PROTO_VERSION_ID_LEN]) { + conn->negnpn = CURL_HTTP_VERSION_2; + } + else +#endif + if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) && + !next_protocol[ALPN_HTTP_1_1_LENGTH]) { + conn->negnpn = CURL_HTTP_VERSION_1_1; + } + } + else { + infof(data, "ALPN, server did not agree to a protocol\n"); + } + } +#endif + + connssl->connecting_state = ssl_connect_3; + infof(data, "SSL connected\n"); + + return CURLE_OK; +} + +static CURLcode +mbed_connect_step3(struct connectdata *conn, + int sockindex) +{ + CURLcode retcode = CURLE_OK; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct Curl_easy *data = conn->data; + + DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); + + if(conn->ssl_config.sessionid) { + int ret; + mbedtls_ssl_session *our_ssl_sessionid; + void *old_ssl_sessionid = NULL; + + our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session)); + if(!our_ssl_sessionid) + return CURLE_OUT_OF_MEMORY; + + mbedtls_ssl_session_init(our_ssl_sessionid); + + ret = mbedtls_ssl_get_session(&connssl->ssl, our_ssl_sessionid); + if(ret) { + failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret); + return CURLE_SSL_CONNECT_ERROR; + } + + /* If there's already a matching session in the cache, delete it */ + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)) + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + + retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0); + Curl_ssl_sessionid_unlock(conn); + if(retcode) { + free(our_ssl_sessionid); + failf(data, "failed to store ssl session"); + return retcode; + } + } + + connssl->connecting_state = ssl_connect_done; + + return CURLE_OK; +} + +static ssize_t mbed_send(struct connectdata *conn, int sockindex, + const void *mem, size_t len, + CURLcode *curlcode) +{ + int ret = -1; + + ret = mbedtls_ssl_write(&conn->ssl[sockindex].ssl, + (unsigned char *)mem, len); + + if(ret < 0) { + *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ? + CURLE_AGAIN : CURLE_SEND_ERROR; + ret = -1; + } + + return ret; +} + +void Curl_mbedtls_close_all(struct Curl_easy *data) +{ + (void)data; +} + +void Curl_mbedtls_close(struct connectdata *conn, int sockindex) +{ + mbedtls_pk_free(&conn->ssl[sockindex].pk); + mbedtls_x509_crt_free(&conn->ssl[sockindex].clicert); + mbedtls_x509_crt_free(&conn->ssl[sockindex].cacert); + mbedtls_x509_crl_free(&conn->ssl[sockindex].crl); + mbedtls_ssl_config_free(&conn->ssl[sockindex].config); + mbedtls_ssl_free(&conn->ssl[sockindex].ssl); + mbedtls_ctr_drbg_free(&conn->ssl[sockindex].ctr_drbg); +#ifndef THREADING_SUPPORT + mbedtls_entropy_free(&conn->ssl[sockindex].entropy); +#endif /* THREADING_SUPPORT */ +} + +static ssize_t mbed_recv(struct connectdata *conn, int num, + char *buf, size_t buffersize, + CURLcode *curlcode) +{ + int ret = -1; + ssize_t len = -1; + + memset(buf, 0, buffersize); + ret = mbedtls_ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf, + buffersize); + + if(ret <= 0) { + if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) + return 0; + + *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ? + CURLE_AGAIN : CURLE_RECV_ERROR; + return -1; + } + + len = ret; + + return len; +} + +void Curl_mbedtls_session_free(void *ptr) +{ + mbedtls_ssl_session_free(ptr); + free(ptr); +} + +size_t Curl_mbedtls_version(char *buffer, size_t size) +{ + unsigned int version = mbedtls_version_get_number(); + return snprintf(buffer, size, "mbedTLS/%d.%d.%d", version>>24, + (version>>16)&0xff, (version>>8)&0xff); +} + +static CURLcode +mbed_connect_common(struct connectdata *conn, + int sockindex, + bool nonblocking, + bool *done) +{ + CURLcode retcode; + struct Curl_easy *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + curl_socket_t sockfd = conn->sock[sockindex]; + long timeout_ms; + int what; + + /* check if the connection has already been established */ + if(ssl_connection_complete == connssl->state) { + *done = TRUE; + return CURLE_OK; + } + + if(ssl_connect_1==connssl->connecting_state) { + /* Find out how much more time we're allowed */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + retcode = mbed_connect_step1(conn, sockindex); + if(retcode) + return retcode; + } + + while(ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state) { + + /* check allowed time left */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + /* if ssl is expecting something, check if it's available. */ + if(connssl->connecting_state == ssl_connect_2_reading + || connssl->connecting_state == ssl_connect_2_writing) { + + curl_socket_t writefd = ssl_connect_2_writing== + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading== + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + + what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + return CURLE_SSL_CONNECT_ERROR; + } + else if(0 == what) { + if(nonblocking) { + *done = FALSE; + return CURLE_OK; + } + else { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + } + /* socket is readable or writable */ + } + + /* Run transaction, and return to the caller if it failed or if + * this connection is part of a multi handle and this loop would + * execute again. This permits the owner of a multi handle to + * abort a connection attempt before step2 has completed while + * ensuring that a client using select() or epoll() will always + * have a valid fdset to wait on. + */ + retcode = mbed_connect_step2(conn, sockindex); + if(retcode || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return retcode; + + } /* repeat step2 until all transactions are done. */ + + if(ssl_connect_3==connssl->connecting_state) { + retcode = mbed_connect_step3(conn, sockindex); + if(retcode) + return retcode; + } + + if(ssl_connect_done==connssl->connecting_state) { + connssl->state = ssl_connection_complete; + conn->recv[sockindex] = mbed_recv; + conn->send[sockindex] = mbed_send; + *done = TRUE; + } + else + *done = FALSE; + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + + return CURLE_OK; +} + +CURLcode +Curl_mbedtls_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done) +{ + return mbed_connect_common(conn, sockindex, TRUE, done); +} + + +CURLcode +Curl_mbedtls_connect(struct connectdata *conn, + int sockindex) +{ + CURLcode retcode; + bool done = FALSE; + + retcode = mbed_connect_common(conn, sockindex, FALSE, &done); + if(retcode) + return retcode; + + DEBUGASSERT(done); + + return CURLE_OK; +} + +/* + * return 0 error initializing SSL + * return 1 SSL initialized successfully + */ +int Curl_mbedtls_init(void) +{ + return Curl_polarsslthreadlock_thread_setup(); +} + +void Curl_mbedtls_cleanup(void) +{ + (void)Curl_polarsslthreadlock_thread_cleanup(); +} + +int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex) +{ + mbedtls_ssl_context *ssl = + (mbedtls_ssl_context *)&conn->ssl[sockindex].ssl; + return ssl->in_msglen != 0; +} + +#endif /* USE_MBEDTLS */ diff --git a/lib/vtls/mbedtls.h b/lib/vtls/mbedtls.h new file mode 100644 index 0000000..1021d54 --- /dev/null +++ b/lib/vtls/mbedtls.h @@ -0,0 +1,80 @@ +#ifndef HEADER_CURL_MBEDTLS_H +#define HEADER_CURL_MBEDTLS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 2010, Hoi-Ho Chan, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_MBEDTLS + +#include + +/* Called on first use mbedTLS, setup threading if supported */ +int Curl_mbedtls_init(void); +void Curl_mbedtls_cleanup(void); +int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex); + +CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex); + +CURLcode Curl_mbedtls_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done); + +/* tell mbedTLS to close down all open information regarding connections (and + thus session ID caching etc) */ +void Curl_mbedtls_close_all(struct Curl_easy *data); + + /* close a SSL connection */ +void Curl_mbedtls_close(struct connectdata *conn, int sockindex); + +void Curl_mbedtls_session_free(void *ptr); +size_t Curl_mbedtls_version(char *buffer, size_t size); +int Curl_mbedtls_shutdown(struct connectdata *conn, int sockindex); + +/* this backends supports CURLOPT_PINNEDPUBLICKEY */ +#define have_curlssl_pinnedpubkey 1 + +/* API setup for mbedTLS */ +#define curlssl_init() Curl_mbedtls_init() +#define curlssl_cleanup() Curl_mbedtls_cleanup() +#define curlssl_connect Curl_mbedtls_connect +#define curlssl_connect_nonblocking Curl_mbedtls_connect_nonblocking +#define curlssl_session_free(x) Curl_mbedtls_session_free(x) +#define curlssl_close_all Curl_mbedtls_close_all +#define curlssl_close Curl_mbedtls_close +#define curlssl_shutdown(x,y) 0 +#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN) +#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN) +#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL) +#define curlssl_version Curl_mbedtls_version +#define curlssl_check_cxn(x) (x=x, -1) +#define curlssl_data_pending(x,y) Curl_mbedtls_data_pending(x, y) +#define CURL_SSL_BACKEND CURLSSLBACKEND_MBEDTLS +#define curlssl_sha256sum(a,b,c,d) mbedtls_sha256(a,b,c,0) + +/* This might cause libcurl to use a weeker random! + TODO: implement proper use of Polarssl's CTR-DRBG or HMAC-DRBG and use that +*/ +#define curlssl_random(x,y,z) (x=x, y=y, z=z, CURLE_NOT_BUILT_IN) + +#endif /* USE_MBEDTLS */ +#endif /* HEADER_CURL_MBEDTLS_H */ diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c index 91727c7..ad33f25 100644 --- a/lib/vtls/nss.c +++ b/lib/vtls/nss.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -198,12 +198,12 @@ static const char* nss_error_to_name(PRErrorCode code) return "unknown error"; } -static void nss_print_error_message(struct SessionHandle *data, PRUint32 err) +static void nss_print_error_message(struct Curl_easy *data, PRUint32 err) { failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT)); } -static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model, +static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model, char *cipher_list) { unsigned int i; @@ -211,16 +211,22 @@ static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model, PRBool found; char *cipher; + /* use accessors to avoid dynamic linking issues after an update of NSS */ + const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers(); + const PRUint16 *implemented_ciphers = SSL_GetImplementedCiphers(); + if(!implemented_ciphers) + return SECFailure; + /* First disable all ciphers. This uses a different max value in case * NSS adds more ciphers later we don't want them available by * accident */ - for(i=0; iset.str[cert_kind]; const char *n; @@ -322,8 +328,8 @@ static char* dup_nickname(struct SessionHandle *data, enum dupstring cert_kind) /* no such file exists, use the string as nickname */ return strdup(str); - /* search the last slash; we require at least one slash in a file name */ - n = strrchr(str, '/'); + /* search the first slash; we require at least one slash in a file name */ + n = strchr(str, '/'); if(!n) { infof(data, "warning: certificate file name \"%s\" handled as nickname; " "please use \"./%s\" to force file name\n", str, str); @@ -591,7 +597,7 @@ static int display_error(struct connectdata *conn, PRInt32 err, static CURLcode cert_stuff(struct connectdata *conn, int sockindex, char *cert_file, char *key_file) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result; if(cert_file) { @@ -690,7 +696,7 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg) unsigned int buflen; SSLNextProtoState state; - if(!conn->data->set.ssl_enable_npn && !conn->data->set.ssl_enable_alpn) { + if(!conn->bits.tls_enable_npn && !conn->bits.tls_enable_alpn) { return; } @@ -714,7 +720,7 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg) #ifdef USE_NGHTTP2 if(buflen == NGHTTP2_PROTO_VERSION_ID_LEN && !memcmp(NGHTTP2_PROTO_VERSION_ID, buf, NGHTTP2_PROTO_VERSION_ID_LEN)) { - conn->negnpn = CURL_HTTP_VERSION_2_0; + conn->negnpn = CURL_HTTP_VERSION_2; } else #endif @@ -730,7 +736,7 @@ static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data, PRBool *canFalseStart) { struct connectdata *conn = client_data; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; SSLChannelInfo channelInfo; SSLCipherSuiteInfo cipherInfo; @@ -785,7 +791,7 @@ end: } #endif -static void display_cert_info(struct SessionHandle *data, +static void display_cert_info(struct Curl_easy *data, CERTCertificate *cert) { char *subject, *issuer, *common_name; @@ -886,7 +892,7 @@ static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock) static SECStatus BadCertHandler(void *arg, PRFileDesc *sock) { struct connectdata *conn = (struct connectdata *)arg; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; PRErrorCode err = PR_GetError(); CERTCertificate *cert; @@ -922,12 +928,6 @@ static SECStatus check_issuer_cert(PRFileDesc *sock, SECStatus res=SECSuccess; void *proto_win = NULL; - /* - PRArenaPool *tmpArena = NULL; - CERTAuthKeyID *authorityKeyID = NULL; - SECITEM *caname = NULL; - */ - cert = SSL_PeerCertificate(sock); cert_issuer = CERT_FindCertIssuer(cert, PR_Now(), certUsageObjectSigner); @@ -950,7 +950,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, const char *pinnedpubkey) { CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; - struct SessionHandle *data = connssl->data; + struct Curl_easy *data = connssl->data; CERTCertificate *cert; if(!pinnedpubkey) @@ -967,8 +967,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, SECItem *cert_der = PK11_DEREncodePublicKey(pubkey); if(cert_der) { /* compare the public key with the pinned public key */ - result = Curl_pin_peer_pubkey(pinnedpubkey, - cert_der->data, + result = Curl_pin_peer_pubkey(data, pinnedpubkey, cert_der->data, cert_der->len); SECITEM_FreeItem(cert_der, PR_TRUE); } @@ -1003,7 +1002,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct SECKEYPrivateKeyStr **pRetKey) { struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; - struct SessionHandle *data = connssl->data; + struct Curl_easy *data = connssl->data; const char *nickname = connssl->client_nickname; if(connssl->obj_clicert) { @@ -1135,7 +1134,7 @@ static PRStatus nspr_io_close(PRFileDesc *fd) } /* data might be NULL */ -static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir) +static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir) { NSSInitParameters initparams; @@ -1173,7 +1172,7 @@ static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir) } /* data might be NULL */ -static CURLcode nss_init(struct SessionHandle *data) +static CURLcode nss_init(struct Curl_easy *data) { char *cert_dir; struct_stat st; @@ -1223,7 +1222,7 @@ static CURLcode nss_init(struct SessionHandle *data) if(result) return result; - if(num_enabled_ciphers() == 0) + if(!any_cipher_enabled()) NSS_SetDomesticPolicy(); initialized = 1; @@ -1252,7 +1251,7 @@ int Curl_nss_init(void) } /* data might be NULL */ -CURLcode Curl_nss_force_init(struct SessionHandle *data) +CURLcode Curl_nss_force_init(struct Curl_easy *data) { CURLcode result; if(!nss_initlock) { @@ -1398,7 +1397,7 @@ static Curl_send nss_send; static CURLcode nss_load_ca_certificates(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; const char *cafile = data->set.ssl.CAfile; const char *capath = data->set.ssl.CApath; @@ -1448,7 +1447,7 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn, } static CURLcode nss_init_sslver(SSLVersionRange *sslver, - struct SessionHandle *data) + struct Curl_easy *data) { switch(data->set.ssl.version) { default: @@ -1501,7 +1500,7 @@ static CURLcode nss_init_sslver(SSLVersionRange *sslver, } static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, - struct SessionHandle *data, + struct Curl_easy *data, CURLcode curlerr) { PRErrorCode err = 0; @@ -1528,7 +1527,7 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, /* Switch the SSL socket into non-blocking mode. */ static CURLcode nss_set_nonblock(struct ssl_connect_data *connssl, - struct SessionHandle *data) + struct Curl_easy *data) { static PRSocketOptionData sock_opt; sock_opt.option = PR_SockOpt_Nonblocking; @@ -1547,7 +1546,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) PRFileDesc *nspr_io_stub = NULL; PRBool ssl_no_cache; PRBool ssl_cbc_random_iv; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CURLcode result; @@ -1745,14 +1744,14 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) #endif #ifdef SSL_ENABLE_NPN - if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, data->set.ssl_enable_npn - ? PR_TRUE : PR_FALSE) != SECSuccess) + if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn + ? PR_TRUE : PR_FALSE) != SECSuccess) goto error; #endif #ifdef SSL_ENABLE_ALPN - if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, data->set.ssl_enable_alpn - ? PR_TRUE : PR_FALSE) != SECSuccess) + if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn + ? PR_TRUE : PR_FALSE) != SECSuccess) goto error; #endif @@ -1769,12 +1768,12 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) #endif #if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN) - if(data->set.ssl_enable_npn || data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_npn || conn->bits.tls_enable_alpn) { int cur = 0; unsigned char protocols[128]; #ifdef USE_NGHTTP2 - if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { + if(data->set.httpversion >= CURL_HTTP_VERSION_2) { protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN); @@ -1792,9 +1791,17 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) /* Force handshake on next I/O */ - SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE); + if(SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE) + != SECSuccess) + goto error; - SSL_SetURL(connssl->handle, conn->host.name); + /* propagate hostname to the TLS layer */ + if(SSL_SetURL(connssl->handle, conn->host.name) != SECSuccess) + goto error; + + /* prevent NSS from re-using the session for a different hostname */ + if(SSL_SetSockPeerID(connssl->handle, conn->host.name) != SECSuccess) + goto error; return CURLE_OK; @@ -1808,7 +1815,7 @@ error: static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result = CURLE_SSL_CONNECT_ERROR; PRUint32 timeout; @@ -1871,7 +1878,7 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, bool *done) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; const bool blocking = (done == NULL); CURLcode result; @@ -2008,14 +2015,14 @@ size_t Curl_nss_version(char *buffer, size_t size) } /* data might be NULL */ -int Curl_nss_seed(struct SessionHandle *data) +int Curl_nss_seed(struct Curl_easy *data) { /* make sure that NSS is initialized */ return !!Curl_nss_force_init(data); } /* data might be NULL */ -int Curl_nss_random(struct SessionHandle *data, +int Curl_nss_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { diff --git a/lib/vtls/nssg.h b/lib/vtls/nssg.h index 5fd7275..ac67e6a 100644 --- a/lib/vtls/nssg.h +++ b/lib/vtls/nssg.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -42,12 +42,12 @@ void Curl_nss_cleanup(void); size_t Curl_nss_version(char *buffer, size_t size); int Curl_nss_check_cxn(struct connectdata *cxn); -int Curl_nss_seed(struct SessionHandle *data); +int Curl_nss_seed(struct Curl_easy *data); /* initialize NSS library if not already */ -CURLcode Curl_nss_force_init(struct SessionHandle *data); +CURLcode Curl_nss_force_init(struct Curl_easy *data); -int Curl_nss_random(struct SessionHandle *data, +int Curl_nss_random(struct Curl_easy *data, unsigned char *entropy, size_t length); @@ -74,6 +74,9 @@ bool Curl_nss_false_start(void); /* this backend supports CURLOPT_CERTINFO */ #define have_curlssl_certinfo 1 +/* this backends supports CURLOPT_PINNEDPUBLICKEY */ +#define have_curlssl_pinnedpubkey 1 + /* API setup for NSS */ #define curlssl_init Curl_nss_init #define curlssl_cleanup Curl_nss_cleanup diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 90e4c2b..3027ca3 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -68,7 +68,7 @@ #include #endif -#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_IS_BORINGSSL) +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP) #include #endif @@ -83,23 +83,8 @@ #error "OPENSSL_VERSION_NUMBER not defined" #endif -#if OPENSSL_VERSION_NUMBER >= 0x00907001L && !defined(OPENSSL_IS_BORINGSSL) -/* ENGINE_load_private_key() takes four arguments */ -#define HAVE_ENGINE_LOAD_FOUR_ARGS +#if defined(HAVE_OPENSSL_ENGINE_H) #include -#else -/* ENGINE_load_private_key() takes three arguments */ -#undef HAVE_ENGINE_LOAD_FOUR_ARGS -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x00903001L) && \ - defined(HAVE_OPENSSL_PKCS12_H) && \ - !defined(OPENSSL_IS_BORINGSSL) -/* OpenSSL has PKCS 12 support, BoringSSL does not */ -#define HAVE_PKCS12_SUPPORT -#else -/* OpenSSL does not have PKCS12 support */ -#undef HAVE_PKCS12_SUPPORT #endif #if OPENSSL_VERSION_NUMBER >= 0x00909000L @@ -108,18 +93,13 @@ #define SSL_METHOD_QUAL #endif -#if OPENSSL_VERSION_NUMBER >= 0x00907000L -/* 0.9.6 didn't have X509_STORE_set_flags() */ -#define HAVE_X509_STORE_SET_FLAGS 1 -#else -#define X509_STORE_set_flags(x,y) Curl_nop_stmt -#endif - -#ifdef OPENSSL_IS_BORINGSSL -/* BoringSSL has no ERR_remove_state() */ -#define ERR_remove_state(x) -#elif (OPENSSL_VERSION_NUMBER >= 0x10000000L) +#if (OPENSSL_VERSION_NUMBER >= 0x10000000L) #define HAVE_ERR_REMOVE_THREAD_STATE 1 +#if (OPENSSL_VERSION_NUMBER >= 0x10100004L) && \ + !defined(LIBRESSL_VERSION_NUMBER) +/* OpenSSL 1.1.0 deprecates the function */ +#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1 +#endif #endif #if !defined(HAVE_SSLV2_CLIENT_METHOD) || \ @@ -128,19 +108,39 @@ #define OPENSSL_NO_SSL2 #endif -#if defined(OPENSSL_IS_BORINGSSL) -#define NO_RAND_SEED 1 -/* In BoringSSL OpenSSL_add_all_algorithms does nothing */ -#define OpenSSL_add_all_algorithms() -/* BoringSSL does not have CONF_modules_load_file */ -#define CONF_modules_load_file(a,b,c) +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \ + !defined(LIBRESSL_VERSION_NUMBER) +#define SSLeay_add_ssl_algorithms() SSL_library_init() +#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER +#define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */ +#define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */ +#define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */ +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \ + !defined(LIBRESSL_VERSION_NUMBER) +#define HAVE_X509_GET0_SIGNATURE 1 #endif -#if (OPENSSL_VERSION_NUMBER < 0x0090808fL) || defined(OPENSSL_IS_BORINGSSL) -/* not present in BoringSSL or older OpenSSL */ +#if OPENSSL_VERSION_NUMBER >= 0x10002003L && \ + OPENSSL_VERSION_NUMBER <= 0x10002FFFL && \ + !defined(OPENSSL_NO_COMP) +#define HAVE_SSL_COMP_FREE_COMPRESSION_METHODS 1 +#endif + +#if (OPENSSL_VERSION_NUMBER < 0x0090808fL) +/* not present in older OpenSSL */ #define OPENSSL_load_builtin_modules(x) #endif +#if defined(LIBRESSL_VERSION_NUMBER) +#define OSSL_PACKAGE "LibreSSL" +#elif defined(OPENSSL_IS_BORINGSSL) +#define OSSL_PACKAGE "BoringSSL" +#else +#define OSSL_PACKAGE "OpenSSL" +#endif + /* * Number of bytes to read from the random number seed file. This must be * a finite value (because some entropy "files" like /dev/urandom have @@ -171,7 +171,6 @@ static int passwd_callback(char *buf, int num, int encrypting, * pass in an argument that is never used. */ -#ifndef NO_RAND_SEED #ifdef HAVE_RAND_STATUS #define seed_enough(x) rand_enough() static bool rand_enough(void) @@ -187,7 +186,7 @@ static bool rand_enough(int nread) } #endif -static int ossl_seed(struct SessionHandle *data) +static int ossl_seed(struct Curl_easy *data) { char *buf = data->state.buffer; /* point to the big buffer */ int nread=0; @@ -256,7 +255,7 @@ static int ossl_seed(struct SessionHandle *data) return nread; } -static void Curl_ossl_seed(struct SessionHandle *data) +static void Curl_ossl_seed(struct Curl_easy *data) { /* we have the "SSL is seeded" boolean static to prevent multiple time-consuming seedings in vain */ @@ -268,11 +267,6 @@ static void Curl_ossl_seed(struct SessionHandle *data) ssl_seeded = TRUE; } } -#else -/* BoringSSL needs no seeding */ -#define Curl_ossl_seed(x) -#endif - #ifndef SSL_FILETYPE_ENGINE #define SSL_FILETYPE_ENGINE 42 @@ -295,7 +289,7 @@ static int do_file_type(const char *type) return -1; } -#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_LOAD_FOUR_ARGS) +#if defined(HAVE_OPENSSL_ENGINE_H) /* * Supply default password to the engine user interface conversation. * The password is passed by OpenSSL engine from ENGINE_load_private_key() @@ -345,7 +339,7 @@ int cert_stuff(struct connectdata *conn, char *key_file, const char *key_type) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int file_type = do_file_type(cert_type); @@ -369,7 +363,8 @@ int cert_stuff(struct connectdata *conn, if(SSL_CTX_use_certificate_chain_file(ctx, cert_file) != 1) { failf(data, - "could not load PEM client certificate, OpenSSL error %s, " + "could not load PEM client certificate, " OSSL_PACKAGE + " error %s, " "(no key found, wrong pass phrase, or wrong file format?)", ERR_error_string(ERR_get_error(), NULL) ); return 0; @@ -384,7 +379,8 @@ int cert_stuff(struct connectdata *conn, cert_file, file_type) != 1) { failf(data, - "could not load ASN1 client certificate, OpenSSL error %s, " + "could not load ASN1 client certificate, " OSSL_PACKAGE + " error %s, " "(no key found, wrong pass phrase, or wrong file format?)", ERR_error_string(ERR_get_error(), NULL) ); return 0; @@ -445,12 +441,11 @@ int cert_stuff(struct connectdata *conn, case SSL_FILETYPE_PKCS12: { -#ifdef HAVE_PKCS12_SUPPORT +#ifdef HAVE_OPENSSL_PKCS12_H FILE *f; PKCS12 *p12; EVP_PKEY *pri; STACK_OF(X509) *ca = NULL; - int i; f = fopen(cert_file, "rb"); if(!f) { @@ -470,7 +465,8 @@ int cert_stuff(struct connectdata *conn, if(!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509, &ca)) { failf(data, - "could not parse PKCS12 file, check password, OpenSSL error %s", + "could not parse PKCS12 file, check password, " OSSL_PACKAGE + " error %s", ERR_error_string(ERR_get_error(), NULL) ); PKCS12_free(p12); return 0; @@ -480,7 +476,8 @@ int cert_stuff(struct connectdata *conn, if(SSL_CTX_use_certificate(ctx, x509) != 1) { failf(data, - "could not load PKCS12 client certificate, OpenSSL error %s", + "could not load PKCS12 client certificate, " OSSL_PACKAGE + " error %s", ERR_error_string(ERR_get_error(), NULL) ); goto fail; } @@ -497,8 +494,8 @@ int cert_stuff(struct connectdata *conn, goto fail; } /* Set Certificate Verification chain */ - if(ca && sk_X509_num(ca)) { - for(i = 0; i < sk_X509_num(ca); i++) { + if(ca) { + while(sk_X509_num(ca)) { /* * Note that sk_X509_pop() is used below to make sure the cert is * removed from the stack properly before getting passed to @@ -508,6 +505,7 @@ int cert_stuff(struct connectdata *conn, */ X509 *x = sk_X509_pop(ca); if(!SSL_CTX_add_extra_chain_cert(ctx, x)) { + X509_free(x); failf(data, "cannot add certificate to certificate chain"); goto fail; } @@ -561,28 +559,23 @@ int cert_stuff(struct connectdata *conn, { /* XXXX still needs some work */ EVP_PKEY *priv_key = NULL; if(data->state.engine) { -#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS UI_METHOD *ui_method = UI_create_method((char *)"cURL user interface"); if(!ui_method) { - failf(data, "unable do create OpenSSL user-interface method"); + failf(data, "unable do create " OSSL_PACKAGE + " user-interface method"); return 0; } UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL())); UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL())); UI_method_set_reader(ui_method, ssl_ui_reader); UI_method_set_writer(ui_method, ssl_ui_writer); -#endif /* the typecast below was added to please mingw32 */ priv_key = (EVP_PKEY *) ENGINE_load_private_key(data->state.engine, key_file, -#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS ui_method, -#endif data->set.str[STRING_KEY_PASSWD]); -#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS UI_destroy_method(ui_method); -#endif if(!priv_key) { failf(data, "failed to load private key from crypto engine"); return 0; @@ -679,7 +672,7 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size) /* Return error string for last OpenSSL error */ -static char *SSL_strerror(unsigned long error, char *buf, size_t size) +static char *ossl_strerror(unsigned long error, char *buf, size_t size) { /* OpenSSL 0.9.6 and later has a function named ERR_error_string_n() that takes the size of the buffer as a @@ -702,16 +695,6 @@ int Curl_ossl_init(void) ENGINE_load_builtin_engines(); #endif - /* Lets get nice error messages */ - SSL_load_error_strings(); - - /* Init the global ciphers and digests */ - if(!SSLeay_add_ssl_algorithms()) - return 0; - - OpenSSL_add_all_algorithms(); - - /* OPENSSL_config(NULL); is "strongly recommended" to use but unfortunately that function makes an exit() call on wrongly formatted config files which makes it hard to use in some situations. OPENSSL_config() itself @@ -728,6 +711,15 @@ int Curl_ossl_init(void) CONF_MFLAGS_DEFAULT_SECTION| CONF_MFLAGS_IGNORE_MISSING_FILE); + /* Lets get nice error messages */ + SSL_load_error_strings(); + + /* Init the global ciphers and digests */ + if(!SSLeay_add_ssl_algorithms()) + return 0; + + OpenSSL_add_all_algorithms(); + return 1; } @@ -751,15 +743,24 @@ void Curl_ossl_cleanup(void) ERR_free_strings(); /* Free thread local error state, destroying hash upon zero refcount */ -#ifdef HAVE_ERR_REMOVE_THREAD_STATE +#ifdef HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED + +#elif defined(HAVE_ERR_REMOVE_THREAD_STATE) ERR_remove_thread_state(NULL); #else ERR_remove_state(0); #endif + + /* Free all memory allocated by all configuration modules */ + CONF_modules_free(); + +#ifdef HAVE_SSL_COMP_FREE_COMPRESSION_METHODS + SSL_COMP_free_compression_methods(); +#endif } /* - * This function uses SSL_peek to determine connection status. + * This function is used to determine connection status. * * Return codes: * 1 means the connection is still in place @@ -768,22 +769,51 @@ void Curl_ossl_cleanup(void) */ int Curl_ossl_check_cxn(struct connectdata *conn) { - int rc; + /* SSL_peek takes data out of the raw recv buffer without peeking so we use + recv MSG_PEEK instead. Bug #795 */ +#ifdef MSG_PEEK char buf; - - rc = SSL_peek(conn->ssl[FIRSTSOCKET].handle, (void*)&buf, 1); - if(rc > 0) - return 1; /* connection still in place */ - - if(rc == 0) + ssize_t nread; + nread = recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf, + (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK); + if(nread == 0) return 0; /* connection has been closed */ - + else if(nread == 1) + return 1; /* connection still in place */ + else if(nread == -1) { + int err = SOCKERRNO; + if(err == EINPROGRESS || +#if defined(EAGAIN) && (EAGAIN != EWOULDBLOCK) + err == EAGAIN || +#endif + err == EWOULDBLOCK) + return 1; /* connection still in place */ + if(err == ECONNRESET || +#ifdef ECONNABORTED + err == ECONNABORTED || +#endif +#ifdef ENETDOWN + err == ENETDOWN || +#endif +#ifdef ENETRESET + err == ENETRESET || +#endif +#ifdef ESHUTDOWN + err == ESHUTDOWN || +#endif +#ifdef ETIMEDOUT + err == ETIMEDOUT || +#endif + err == ENOTCONN) + return 0; /* connection has been closed */ + } +#endif return -1; /* connection status unknown */ } /* Selects an OpenSSL crypto engine */ -CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine) +CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine) { #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) ENGINE *e; @@ -814,7 +844,7 @@ CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine) ENGINE_free(e); failf(data, "Failed to initialise SSL Engine '%s':\n%s", - engine, SSL_strerror(ERR_get_error(), buf, sizeof(buf))); + engine, ossl_strerror(ERR_get_error(), buf, sizeof(buf))); return CURLE_SSL_ENGINE_INITFAILED; } data->state.engine = e; @@ -828,7 +858,7 @@ CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine) /* Sets engine as default for all SSL operations */ -CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data) +CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data) { #ifdef HAVE_OPENSSL_ENGINE_H if(data->state.engine) { @@ -850,7 +880,7 @@ CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data) /* Return list of OpenSSL crypto engine names. */ -struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data) +struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data) { struct curl_slist *list = NULL; #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) @@ -899,9 +929,9 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) { int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; - char buf[120]; /* We will use this for the OpenSSL error buffer, so it has - to be at least 120 bytes long. */ + struct Curl_easy *data = conn->data; + char buf[256]; /* We will use this for the OpenSSL error buffer, so it has + to be at least 256 bytes long. */ unsigned long sslerror; ssize_t nread; int buffsize; @@ -949,8 +979,8 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) default: /* openssl/ssl.h says "look at error stack/return value/errno" */ sslerror = ERR_get_error(); - failf(conn->data, "SSL read: %s, errno %d", - ERR_error_string(sslerror, buf), + failf(conn->data, OSSL_PACKAGE " SSL read: %s, errno %d", + ossl_strerror(sslerror, buf, sizeof(buf)), SOCKERRNO); done = 1; break; @@ -1002,7 +1032,7 @@ void Curl_ossl_session_free(void *ptr) * This function is called when the 'data' struct is going away. Close * down everything and free all resources! */ -void Curl_ossl_close_all(struct SessionHandle *data) +void Curl_ossl_close_all(struct Curl_easy *data) { #ifdef HAVE_OPENSSL_ENGINE_H if(data->state.engine) { @@ -1015,49 +1045,6 @@ void Curl_ossl_close_all(struct SessionHandle *data) #endif } -static int asn1_output(const ASN1_UTCTIME *tm, - char *buf, - size_t sizeofbuf) -{ - const char *asn1_string; - int gmt=FALSE; - int i; - int year=0, month=0, day=0, hour=0, minute=0, second=0; - - i=tm->length; - asn1_string=(const char *)tm->data; - - if(i < 10) - return 1; - if(asn1_string[i-1] == 'Z') - gmt=TRUE; - for(i=0; i<10; i++) - if((asn1_string[i] > '9') || (asn1_string[i] < '0')) - return 2; - - year= (asn1_string[0]-'0')*10+(asn1_string[1]-'0'); - if(year < 50) - year+=100; - - month= (asn1_string[2]-'0')*10+(asn1_string[3]-'0'); - if((month > 12) || (month < 1)) - return 3; - - day= (asn1_string[4]-'0')*10+(asn1_string[5]-'0'); - hour= (asn1_string[6]-'0')*10+(asn1_string[7]-'0'); - minute= (asn1_string[8]-'0')*10+(asn1_string[9]-'0'); - - if((asn1_string[10] >= '0') && (asn1_string[10] <= '9') && - (asn1_string[11] >= '0') && (asn1_string[11] <= '9')) - second= (asn1_string[10]-'0')*10+(asn1_string[11]-'0'); - - snprintf(buf, sizeofbuf, - "%04d-%02d-%02d %02d:%02d:%02d %s", - year+1900, month, day, hour, minute, second, (gmt?"GMT":"")); - - return 0; -} - /* ====================================================== */ @@ -1084,11 +1071,10 @@ static int asn1_output(const ASN1_UTCTIME *tm, */ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) { - int matched = -1; /* -1 is no alternative match yet, 1 means match and 0 - means mismatch */ + bool matched = FALSE; int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */ size_t addrlen = 0; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; STACK_OF(GENERAL_NAME) *altnames; #ifdef ENABLE_IPV6 struct in6_addr addr; @@ -1096,6 +1082,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) struct in_addr addr; #endif CURLcode result = CURLE_OK; + bool dNSName = FALSE; /* if a dNSName field exists in the cert */ #ifdef ENABLE_IPV6 if(conn->bits.ipv6_ip && @@ -1116,16 +1103,23 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) if(altnames) { int numalts; int i; + bool dnsmatched = FALSE; + bool ipmatched = FALSE; /* get amount of alternatives, RFC2459 claims there MUST be at least one, but we don't depend on it... */ numalts = sk_GENERAL_NAME_num(altnames); - /* loop through all alternatives while none has matched */ - for(i=0; (itype == GEN_DNS) + dNSName = TRUE; + /* only check alternatives of the same type the target is */ if(check->type == target) { /* get data and length */ @@ -1147,33 +1141,42 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) if((altlen == strlen(altptr)) && /* if this isn't true, there was an embedded zero in the name string and we cannot match it. */ - Curl_cert_hostcheck(altptr, conn->host.name)) - matched = 1; - else - matched = 0; + Curl_cert_hostcheck(altptr, conn->host.name)) { + dnsmatched = TRUE; + infof(data, + " subjectAltName: host \"%s\" matched cert's \"%s\"\n", + conn->host.dispname, altptr); + } break; case GEN_IPADD: /* IP address comparison */ /* compare alternative IP address if the data chunk is the same size our server IP address is */ - if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) - matched = 1; - else - matched = 0; + if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) { + ipmatched = TRUE; + infof(data, + " subjectAltName: host \"%s\" matched cert's IP address!\n", + conn->host.dispname); + } break; } } } GENERAL_NAMES_free(altnames); + + if(dnsmatched || (!dNSName && ipmatched)) { + /* count as a match if the dnsname matched or if there was no dnsname + fields at all AND there was an IP field match */ + matched = TRUE; + } } - if(matched == 1) - /* an alternative name matched the server hostname */ - infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname); - else if(matched == 0) { - /* an alternative name field existed, but didn't match and then - we MUST fail */ - infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname); + if(matched) + /* an alternative name matched */ + ; + else if(dNSName) { + /* an dNSName field existed, but didn't match and then we MUST fail */ + infof(data, " subjectAltName does not match %s\n", conn->host.dispname); failf(data, "SSL: no alternative certificate subject name matches " "target host name '%s'", conn->host.dispname); result = CURLE_PEER_FAILED_VERIFICATION; @@ -1183,7 +1186,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) distinguished one to get the most significant one. */ int j, i=-1; -/* The following is done because of a bug in 0.9.6b */ + /* The following is done because of a bug in 0.9.6b */ unsigned char *nulstr = (unsigned char *)""; unsigned char *peer_CN = nulstr; @@ -1255,7 +1258,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) result = CURLE_PEER_FAILED_VERIFICATION; } else { - infof(data, "\t common name: %s (matched)\n", peer_CN); + infof(data, " common name: %s (matched)\n", peer_CN); } if(peer_CN) OPENSSL_free(peer_CN); @@ -1265,14 +1268,14 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) } #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_IS_BORINGSSL) + !defined(OPENSSL_NO_OCSP) static CURLcode verifystatus(struct connectdata *conn, struct ssl_connect_data *connssl) { int i, ocsp_status; const unsigned char *p; CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; OCSP_RESPONSE *rsp = NULL; OCSP_BASICRESP *br = NULL; @@ -1351,7 +1354,8 @@ static CURLcode verifystatus(struct connectdata *conn, ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; - if(!(single = OCSP_resp_get0(br, i))) + single = OCSP_resp_get0(br, i); + if(!single) continue; cert_status = OCSP_single_get0_status(single, &crl_reason, &rev, @@ -1487,7 +1491,7 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, const void *buf, size_t len, SSL *ssl, void *userp) { - struct SessionHandle *data; + struct Curl_easy *data; const char *msg_name, *tls_rt_name; char ssl_buf[1024]; char unknown[32]; @@ -1620,12 +1624,12 @@ select_next_proto_cb(SSL *ssl, (void)ssl; #ifdef USE_NGHTTP2 - if(conn->data->set.httpversion == CURL_HTTP_VERSION_2_0 && + if(conn->data->set.httpversion >= CURL_HTTP_VERSION_2 && !select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN)) { infof(conn->data, "NPN, negotiated HTTP2 (%s)\n", NGHTTP2_PROTO_VERSION_ID); - conn->negnpn = CURL_HTTP_VERSION_2_0; + conn->negnpn = CURL_HTTP_VERSION_2; return SSL_TLSEXT_ERR_OK; } #endif @@ -1673,9 +1677,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; char *ciphers; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; SSL_METHOD_QUAL SSL_METHOD *req_method = NULL; - void *ssl_sessionid = NULL; X509_LOOKUP *lookup = NULL; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; @@ -1707,7 +1710,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) case CURL_SSLVERSION_TLSv1_2: /* it will be handled later with the context options */ #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ - !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) + !defined(LIBRESSL_VERSION_NUMBER) req_method = TLS_client_method(); #else req_method = SSLv23_client_method(); @@ -1716,7 +1719,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) break; case CURL_SSLVERSION_SSLv2: #ifdef OPENSSL_NO_SSL2 - failf(data, "OpenSSL was built without SSLv2 support"); + failf(data, OSSL_PACKAGE " was built without SSLv2 support"); return CURLE_NOT_BUILT_IN; #else #ifdef USE_TLS_SRP @@ -1729,7 +1732,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #endif case CURL_SSLVERSION_SSLv3: #ifdef OPENSSL_NO_SSL3_METHOD - failf(data, "OpenSSL was built without SSLv3 support"); + failf(data, OSSL_PACKAGE " was built without SSLv3 support"); return CURLE_NOT_BUILT_IN; #else #ifdef USE_TLS_SRP @@ -1887,17 +1890,17 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) SSL_CTX_set_options(connssl->ctx, ctx_options); #ifdef HAS_NPN - if(data->set.ssl_enable_npn) + if(conn->bits.tls_enable_npn) SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb, conn); #endif #ifdef HAS_ALPN - if(data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_alpn) { int cur = 0; unsigned char protocols[128]; #ifdef USE_NGHTTP2 - if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { + if(data->set.httpversion >= CURL_HTTP_VERSION_2) { protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, @@ -1997,6 +2000,13 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]: "none"); } +#ifdef CURL_CA_FALLBACK + else if(data->set.ssl.verifypeer) { + /* verfying the peer without any CA certificates won't + work so use openssl's built in default as fallback */ + SSL_CTX_set_default_verify_paths(connssl->ctx); + } +#endif if(data->set.str[STRING_SSL_CRLFILE]) { /* tell SSL where to find CRL file that is used to check certificate @@ -2063,7 +2073,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) } #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_IS_BORINGSSL) + !defined(OPENSSL_NO_OCSP) if(data->set.ssl.verifystatus) SSL_set_tlsext_status_type(connssl->handle, TLSEXT_STATUSTYPE_ocsp); #endif @@ -2084,15 +2094,22 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #endif /* Check if there's a cached ID we can/should use here! */ - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { - /* we got a session id, use it! */ - if(!SSL_set_session(connssl->handle, ssl_sessionid)) { - failf(data, "SSL: SSL_set_session failed: %s", - ERR_error_string(ERR_get_error(), NULL)); - return CURLE_SSL_CONNECT_ERROR; + if(conn->ssl_config.sessionid) { + void *ssl_sessionid = NULL; + + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { + /* we got a session id, use it! */ + if(!SSL_set_session(connssl->handle, ssl_sessionid)) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "SSL: SSL_set_session failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof (data, "SSL re-using session ID\n"); } - /* Informational message */ - infof (data, "SSL re-using session ID\n"); + Curl_ssl_sessionid_unlock(conn); } /* pass the raw socket into the SSL layers */ @@ -2109,7 +2126,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int err; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; DEBUGASSERT(ssl_connect_2 == connssl->connecting_state @@ -2141,27 +2158,22 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) least 256 bytes long. */ CURLcode result; long lerr; + int lib; + int reason; - connssl->connecting_state = ssl_connect_2; /* the connection failed, - we're not waiting for - anything else. */ - - errdetail = ERR_get_error(); /* Gets the earliest error code from the - thread's error queue and removes the - entry. */ - - switch(errdetail) { - case 0x1407E086: - /* 1407E086: - SSL routines: - SSL2_SET_CERTIFICATE: - certificate verify failed */ - /* fall-through */ - case 0x14090086: - /* 14090086: - SSL routines: - SSL3_GET_SERVER_CERTIFICATE: - certificate verify failed */ + /* the connection failed, we're not waiting for anything else. */ + connssl->connecting_state = ssl_connect_2; + + /* Get the earliest error code from the thread's error queue and removes + the entry. */ + errdetail = ERR_get_error(); + + /* Extract which lib and reason */ + lib = ERR_GET_LIB(errdetail); + reason = ERR_GET_REASON(errdetail); + + if((lib == ERR_LIB_SSL) && + (reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) { result = CURLE_SSL_CACERT; lerr = SSL_get_verify_result(connssl->handle); @@ -2173,13 +2185,11 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) else /* strcpy() is fine here as long as the string fits within error_buffer */ - strcpy(error_buffer, - "SSL certificate problem, check your CA cert"); - break; - default: + strcpy(error_buffer, "SSL certificate verification failed"); + } + else { result = CURLE_SSL_CONNECT_ERROR; - SSL_strerror(errdetail, error_buffer, sizeof(error_buffer)); - break; + ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)); } /* detail is already set to the SSL error above */ @@ -2213,7 +2223,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) /* Sets data and len to negotiated protocol, len is 0 if no protocol was * negotiated */ - if(data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_alpn) { const unsigned char* neg_protocol; unsigned int len; SSL_get0_alpn_selected(connssl->handle, &neg_protocol, &len); @@ -2223,7 +2233,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) #ifdef USE_NGHTTP2 if(len == NGHTTP2_PROTO_VERSION_ID_LEN && !memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len)) { - conn->negnpn = CURL_HTTP_VERSION_2_0; + conn->negnpn = CURL_HTTP_VERSION_2; } else #endif @@ -2256,58 +2266,59 @@ static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) return 0; } -static void pubkey_show(struct SessionHandle *data, +#define push_certinfo(_label, _num) \ +do { \ + long info_len = BIO_get_mem_data(mem, &ptr); \ + Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \ + if(1!=BIO_reset(mem)) \ + break; \ +} WHILE_FALSE + +static void pubkey_show(struct Curl_easy *data, + BIO *mem, int num, const char *type, const char *name, - unsigned char *raw, - int len) +#ifdef HAVE_OPAQUE_RSA_DSA_DH + const +#endif + BIGNUM *bn) { - size_t left; - int i; + char *ptr; char namebuf[32]; - char *buffer; - - left = len*3 + 1; - buffer = malloc(left); - if(buffer) { - char *ptr=buffer; - snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); - for(i=0; i< len; i++) { - snprintf(ptr, left, "%02x:", raw[i]); - ptr += 3; - left -= 3; - } - infof(data, " %s: %s\n", namebuf, buffer); - Curl_ssl_push_certinfo(data, num, namebuf, buffer); - free(buffer); - } + + snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); + + if(bn) + BN_print(mem, bn); + push_certinfo(namebuf, num); } +#ifdef HAVE_OPAQUE_RSA_DSA_DH +#define print_pubkey_BN(_type, _name, _num) \ + pubkey_show(data, mem, _num, #_type, #_name, _name) + +#else #define print_pubkey_BN(_type, _name, _num) \ do { \ - if(pubkey->pkey._type->_name) { \ - int len = BN_num_bytes(pubkey->pkey._type->_name); \ - if(len < CERTBUFFERSIZE) { \ - BN_bn2bin(pubkey->pkey._type->_name, (unsigned char*)bufp); \ - bufp[len] = 0; \ - pubkey_show(data, _num, #_type, #_name, (unsigned char*)bufp, len); \ - } \ + if(_type->_name) { \ + pubkey_show(data, mem, _num, #_type, #_name, _type->_name); \ } \ } WHILE_FALSE +#endif -static int X509V3_ext(struct SessionHandle *data, +static int X509V3_ext(struct Curl_easy *data, int certnum, STACK_OF(X509_EXTENSION) *exts) { int i; size_t j; - if(sk_X509_EXTENSION_num(exts) <= 0) + if((int)sk_X509_EXTENSION_num(exts) <= 0) /* no extensions, bail out */ return 1; - for(i=0; ilength bytes at biomem->data, this little loop here is only - done for the infof() call, we send the "raw" data to the certinfo - function */ - for(j=0; j<(size_t)biomem->length; j++) { + for(j = 0; j < (size_t)biomem->length; j++) { const char *sep=""; if(biomem->data[j] == '\n') { sep=", "; @@ -2346,7 +2351,6 @@ static int X509V3_ext(struct SessionHandle *data, ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep, biomem->data[j]); } - infof(data, " %s\n", buf); Curl_ssl_push_certinfo(data, certnum, namebuf, buf); @@ -2356,46 +2360,6 @@ static int X509V3_ext(struct SessionHandle *data, return 0; /* all is fine */ } - -static void X509_signature(struct SessionHandle *data, - int numcert, - ASN1_STRING *sig) -{ - char buf[1024]; - char *ptr = buf; - int i; - - for(i=0; ilength; i++) - ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%02x:", sig->data[i]); - - infof(data, " Signature: %s\n", buf); - Curl_ssl_push_certinfo(data, numcert, "Signature", buf); -} - -static void dumpcert(struct SessionHandle *data, X509 *x, int numcert) -{ - BIO *bio_out = BIO_new(BIO_s_mem()); - BUF_MEM *biomem; - - /* this outputs the cert in this 64 column wide style with newlines and - -----BEGIN CERTIFICATE----- texts and more */ - PEM_write_bio_X509(bio_out, x); - - BIO_get_mem_ptr(bio_out, &biomem); - - Curl_ssl_push_certinfo_len(data, numcert, - "Cert", biomem->data, biomem->length); - - BIO_free(bio_out); -} - -/* - * This size was previously 512 which has been reported "too small" without - * any specifics, so it was enlarged to allow more data to get shown uncut. - * The "perfect" size is yet to figure out. - */ -#define CERTBUFFERSIZE 8192 - static CURLcode get_cert_chain(struct connectdata *conn, struct ssl_connect_data *connssl) @@ -2403,17 +2367,12 @@ static CURLcode get_cert_chain(struct connectdata *conn, CURLcode result; STACK_OF(X509) *sk; int i; - char *bufp; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int numcerts; - - bufp = malloc(CERTBUFFERSIZE); - if(!bufp) - return CURLE_OUT_OF_MEMORY; + BIO *mem; sk = SSL_get_peer_cert_chain(connssl->handle); if(!sk) { - free(bufp); return CURLE_OUT_OF_MEMORY; } @@ -2421,99 +2380,122 @@ static CURLcode get_cert_chain(struct connectdata *conn, result = Curl_ssl_init_certinfo(data, numcerts); if(result) { - free(bufp); return result; } - infof(data, "--- Certificate chain\n"); - for(i=0; itype == V_ASN1_NEG_INTEGER) + BIO_puts(mem, "-"); + for(j = 0; j < num->length; j++) + BIO_printf(mem, "%02x", num->data[j]); + push_certinfo("Serial Number", i); - ptr = bufp; - if(num->type == V_ASN1_NEG_INTEGER) { - *ptr++='-'; - left--; - } - - for(j=0; (jlength) && (left>=3); j++) { - snprintf(ptr, left, "%02x", num->data[j]); - ptr += 2; - left -= 2; +#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS) + { + X509_ALGOR *palg = NULL; + ASN1_STRING *a = ASN1_STRING_new(); + if(a) { + X509_get0_signature(&psig, &palg, x); + X509_signature_print(mem, palg, a); + ASN1_STRING_free(a); + + if(palg) { + i2a_ASN1_OBJECT(mem, palg->algorithm); + push_certinfo("Public Key Algorithm", i); + } } - if(num->length) - infof(data, " Serial Number: %s\n", bufp); - else - bufp[0]=0; + X509V3_ext(data, i, X509_get0_extensions(x)); } - if(bufp[0]) - Curl_ssl_push_certinfo(data, i, "Serial Number", bufp); /* hex */ - - cinf = x->cert_info; +#else + { + /* before OpenSSL 1.0.2 */ + X509_CINF *cinf = x->cert_info; - j = asn1_object_dump(cinf->signature->algorithm, bufp, CERTBUFFERSIZE); - if(!j) { - infof(data, " Signature Algorithm: %s\n", bufp); - Curl_ssl_push_certinfo(data, i, "Signature Algorithm", bufp); - } + i2a_ASN1_OBJECT(mem, cinf->signature->algorithm); + push_certinfo("Signature Algorithm", i); - certdate = X509_get_notBefore(x); - asn1_output(certdate, bufp, CERTBUFFERSIZE); - infof(data, " Start date: %s\n", bufp); - Curl_ssl_push_certinfo(data, i, "Start date", bufp); + i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm); + push_certinfo("Public Key Algorithm", i); - certdate = X509_get_notAfter(x); - asn1_output(certdate, bufp, CERTBUFFERSIZE); - infof(data, " Expire date: %s\n", bufp); - Curl_ssl_push_certinfo(data, i, "Expire date", bufp); + X509V3_ext(data, i, cinf->extensions); - j = asn1_object_dump(cinf->key->algor->algorithm, bufp, CERTBUFFERSIZE); - if(!j) { - infof(data, " Public Key Algorithm: %s\n", bufp); - Curl_ssl_push_certinfo(data, i, "Public Key Algorithm", bufp); + psig = x->signature; } +#endif + + ASN1_TIME_print(mem, X509_get_notBefore(x)); + push_certinfo("Start date", i); + + ASN1_TIME_print(mem, X509_get_notAfter(x)); + push_certinfo("Expire date", i); pubkey = X509_get_pubkey(x); if(!pubkey) infof(data, " Unable to load public key\n"); else { - switch(pubkey->type) { + int pktype; +#ifdef HAVE_OPAQUE_EVP_PKEY + pktype = EVP_PKEY_id(pubkey); +#else + pktype = pubkey->type; +#endif + switch(pktype) { case EVP_PKEY_RSA: - infof(data, " RSA Public Key (%d bits)\n", - BN_num_bits(pubkey->pkey.rsa->n)); - snprintf(bufp, CERTBUFFERSIZE, "%d", BN_num_bits(pubkey->pkey.rsa->n)); - Curl_ssl_push_certinfo(data, i, "RSA Public Key", bufp); - + { + RSA *rsa; +#ifdef HAVE_OPAQUE_EVP_PKEY + rsa = EVP_PKEY_get0_RSA(pubkey); +#else + rsa = pubkey->pkey.rsa; +#endif + +#ifdef HAVE_OPAQUE_RSA_DSA_DH + { + const BIGNUM *n; + const BIGNUM *e; + const BIGNUM *d; + const BIGNUM *p; + const BIGNUM *q; + const BIGNUM *dmp1; + const BIGNUM *dmq1; + const BIGNUM *iqmp; + + RSA_get0_key(rsa, &n, &e, &d); + RSA_get0_factors(rsa, &p, &q); + RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); + BN_print(mem, n); + push_certinfo("RSA Public Key", i); + print_pubkey_BN(rsa, n, i); + print_pubkey_BN(rsa, e, i); + print_pubkey_BN(rsa, d, i); + print_pubkey_BN(rsa, p, i); + print_pubkey_BN(rsa, q, i); + print_pubkey_BN(rsa, dmp1, i); + print_pubkey_BN(rsa, dmq1, i); + print_pubkey_BN(rsa, iqmp, i); + } +#else + BIO_printf(mem, "%d", BN_num_bits(rsa->n)); + push_certinfo("RSA Public Key", i); print_pubkey_BN(rsa, n, i); print_pubkey_BN(rsa, e, i); print_pubkey_BN(rsa, d, i); @@ -2522,20 +2504,75 @@ static CURLcode get_cert_chain(struct connectdata *conn, print_pubkey_BN(rsa, dmp1, i); print_pubkey_BN(rsa, dmq1, i); print_pubkey_BN(rsa, iqmp, i); +#endif + break; + } case EVP_PKEY_DSA: + { + DSA *dsa; +#ifdef HAVE_OPAQUE_EVP_PKEY + dsa = EVP_PKEY_get0_DSA(pubkey); +#else + dsa = pubkey->pkey.dsa; +#endif +#ifdef HAVE_OPAQUE_RSA_DSA_DH + { + const BIGNUM *p; + const BIGNUM *q; + const BIGNUM *g; + const BIGNUM *priv_key; + const BIGNUM *pub_key; + + DSA_get0_pqg(dsa, &p, &q, &g); + DSA_get0_key(dsa, &pub_key, &priv_key); + + print_pubkey_BN(dsa, p, i); + print_pubkey_BN(dsa, q, i); + print_pubkey_BN(dsa, g, i); + print_pubkey_BN(dsa, priv_key, i); + print_pubkey_BN(dsa, pub_key, i); + } +#else print_pubkey_BN(dsa, p, i); print_pubkey_BN(dsa, q, i); print_pubkey_BN(dsa, g, i); print_pubkey_BN(dsa, priv_key, i); print_pubkey_BN(dsa, pub_key, i); +#endif break; + } case EVP_PKEY_DH: + { + DH *dh; +#ifdef HAVE_OPAQUE_EVP_PKEY + dh = EVP_PKEY_get0_DH(pubkey); +#else + dh = pubkey->pkey.dh; +#endif +#ifdef HAVE_OPAQUE_RSA_DSA_DH + { + const BIGNUM *p; + const BIGNUM *q; + const BIGNUM *g; + const BIGNUM *priv_key; + const BIGNUM *pub_key; + DH_get0_pqg(dh, &p, &q, &g); + DH_get0_key(dh, &pub_key, &priv_key); + print_pubkey_BN(dh, p, i); + print_pubkey_BN(dh, q, i); + print_pubkey_BN(dh, g, i); + print_pubkey_BN(dh, priv_key, i); + print_pubkey_BN(dh, pub_key, i); + } +#else print_pubkey_BN(dh, p, i); print_pubkey_BN(dh, g, i); print_pubkey_BN(dh, priv_key, i); print_pubkey_BN(dh, pub_key, i); +#endif break; + } #if 0 case EVP_PKEY_EC: /* symbol not present in OpenSSL 0.9.6 */ /* left TODO */ @@ -2545,14 +2582,17 @@ static CURLcode get_cert_chain(struct connectdata *conn, EVP_PKEY_free(pubkey); } - X509V3_ext(data, i, cinf->extensions); - - X509_signature(data, i, x->signature); + if(psig) { + for(j = 0; j < psig->length; j++) + BIO_printf(mem, "%02x:", psig->data[j]); + push_certinfo("Signature", i); + } - dumpcert(data, x, i); + PEM_write_bio_X509(mem, x); + push_certinfo("Cert", i); } - free(bufp); + BIO_free(mem); return CURLE_OK; } @@ -2561,7 +2601,8 @@ static CURLcode get_cert_chain(struct connectdata *conn, * Heavily modified from: * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL */ -static CURLcode pkp_pin_peer_pubkey(X509* cert, const char *pinnedpubkey) +static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, + const char *pinnedpubkey) { /* Scratch */ int len1 = 0, len2 = 0; @@ -2606,7 +2647,7 @@ static CURLcode pkp_pin_peer_pubkey(X509* cert, const char *pinnedpubkey) /* End Gyrations */ /* The one good exit point */ - result = Curl_pin_peer_pubkey(pinnedpubkey, buff1, len1); + result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); } while(0); /* https://www.openssl.org/docs/crypto/buffer.html */ @@ -2630,13 +2671,13 @@ static CURLcode servercert(struct connectdata *conn, { CURLcode result = CURLE_OK; int rc; - long lerr; - ASN1_TIME *certdate; - struct SessionHandle *data = conn->data; + long lerr, len; + struct Curl_easy *data = conn->data; X509 *issuer; FILE *fp; char *buffer = data->state.buffer; const char *ptr; + BIO *mem = BIO_new(BIO_s_mem()); if(data->set.ssl.certinfo) /* we've been asked to gather certificate info! */ @@ -2644,8 +2685,10 @@ static CURLcode servercert(struct connectdata *conn, connssl->server_cert = SSL_get_peer_certificate(connssl->handle); if(!connssl->server_cert) { - if(strict) - failf(data, "SSL: couldn't get peer certificate!"); + if(!strict) + return CURLE_OK; + + failf(data, "SSL: couldn't get peer certificate!"); return CURLE_PEER_FAILED_VERIFICATION; } @@ -2653,15 +2696,19 @@ static CURLcode servercert(struct connectdata *conn, rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert), buffer, BUFSIZE); - infof(data, "\t subject: %s\n", rc?"[NONE]":buffer); + infof(data, " subject: %s\n", rc?"[NONE]":buffer); + + ASN1_TIME_print(mem, X509_get_notBefore(connssl->server_cert)); + len = BIO_get_mem_data(mem, (char **) &ptr); + infof(data, " start date: %.*s\n", len, ptr); + rc = BIO_reset(mem); - certdate = X509_get_notBefore(connssl->server_cert); - asn1_output(certdate, buffer, BUFSIZE); - infof(data, "\t start date: %s\n", buffer); + ASN1_TIME_print(mem, X509_get_notAfter(connssl->server_cert)); + len = BIO_get_mem_data(mem, (char **) &ptr); + infof(data, " expire date: %.*s\n", len, ptr); + rc = BIO_reset(mem); - certdate = X509_get_notAfter(connssl->server_cert); - asn1_output(certdate, buffer, BUFSIZE); - infof(data, "\t expire date: %s\n", buffer); + BIO_free(mem); if(data->set.ssl.verifyhost) { result = verifyhost(conn, connssl->server_cert); @@ -2680,7 +2727,7 @@ static CURLcode servercert(struct connectdata *conn, result = CURLE_SSL_CONNECT_ERROR; } else { - infof(data, "\t issuer: %s\n", buffer); + infof(data, " issuer: %s\n", buffer); /* We could do all sorts of certificate verification stuff here before deallocating the certificate. */ @@ -2720,7 +2767,7 @@ static CURLcode servercert(struct connectdata *conn, return CURLE_SSL_ISSUER_ERROR; } - infof(data, "\t SSL certificate issuer check ok (%s)\n", + infof(data, " SSL certificate issuer check ok (%s)\n", data->set.str[STRING_SSL_ISSUERCERT]); X509_free(issuer); } @@ -2738,16 +2785,16 @@ static CURLcode servercert(struct connectdata *conn, result = CURLE_PEER_FAILED_VERIFICATION; } else - infof(data, "\t SSL certificate verify result: %s (%ld)," + infof(data, " SSL certificate verify result: %s (%ld)," " continuing anyway.\n", X509_verify_cert_error_string(lerr), lerr); } else - infof(data, "\t SSL certificate verify ok.\n"); + infof(data, " SSL certificate verify ok.\n"); } #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_IS_BORINGSSL) + !defined(OPENSSL_NO_OCSP) if(data->set.ssl.verifystatus) { result = verifystatus(conn, connssl); if(result) { @@ -2764,7 +2811,7 @@ static CURLcode servercert(struct connectdata *conn, ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; if(!result && ptr) { - result = pkp_pin_peer_pubkey(connssl->server_cert, ptr); + result = pkp_pin_peer_pubkey(data, connssl->server_cert, ptr); if(result) failf(data, "SSL: public key does not match pinned public key!"); } @@ -2779,43 +2826,49 @@ static CURLcode servercert(struct connectdata *conn, static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; - void *old_ssl_sessionid = NULL; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - bool incache; - SSL_SESSION *our_ssl_sessionid; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - our_ssl_sessionid = SSL_get1_session(connssl->handle); + if(conn->ssl_config.sessionid) { + bool incache; + SSL_SESSION *our_ssl_sessionid; + void *old_ssl_sessionid = NULL; - /* SSL_get1_session() will increment the reference count and the session - will stay in memory until explicitly freed with SSL_SESSION_free(3), - regardless of its state. */ + our_ssl_sessionid = SSL_get1_session(connssl->handle); - incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); - if(incache) { - if(old_ssl_sessionid != our_ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - incache = FALSE; + /* SSL_get1_session() will increment the reference count and the session + will stay in memory until explicitly freed with SSL_SESSION_free(3), + regardless of its state. */ + + Curl_ssl_sessionid_lock(conn); + incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); + if(incache) { + if(old_ssl_sessionid != our_ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing\n"); + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + incache = FALSE; + } } - } - if(!incache) { - result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */); - if(result) { - failf(data, "failed to store ssl session"); - return result; + if(!incache) { + result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, + 0 /* unknown size */); + if(result) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "failed to store ssl session"); + return result; + } } - } - else { - /* Session was incache, so refcount already incremented earlier. - * Avoid further increments with each SSL_get1_session() call. - * This does not free the session as refcount remains > 0 - */ - SSL_SESSION_free(our_ssl_sessionid); + else { + /* Session was incache, so refcount already incremented earlier. + * Avoid further increments with each SSL_get1_session() call. + * This does not free the session as refcount remains > 0 + */ + SSL_SESSION_free(our_ssl_sessionid); + } + Curl_ssl_sessionid_unlock(conn); } /* @@ -2843,7 +2896,7 @@ static CURLcode ossl_connect_common(struct connectdata *conn, bool *done) { CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; long timeout_ms; @@ -2987,7 +3040,7 @@ static ssize_t ossl_send(struct connectdata *conn, /* SSL_write() is said to return 'int' while write() and send() returns 'size_t' */ int err; - char error_buffer[120]; /* OpenSSL documents that this must be at least 120 + char error_buffer[256]; /* OpenSSL documents that this must be at least 256 bytes long. */ unsigned long sslerror; int memlen; @@ -3019,7 +3072,7 @@ static ssize_t ossl_send(struct connectdata *conn, The OpenSSL error queue contains more information on the error. */ sslerror = ERR_get_error(); failf(conn->data, "SSL_write() error: %s", - ERR_error_string(sslerror, error_buffer)); + ossl_strerror(sslerror, error_buffer, sizeof(error_buffer))); *curlcode = CURLE_SEND_ERROR; return -1; } @@ -3038,8 +3091,8 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ size_t buffersize, /* max amount to read */ CURLcode *curlcode) { - char error_buffer[120]; /* OpenSSL documents that this must be at - least 120 bytes long. */ + char error_buffer[256]; /* OpenSSL documents that this must be at + least 256 bytes long. */ unsigned long sslerror; ssize_t nread; int buffsize; @@ -3070,7 +3123,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ /* If the return code was negative or there actually is an error in the queue */ failf(conn->data, "SSL read: %s, errno %d", - ERR_error_string(sslerror, error_buffer), + ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)), SOCKERRNO); *curlcode = CURLE_RECV_ERROR; return -1; @@ -3082,86 +3135,45 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ size_t Curl_ossl_version(char *buffer, size_t size) { -#ifdef YASSL_VERSION - /* yassl provides an OpenSSL API compatibility layer so it looks identical - to OpenSSL in all other aspects */ - return snprintf(buffer, size, "yassl/%s", YASSL_VERSION); -#else /* YASSL_VERSION */ #ifdef OPENSSL_IS_BORINGSSL - return snprintf(buffer, size, "BoringSSL"); + return snprintf(buffer, size, OSSL_PACKAGE); #else /* OPENSSL_IS_BORINGSSL */ - -#if(OPENSSL_VERSION_NUMBER >= 0x905000) - { - char sub[3]; - unsigned long ssleay_value; - sub[2]='\0'; - sub[1]='\0'; - ssleay_value=SSLeay(); - if(ssleay_value < 0x906000) { - ssleay_value=SSLEAY_VERSION_NUMBER; - sub[0]='\0'; - } - else { - if(ssleay_value&0xff0) { - int minor_ver = (ssleay_value >> 4) & 0xff; - if(minor_ver > 26) { - /* handle extended version introduced for 0.9.8za */ - sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1); - sub[0] = 'z'; - } - else { - sub[0]=(char)(((ssleay_value>>4)&0xff) + 'a' -1); - } - } - else - sub[0]='\0'; - } - - return snprintf(buffer, size, "%s/%lx.%lx.%lx%s", -#ifdef LIBRESSL_VERSION_NUMBER - "LibreSSL" -#else - "OpenSSL" -#endif - , (ssleay_value>>28)&0xf, - (ssleay_value>>20)&0xff, - (ssleay_value>>12)&0xff, - sub); + char sub[3]; + unsigned long ssleay_value; + sub[2]='\0'; + sub[1]='\0'; + ssleay_value=SSLeay(); + if(ssleay_value < 0x906000) { + ssleay_value=SSLEAY_VERSION_NUMBER; + sub[0]='\0'; } - -#else /* OPENSSL_VERSION_NUMBER is less than 0.9.5 */ - -#if(OPENSSL_VERSION_NUMBER >= 0x900000) - return snprintf(buffer, size, "OpenSSL/%lx.%lx.%lx", - (OPENSSL_VERSION_NUMBER>>28)&0xff, - (OPENSSL_VERSION_NUMBER>>20)&0xff, - (OPENSSL_VERSION_NUMBER>>12)&0xf); - -#else /* (OPENSSL_VERSION_NUMBER >= 0x900000) */ - { - char sub[2]; - sub[1]='\0'; - if(OPENSSL_VERSION_NUMBER&0x0f) { - sub[0]=(OPENSSL_VERSION_NUMBER&0x0f) + 'a' -1; + else { + if(ssleay_value&0xff0) { + int minor_ver = (ssleay_value >> 4) & 0xff; + if(minor_ver > 26) { + /* handle extended version introduced for 0.9.8za */ + sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1); + sub[0] = 'z'; + } + else { + sub[0]=(char)(((ssleay_value>>4)&0xff) + 'a' -1); + } } else sub[0]='\0'; - - return snprintf(buffer, size, "SSL/%x.%x.%x%s", - (OPENSSL_VERSION_NUMBER>>12)&0xff, - (OPENSSL_VERSION_NUMBER>>8)&0xf, - (OPENSSL_VERSION_NUMBER>>4)&0xf, sub); } -#endif /* (OPENSSL_VERSION_NUMBER >= 0x900000) */ -#endif /* OPENSSL_VERSION_NUMBER is less than 0.9.5 */ + return snprintf(buffer, size, "%s/%lx.%lx.%lx%s", + OSSL_PACKAGE, + (ssleay_value>>28)&0xf, + (ssleay_value>>20)&0xff, + (ssleay_value>>12)&0xff, + sub); #endif /* OPENSSL_IS_BORINGSSL */ -#endif /* YASSL_VERSION */ } /* can be called with data == NULL */ -int Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy, +int Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { if(data) { @@ -3183,7 +3195,7 @@ void Curl_ossl_md5sum(unsigned char *tmp, /* input */ MD5_Final(md5sum, &MD5pw); } -#ifndef OPENSSL_NO_SHA256 +#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ size_t tmplen, unsigned char *sha256sum /* output */, @@ -3200,7 +3212,7 @@ void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ bool Curl_ossl_cert_status_request(void) { #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_IS_BORINGSSL) + !defined(OPENSSL_NO_OCSP) return TRUE; #else return FALSE; diff --git a/lib/vtls/openssl.h b/lib/vtls/openssl.h index a1f347a..ee18e71 100644 --- a/lib/vtls/openssl.h +++ b/lib/vtls/openssl.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -41,20 +41,20 @@ void Curl_ossl_close(struct connectdata *conn, int sockindex); /* tell OpenSSL to close down all open information regarding connections (and thus session ID caching etc) */ -void Curl_ossl_close_all(struct SessionHandle *data); +void Curl_ossl_close_all(struct Curl_easy *data); /* Sets an OpenSSL engine */ -CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine); +CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine); /* function provided for the generic SSL-layer, called when a session id should be freed */ void Curl_ossl_session_free(void *ptr); /* Sets engine as default for all SSL operations */ -CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data); +CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data); /* Build list of OpenSSL engines */ -struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data); +struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data); int Curl_ossl_init(void); void Curl_ossl_cleanup(void); @@ -66,7 +66,7 @@ bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex); /* return 0 if a find random is filled in */ -int Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy, +int Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy, size_t length); void Curl_ossl_md5sum(unsigned char *tmp, /* input */ size_t tmplen, @@ -88,9 +88,12 @@ bool Curl_ossl_cert_status_request(void); /* this backend supports CURLOPT_CERTINFO */ #define have_curlssl_certinfo 1 -/* this backend suppots CURLOPT_SSL_CTX_* */ +/* this backend supports CURLOPT_SSL_CTX_* */ #define have_curlssl_ssl_ctx 1 +/* this backend supports CURLOPT_PINNEDPUBLICKEY */ +#define have_curlssl_pinnedpubkey 1 + /* API setup for OpenSSL */ #define curlssl_init Curl_ossl_init #define curlssl_cleanup Curl_ossl_cleanup @@ -108,7 +111,7 @@ bool Curl_ossl_cert_status_request(void); #define curlssl_data_pending(x,y) Curl_ossl_data_pending(x,y) #define curlssl_random(x,y,z) Curl_ossl_random(x,y,z) #define curlssl_md5sum(a,b,c,d) Curl_ossl_md5sum(a,b,c,d) -#ifndef OPENSSL_NO_SHA256 +#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) #define curlssl_sha256sum(a,b,c,d) Curl_ossl_sha256sum(a,b,c,d) #endif #define curlssl_cert_status_request() Curl_ossl_cert_status_request() diff --git a/lib/vtls/polarssl.c b/lib/vtls/polarssl.c index 066c055..d33f548 100644 --- a/lib/vtls/polarssl.c +++ b/lib/vtls/polarssl.c @@ -5,12 +5,12 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. * Copyright (C) 2010 - 2011, Hoi-Ho Chan, - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -36,6 +36,7 @@ #include #include #include +#include #if POLARSSL_VERSION_NUMBER < 0x01030000 #error too old PolarSSL @@ -60,6 +61,15 @@ /* The last #include file should be: */ #include "memdebug.h" +/* See https://tls.mbed.org/discussions/generic/ + howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der +*/ +#define RSA_PUB_DER_MAX_BYTES (38 + 2 * POLARSSL_MPI_MAX_SIZE) +#define ECP_PUB_DER_MAX_BYTES (30 + 2 * POLARSSL_ECP_MAX_BYTES) + +#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ + RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES) + /* apply threading? */ #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) #define THREADING_SUPPORT @@ -74,12 +84,12 @@ static int entropy_init_initialized = 0; static void entropy_init_mutex(entropy_context *ctx) { /* lock 0 = entropy_init_mutex() */ - polarsslthreadlock_lock_function(0); + Curl_polarsslthreadlock_lock_function(0); if(entropy_init_initialized == 0) { entropy_init(ctx); entropy_init_initialized = 1; } - polarsslthreadlock_unlock_function(0); + Curl_polarsslthreadlock_unlock_function(0); } /* end of entropy_init_mutex() */ @@ -88,9 +98,9 @@ static int entropy_func_mutex(void *data, unsigned char *output, size_t len) { int ret; /* lock 1 = entropy_func_mutex() */ - polarsslthreadlock_lock_function(1); + Curl_polarsslthreadlock_lock_function(1); ret = entropy_func(data, output, len); - polarsslthreadlock_unlock_function(1); + Curl_polarsslthreadlock_unlock_function(1); return ret; } @@ -104,12 +114,12 @@ static int entropy_func_mutex(void *data, unsigned char *output, size_t len) #ifdef POLARSSL_DEBUG static void polarssl_debug(void *context, int level, const char *line) { - struct SessionHandle *data = NULL; + struct Curl_easy *data = NULL; if(!context) return; - data = (struct SessionHandle *)context; + data = (struct Curl_easy *)context; infof(data, "%s", line); (void) level; @@ -130,7 +140,7 @@ static CURLcode polarssl_connect_step1(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; bool sni = TRUE; /* default is SNI enabled */ @@ -140,8 +150,6 @@ polarssl_connect_step1(struct connectdata *conn, #else struct in_addr addr; #endif - void *old_session = NULL; - size_t old_session_size = 0; char errorbuf[128]; errorbuf[0]=0; @@ -157,7 +165,7 @@ polarssl_connect_step1(struct connectdata *conn, entropy_init_mutex(&entropy); if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func_mutex, &entropy, - connssl->ssn.id, connssl->ssn.length)) != 0) { + NULL, 0)) != 0) { #ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* POLARSSL_ERROR_C */ @@ -168,7 +176,7 @@ polarssl_connect_step1(struct connectdata *conn, entropy_init(&connssl->entropy); if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func, &connssl->entropy, - connssl->ssn.id, connssl->ssn.length)) != 0) { + NULL, 0)) != 0) { #ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* POLARSSL_ERROR_C */ @@ -328,13 +336,22 @@ polarssl_connect_step1(struct connectdata *conn, net_send, &conn->sock[sockindex]); ssl_set_ciphersuites(&connssl->ssl, ssl_list_ciphersuites()); - if(!Curl_ssl_getsessionid(conn, &old_session, &old_session_size)) { - memcpy(&connssl->ssn, old_session, old_session_size); - infof(data, "PolarSSL re-using session\n"); - } - ssl_set_session(&connssl->ssl, - &connssl->ssn); + /* Check if there's a cached ID we can/should use here! */ + if(conn->ssl_config.sessionid) { + void *old_session = NULL; + + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) { + ret = ssl_set_session(&connssl->ssl, old_session); + Curl_ssl_sessionid_unlock(conn); + if(ret) { + failf(data, "ssl_set_session returned -0x%x", -ret); + return CURLE_SSL_CONNECT_ERROR; + } + infof(data, "PolarSSL re-using session\n"); + } + } ssl_set_ca_chain(&connssl->ssl, &connssl->cacert, @@ -344,22 +361,21 @@ polarssl_connect_step1(struct connectdata *conn, ssl_set_own_cert_rsa(&connssl->ssl, &connssl->clicert, &connssl->rsa); - if(!Curl_inet_pton(AF_INET, conn->host.name, &addr) && -#ifdef ENABLE_IPV6 - !Curl_inet_pton(AF_INET6, conn->host.name, &addr) && -#endif - sni && ssl_set_hostname(&connssl->ssl, conn->host.name)) { - infof(data, "WARNING: failed to configure " - "server name indication (SNI) TLS extension\n"); + if(ssl_set_hostname(&connssl->ssl, conn->host.name)) { + /* ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name + to set in the SNI extension. So even if curl connects to a host + specified as an IP address, this function must be used. */ + failf(data, "couldn't set hostname in PolarSSL"); + return CURLE_SSL_CONNECT_ERROR; } #ifdef HAS_ALPN - if(data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_alpn) { static const char* protocols[3]; int cur = 0; #ifdef USE_NGHTTP2 - if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { + if(data->set.httpversion >= CURL_HTTP_VERSION_2) { protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } @@ -388,7 +404,7 @@ polarssl_connect_step2(struct connectdata *conn, int sockindex) { int ret; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; char buffer[1024]; @@ -453,8 +469,63 @@ polarssl_connect_step2(struct connectdata *conn, infof(data, "Dumping cert info:\n%s\n", buffer); } + /* adapted from mbedtls.c */ + if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { + int size; + CURLcode result; + x509_crt *p; + unsigned char pubkey[PUB_DER_MAX_BYTES]; + const x509_crt *peercert; + + peercert = ssl_get_peer_cert(&connssl->ssl); + + if(!peercert || !peercert->raw.p || !peercert->raw.len) { + failf(data, "Failed due to missing peer certificate"); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + p = calloc(1, sizeof(*p)); + + if(!p) + return CURLE_OUT_OF_MEMORY; + + x509_crt_init(p); + + /* Make a copy of our const peercert because pk_write_pubkey_der + needs a non-const key, for now. + https://github.com/ARMmbed/mbedtls/issues/396 */ + if(x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { + failf(data, "Failed copying peer certificate"); + x509_crt_free(p); + free(p); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + size = pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); + + if(size <= 0) { + failf(data, "Failed copying public key from peer certificate"); + x509_crt_free(p); + free(p); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + /* pk_write_pubkey_der writes data at the end of the buffer. */ + result = Curl_pin_peer_pubkey(data, + data->set.str[STRING_SSL_PINNEDPUBLICKEY], + &pubkey[PUB_DER_MAX_BYTES - size], size); + if(result) { + x509_crt_free(p); + free(p); + return result; + } + + x509_crt_free(p); + free(p); + } + #ifdef HAS_ALPN - if(data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_alpn) { const char *next_protocol = ssl_get_alpn_protocol(&connssl->ssl); if(next_protocol != NULL) { @@ -463,7 +534,7 @@ polarssl_connect_step2(struct connectdata *conn, #ifdef USE_NGHTTP2 if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN)) { - conn->negnpn = CURL_HTTP_VERSION_2_0; + conn->negnpn = CURL_HTTP_VERSION_2; } else #endif @@ -486,39 +557,40 @@ static CURLcode polarssl_connect_step3(struct connectdata *conn, int sockindex) { - CURLcode result = CURLE_OK; + CURLcode retcode = CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; - void *old_ssl_sessionid = NULL; - ssl_session *our_ssl_sessionid = &conn->ssl[sockindex].ssn; - bool incache; + struct Curl_easy *data = conn->data; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - /* Save the current session data for possible re-use */ - incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); - if(incache) { - if(old_ssl_sessionid != our_ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - incache = FALSE; - } - } + if(conn->ssl_config.sessionid) { + int ret; + ssl_session *our_ssl_sessionid; + void *old_ssl_sessionid = NULL; - if(!incache) { - void *new_session = malloc(sizeof(ssl_session)); + our_ssl_sessionid = malloc(sizeof(ssl_session)); + if(!our_ssl_sessionid) + return CURLE_OUT_OF_MEMORY; - if(new_session) { - memcpy(new_session, our_ssl_sessionid, sizeof(ssl_session)); + ssl_session_init(our_ssl_sessionid); - result = Curl_ssl_addsessionid(conn, new_session, sizeof(ssl_session)); + ret = ssl_get_session(&connssl->ssl, our_ssl_sessionid); + if(ret) { + failf(data, "ssl_get_session returned -0x%x", -ret); + return CURLE_SSL_CONNECT_ERROR; } - else - result = CURLE_OUT_OF_MEMORY; - if(result) { + /* If there's already a matching session in the cache, delete it */ + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)) + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + + retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0); + Curl_ssl_sessionid_unlock(conn); + if(retcode) { + free(our_ssl_sessionid); failf(data, "failed to store ssl session"); - return result; + return retcode; } } @@ -584,6 +656,7 @@ static ssize_t polarssl_recv(struct connectdata *conn, void Curl_polarssl_session_free(void *ptr) { + ssl_session_free(ptr); free(ptr); } @@ -605,7 +678,7 @@ polarssl_connect_common(struct connectdata *conn, bool *done) { CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; long timeout_ms; @@ -740,14 +813,14 @@ Curl_polarssl_connect(struct connectdata *conn, * return 0 error initializing SSL * return 1 SSL initialized successfully */ -int polarssl_init(void) +int Curl_polarssl_init(void) { - return polarsslthreadlock_thread_setup(); + return Curl_polarsslthreadlock_thread_setup(); } -void polarssl_cleanup(void) +void Curl_polarssl_cleanup(void) { - (void)polarsslthreadlock_thread_cleanup(); + (void)Curl_polarsslthreadlock_thread_cleanup(); } #endif /* USE_POLARSSL */ diff --git a/lib/vtls/polarssl.h b/lib/vtls/polarssl.h index f980dbb..7098b24 100644 --- a/lib/vtls/polarssl.h +++ b/lib/vtls/polarssl.h @@ -7,12 +7,12 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. * Copyright (C) 2010, Hoi-Ho Chan, - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,9 +26,11 @@ #ifdef USE_POLARSSL +#include + /* Called on first use PolarSSL, setup threading if supported */ -int polarssl_init(void); -void polarssl_cleanup(void); +int Curl_polarssl_init(void); +void Curl_polarssl_cleanup(void); CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex); @@ -50,9 +52,12 @@ int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex); /* this backend supports the CAPATH option */ #define have_curlssl_ca_path 1 +/* this backends supports CURLOPT_PINNEDPUBLICKEY */ +#define have_curlssl_pinnedpubkey 1 + /* API setup for PolarSSL */ -#define curlssl_init() polarssl_init() -#define curlssl_cleanup() polarssl_cleanup() +#define curlssl_init() Curl_polarssl_init() +#define curlssl_cleanup() Curl_polarssl_cleanup() #define curlssl_connect Curl_polarssl_connect #define curlssl_connect_nonblocking Curl_polarssl_connect_nonblocking #define curlssl_session_free(x) Curl_polarssl_session_free(x) @@ -65,6 +70,7 @@ int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex); #define curlssl_version Curl_polarssl_version #define curlssl_check_cxn(x) ((void)x, -1) #define curlssl_data_pending(x,y) ((void)x, (void)y, 0) +#define curlssl_sha256sum(a,b,c,d) sha256(a,b,c,0) /* This might cause libcurl to use a weeker random! TODO: implement proper use of Polarssl's CTR-DRBG or HMAC-DRBG and use that diff --git a/lib/vtls/polarssl_threadlock.c b/lib/vtls/polarssl_threadlock.c index 62abf43..3b0ebf8 100644 --- a/lib/vtls/polarssl_threadlock.c +++ b/lib/vtls/polarssl_threadlock.c @@ -5,12 +5,12 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * + * Copyright (C) 2013-2015, Daniel Stenberg, , et al. * Copyright (C) 2010, 2011, Hoi-Ho Chan, - * Copyright (C) 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,7 +22,7 @@ ***************************************************************************/ #include "curl_setup.h" -#if defined(USE_POLARSSL) && \ +#if (defined(USE_POLARSSL) || defined(USE_MBEDTLS)) && \ (defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)) #if defined(USE_THREADS_POSIX) @@ -47,7 +47,7 @@ /* This array will store all of the mutexes available to PolarSSL. */ static POLARSSL_MUTEX_T *mutex_buf = NULL; -int polarsslthreadlock_thread_setup(void) +int Curl_polarsslthreadlock_thread_setup(void) { int i; int ret; @@ -73,7 +73,7 @@ int polarsslthreadlock_thread_setup(void) return 1; /* OK */ } -int polarsslthreadlock_thread_cleanup(void) +int Curl_polarsslthreadlock_thread_cleanup(void) { int i; int ret; @@ -100,7 +100,7 @@ int polarsslthreadlock_thread_cleanup(void) return 1; /* OK */ } -int polarsslthreadlock_lock_function(int n) +int Curl_polarsslthreadlock_lock_function(int n) { int ret; #ifdef HAVE_PTHREAD_H @@ -125,7 +125,7 @@ int polarsslthreadlock_lock_function(int n) return 1; /* OK */ } -int polarsslthreadlock_unlock_function(int n) +int Curl_polarsslthreadlock_unlock_function(int n) { int ret; #ifdef HAVE_PTHREAD_H @@ -150,4 +150,4 @@ int polarsslthreadlock_unlock_function(int n) return 1; /* OK */ } -#endif /* USE_POLARSSL */ +#endif /* USE_POLARSSL || USE_MBEDTLS */ diff --git a/lib/vtls/polarssl_threadlock.h b/lib/vtls/polarssl_threadlock.h index b67b3f9..dda5359 100644 --- a/lib/vtls/polarssl_threadlock.h +++ b/lib/vtls/polarssl_threadlock.h @@ -7,12 +7,12 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * + * Copyright (C) 2013-2015, Daniel Stenberg, , et al. * Copyright (C) 2010, Hoi-Ho Chan, - * Copyright (C) 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -24,7 +24,7 @@ ***************************************************************************/ #include "curl_setup.h" -#ifdef USE_POLARSSL +#if (defined USE_POLARSSL) || (defined USE_MBEDTLS) #if defined(USE_THREADS_POSIX) # define POLARSSL_MUTEX_T pthread_mutex_t @@ -34,17 +34,17 @@ #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) -int polarsslthreadlock_thread_setup(void); -int polarsslthreadlock_thread_cleanup(void); -int polarsslthreadlock_lock_function(int n); -int polarsslthreadlock_unlock_function(int n); +int Curl_polarsslthreadlock_thread_setup(void); +int Curl_polarsslthreadlock_thread_cleanup(void); +int Curl_polarsslthreadlock_lock_function(int n); +int Curl_polarsslthreadlock_unlock_function(int n); #else -#define polarsslthreadlock_thread_setup() 1 -#define polarsslthreadlock_thread_cleanup() 1 -#define polarsslthreadlock_lock_function(x) 1 -#define polarsslthreadlock_unlock_function(x) 1 +#define Curl_polarsslthreadlock_thread_setup() 1 +#define Curl_polarsslthreadlock_thread_cleanup() 1 +#define Curl_polarsslthreadlock_lock_function(x) 1 +#define Curl_polarsslthreadlock_unlock_function(x) 1 #endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */ diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 2174e21..f991ec9 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -5,13 +5,13 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2015, Marc Hoersken, + * Copyright (C) 2012 - 2016, Marc Hoersken, * Copyright (C) 2012, Mark Salisbury, - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -56,11 +56,23 @@ #include "inet_pton.h" /* for IP addr SNI check */ #include "curl_multibyte.h" #include "warnless.h" +#include "x509asn1.h" #include "curl_printf.h" +#include "system_win32.h" + + /* The last #include file should be: */ #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" +/* ALPN requires version 8.1 of the Windows SDK, which was + shipped with Visual Studio 2013, aka _MSC_VER 1800: + + https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx +*/ +#if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_) +# define HAS_ALPN 1 +#endif + /* Uncomment to force verbose output * #define infof(x, y, ...) printf(y, __VA_ARGS__) * #define failf(x, y, ...) printf(y, __VA_ARGS__) @@ -93,10 +105,15 @@ static CURLcode schannel_connect_step1(struct connectdata *conn, int sockindex) { ssize_t written = -1; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; SecBuffer outbuf; SecBufferDesc outbuf_desc; + SecBuffer inbuf; + SecBufferDesc inbuf_desc; +#ifdef HAS_ALPN + unsigned char alpn_buffer[128]; +#endif SCHANNEL_CRED schannel_cred; SECURITY_STATUS sspi_status = SEC_E_OK; struct curl_schannel_cred *old_cred = NULL; @@ -110,12 +127,24 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n", conn->host.name, conn->remote_port); + connssl->cred = NULL; + /* check for an existing re-usable credential handle */ - if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)) { - connssl->cred = old_cred; - infof(data, "schannel: re-using existing credential handle\n"); + if(conn->ssl_config.sessionid) { + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)) { + connssl->cred = old_cred; + infof(data, "schannel: re-using existing credential handle\n"); + + /* increment the reference counter of the credential/session handle */ + connssl->cred->refcount++; + infof(data, "schannel: incremented credential handle refcount = %d\n", + connssl->cred->refcount); + } + Curl_ssl_sessionid_unlock(conn); } - else { + + if(!connssl->cred) { /* setup Schannel API options */ memset(&schannel_cred, 0, sizeof(schannel_cred)); schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; @@ -188,8 +217,10 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) return CURLE_OUT_OF_MEMORY; } memset(connssl->cred, 0, sizeof(struct curl_schannel_cred)); + connssl->cred->refcount = 1; - /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */ + /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx + */ sspi_status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, @@ -218,6 +249,63 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) infof(data, "schannel: using IP address, SNI is not supported by OS.\n"); } +#ifdef HAS_ALPN + /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above */ + if(conn->bits.tls_enable_alpn && + Curl_verify_windows_version(6, 3, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) { + int cur = 0; + int list_start_index = 0; + unsigned int* extension_len = NULL; + unsigned short* list_len = NULL; + + /* The first four bytes will be an unsigned int indicating number + of bytes of data in the rest of the the buffer. */ + extension_len = (unsigned int*)(&alpn_buffer[cur]); + cur += sizeof(unsigned int); + + /* The next four bytes are an indicator that this buffer will contain + ALPN data, as opposed to NPN, for example. */ + *(unsigned int*)&alpn_buffer[cur] = + SecApplicationProtocolNegotiationExt_ALPN; + cur += sizeof(unsigned int); + + /* The next two bytes will be an unsigned short indicating the number + of bytes used to list the preferred protocols. */ + list_len = (unsigned short*)(&alpn_buffer[cur]); + cur += sizeof(unsigned short); + + list_start_index = cur; + +#ifdef USE_NGHTTP2 + if(data->set.httpversion >= CURL_HTTP_VERSION_2) { + memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN); + cur += NGHTTP2_PROTO_ALPN_LEN; + infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); + } +#endif + + alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH; + memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); + cur += ALPN_HTTP_1_1_LENGTH; + infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1); + + *list_len = curlx_uitous(cur - list_start_index); + *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short); + + InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur); + InitSecBufferDesc(&inbuf_desc, &inbuf, 1); + } + else + { + InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&inbuf_desc, &inbuf, 1); + } +#else /* HAS_ALPN */ + InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&inbuf_desc, &inbuf, 1); +#endif + /* setup output buffer */ InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&outbuf_desc, &outbuf, 1); @@ -240,11 +328,11 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) if(!host_name) return CURLE_OUT_OF_MEMORY; - /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */ + /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */ sspi_status = s_pSecFn->InitializeSecurityContext( &connssl->cred->cred_handle, NULL, host_name, - connssl->req_flags, 0, 0, NULL, 0, &connssl->ctxt->ctxt_handle, + connssl->req_flags, 0, 0, &inbuf_desc, 0, &connssl->ctxt->ctxt_handle, &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp); Curl_unicodefree(host_name); @@ -291,7 +379,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) { int i; ssize_t nread = -1, written = -1; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; unsigned char *reallocated_buffer; size_t reallocated_length; @@ -407,8 +495,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) if(!host_name) return CURLE_OUT_OF_MEMORY; - /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */ - + /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx + */ sspi_status = s_pSecFn->InitializeSecurityContext( &connssl->cred->cred_handle, &connssl->ctxt->ctxt_handle, host_name, connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL, @@ -531,10 +619,13 @@ static CURLcode schannel_connect_step3(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct curl_schannel_cred *old_cred = NULL; - bool incache; + SECURITY_STATUS sspi_status = SEC_E_OK; + CERT_CONTEXT *ccert_context = NULL; +#ifdef HAS_ALPN + SecPkgContext_ApplicationProtocol alpn_result; +#endif DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); @@ -559,34 +650,98 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) return CURLE_SSL_CONNECT_ERROR; } - /* increment the reference counter of the credential/session handle */ - if(connssl->cred && connssl->ctxt) { - connssl->cred->refcount++; - infof(data, "schannel: incremented credential handle refcount = %d\n", - connssl->cred->refcount); +#ifdef HAS_ALPN + /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above */ + if(conn->bits.tls_enable_alpn && + Curl_verify_windows_version(6, 3, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) { + sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, + SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); + + if(sspi_status != SEC_E_OK) { + failf(data, "schannel: failed to retrieve ALPN result"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(alpn_result.ProtoNegoStatus == + SecApplicationProtocolNegotiationStatus_Success) { + + infof(data, "schannel: ALPN, server accepted to use %.*s\n", + alpn_result.ProtocolIdSize, alpn_result.ProtocolId); + +#ifdef USE_NGHTTP2 + if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN && + !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId, + NGHTTP2_PROTO_VERSION_ID_LEN)) { + conn->negnpn = CURL_HTTP_VERSION_2; + } + else +#endif + if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH && + !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId, + ALPN_HTTP_1_1_LENGTH)) { + conn->negnpn = CURL_HTTP_VERSION_1_1; + } + } + else + infof(data, "ALPN, server did not agree to a protocol\n"); } +#endif /* save the current session data for possible re-use */ - incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)); - if(incache) { - if(old_cred != connssl->cred) { - infof(data, "schannel: old credential handle is stale, removing\n"); - Curl_ssl_delsessionid(conn, (void *)old_cred); - incache = FALSE; + if(conn->ssl_config.sessionid) { + bool incache; + struct curl_schannel_cred *old_cred = NULL; + + Curl_ssl_sessionid_lock(conn); + incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)); + if(incache) { + if(old_cred != connssl->cred) { + infof(data, "schannel: old credential handle is stale, removing\n"); + /* we're not taking old_cred ownership here, no refcount++ is needed */ + Curl_ssl_delsessionid(conn, (void *)old_cred); + incache = FALSE; + } } + if(!incache) { + result = Curl_ssl_addsessionid(conn, (void *)connssl->cred, + sizeof(struct curl_schannel_cred)); + if(result) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "schannel: failed to store credential handle"); + return result; + } + else { + /* this cred session is now also referenced by sessionid cache */ + connssl->cred->refcount++; + infof(data, "schannel: stored credential handle in session cache\n"); + } + } + Curl_ssl_sessionid_unlock(conn); } - if(!incache) { - result = Curl_ssl_addsessionid(conn, (void *)connssl->cred, - sizeof(struct curl_schannel_cred)); - if(result) { - failf(data, "schannel: failed to store credential handle"); - return result; + if(data->set.ssl.certinfo) { + sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, + SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context); + + if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) { + failf(data, "schannel: failed to retrieve remote cert context"); + return CURLE_SSL_CONNECT_ERROR; } - else { - connssl->cred->cached = TRUE; - infof(data, "schannel: stored credential handle in session cache\n"); + + result = Curl_ssl_init_certinfo(data, 1); + if(!result) { + if(((ccert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) && + (ccert_context->cbCertEncoded > 0)) { + + const char *beg = (const char *) ccert_context->pbCertEncoded; + const char *end = beg + ccert_context->cbCertEncoded; + result = Curl_extract_certinfo(conn, 0, beg, end); + } } + CertFreeCertificateContext(ccert_context); + if(result) + return result; } connssl->connecting_state = ssl_connect_done; @@ -599,7 +754,7 @@ schannel_connect_common(struct connectdata *conn, int sockindex, bool nonblocking, bool *done) { CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; long timeout_ms; @@ -759,7 +914,7 @@ schannel_send(struct connectdata *conn, int sockindex, /* copy data into output buffer */ memcpy(outbuf[1].pvBuffer, buf, len); - /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */ + /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */ sspi_status = s_pSecFn->EncryptMessage(&connssl->ctxt->ctxt_handle, 0, &outbuf_desc, 0); @@ -858,7 +1013,7 @@ schannel_recv(struct connectdata *conn, int sockindex, { size_t size = 0; ssize_t nread = -1; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; unsigned char *reallocated_buffer; size_t reallocated_length; @@ -973,7 +1128,8 @@ schannel_recv(struct connectdata *conn, int sockindex, InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&inbuf_desc, inbuf, 4); - /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */ + /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx + */ sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle, &inbuf_desc, 0, NULL); @@ -1120,23 +1276,8 @@ cleanup: */ if(len && !connssl->decdata_offset && connssl->recv_connection_closed && !connssl->recv_sspi_close_notify) { - BOOL isWin2k; - ULONGLONG cm; - OSVERSIONINFOEX osver; - - memset(&osver, 0, sizeof(osver)); - osver.dwOSVersionInfoSize = sizeof(osver); - osver.dwMajorVersion = 5; - - cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); - cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_EQUAL); - cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); - cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); - - isWin2k = VerifyVersionInfo(&osver, - (VER_MAJORVERSION | VER_MINORVERSION | - VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), - cm); + bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT, + VERSION_EQUAL); if(isWin2k && sspi_status == SEC_E_OK) connssl->recv_sspi_close_notify = true; @@ -1204,7 +1345,7 @@ bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex) if(connssl->use) /* SSL/TLS is in use */ return (connssl->encdata_offset > 0 || - connssl->decdata_offset > 0 ) ? TRUE : FALSE; + connssl->decdata_offset > 0) ? TRUE : FALSE; else return FALSE; } @@ -1218,10 +1359,10 @@ void Curl_schannel_close(struct connectdata *conn, int sockindex) int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) { - /* See http://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx + /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx * Shutting Down an Schannel Connection */ - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n", @@ -1294,19 +1435,10 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) /* free SSPI Schannel API credential handle */ if(connssl->cred) { - /* decrement the reference counter of the credential/session handle */ - if(connssl->cred->refcount > 0) { - connssl->cred->refcount--; - infof(data, "schannel: decremented credential handle refcount = %d\n", - connssl->cred->refcount); - } - - /* if the handle was not cached and the refcount is zero */ - if(!connssl->cred->cached && connssl->cred->refcount == 0) { - infof(data, "schannel: clear credential handle\n"); - s_pSecFn->FreeCredentialsHandle(&connssl->cred->cred_handle); - Curl_safefree(connssl->cred); - } + Curl_ssl_sessionid_lock(conn); + Curl_schannel_session_free(connssl->cred); + Curl_ssl_sessionid_unlock(conn); + connssl->cred = NULL; } /* free internal buffer for received encrypted data */ @@ -1328,16 +1460,13 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) void Curl_schannel_session_free(void *ptr) { + /* this is expected to be called under sessionid lock */ struct curl_schannel_cred *cred = ptr; - if(cred && cred->cached) { - if(cred->refcount == 0) { - s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); - Curl_safefree(cred); - } - else { - cred->cached = FALSE; - } + cred->refcount--; + if(cred->refcount == 0) { + s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); + Curl_safefree(cred); } } @@ -1379,7 +1508,7 @@ int Curl_schannel_random(unsigned char *entropy, size_t length) static CURLcode verify_certificate(struct connectdata *conn, int sockindex) { SECURITY_STATUS status; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CURLcode result = CURLE_OK; CERT_CONTEXT *pCertContextServer = NULL; diff --git a/lib/vtls/schannel.h b/lib/vtls/schannel.h index 5329584..8a4991e 100644 --- a/lib/vtls/schannel.h +++ b/lib/vtls/schannel.h @@ -12,7 +12,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -97,6 +97,9 @@ int Curl_schannel_random(unsigned char *entropy, size_t length); /* Set the API backend definition to Schannel */ #define CURL_SSL_BACKEND CURLSSLBACKEND_SCHANNEL +/* this backend supports CURLOPT_CERTINFO */ +#define have_curlssl_certinfo 1 + /* API setup for Schannel */ #define curlssl_init Curl_schannel_init #define curlssl_cleanup Curl_schannel_cleanup diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 01bbc61..3863777 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -41,7 +41,7 @@ defines/macros #defined by the lib-specific header files. "SSL/TLS Strong Encryption: An Introduction" - http://httpd.apache.org/docs-2.0/ssl/ssl_intro.html + https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html */ #include "curl_setup.h" @@ -99,6 +99,7 @@ Curl_ssl_config_matches(struct ssl_config_data* data, (data->verifyhost == needle->verifyhost) && safe_strequal(data->CApath, needle->CApath) && safe_strequal(data->CAfile, needle->CAfile) && + safe_strequal(data->clientcert, needle->clientcert) && safe_strequal(data->random_file, needle->random_file) && safe_strequal(data->egdsocket, needle->egdsocket) && safe_strequal(data->cipher_list, needle->cipher_list)) @@ -156,6 +157,15 @@ Curl_clone_ssl_config(struct ssl_config_data *source, else dest->random_file = NULL; + if(source->clientcert) { + dest->clientcert = strdup(source->clientcert); + if(!dest->clientcert) + return FALSE; + dest->sessionid = FALSE; + } + else + dest->clientcert = NULL; + return TRUE; } @@ -166,6 +176,7 @@ void Curl_free_ssl_config(struct ssl_config_data* sslc) Curl_safefree(sslc->cipher_list); Curl_safefree(sslc->egdsocket); Curl_safefree(sslc->random_file); + Curl_safefree(sslc->clientcert); } @@ -181,7 +192,7 @@ void Curl_free_ssl_config(struct ssl_config_data* sslc) * */ -unsigned int Curl_rand(struct SessionHandle *data) +unsigned int Curl_rand(struct Curl_easy *data) { unsigned int r = 0; static unsigned int randseed; @@ -276,7 +287,7 @@ void Curl_ssl_cleanup(void) } } -static bool ssl_prefs_check(struct SessionHandle *data) +static bool ssl_prefs_check(struct Curl_easy *data) { /* check for CURLOPT_SSLVERSION invalid parameter value */ if((data->set.ssl.version < 0) @@ -330,6 +341,25 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, } /* + * Lock shared SSL session data + */ +void Curl_ssl_sessionid_lock(struct connectdata *conn) +{ + if(SSLSESSION_SHARED(conn->data)) + Curl_share_lock(conn->data, + CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); +} + +/* + * Unlock shared SSL session data + */ +void Curl_ssl_sessionid_unlock(struct connectdata *conn) +{ + if(SSLSESSION_SHARED(conn->data)) + Curl_share_unlock(conn->data, CURL_LOCK_DATA_SSL_SESSION); +} + +/* * Check if there's a session ID for the given connection in the cache, and if * there's one suitable, it is provided. Returns TRUE when no entry matched. */ @@ -338,22 +368,22 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, size_t *idsize) /* set 0 if unknown */ { struct curl_ssl_session *check; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; size_t i; long *general_age; bool no_match = TRUE; *ssl_sessionid = NULL; + DEBUGASSERT(conn->ssl_config.sessionid); + if(!conn->ssl_config.sessionid) /* session ID re-use is disabled */ return TRUE; /* Lock if shared */ - if(SSLSESSION_SHARED(data)) { - Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); + if(SSLSESSION_SHARED(data)) general_age = &data->share->sessionage; - } else general_age = &data->state.sessionage; @@ -363,6 +393,12 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, /* not session ID means blank entry */ continue; if(Curl_raw_equal(conn->host.name, check->name) && + ((!conn->bits.conn_to_host && !check->conn_to_host) || + (conn->bits.conn_to_host && check->conn_to_host && + Curl_raw_equal(conn->conn_to_host.name, check->conn_to_host))) && + ((!conn->bits.conn_to_port && check->conn_to_port == -1) || + (conn->bits.conn_to_port && check->conn_to_port != -1 && + conn->conn_to_port == check->conn_to_port)) && (conn->remote_port == check->remote_port) && Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) { /* yes, we have a session ID! */ @@ -376,10 +412,6 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, } } - /* Unlock */ - if(SSLSESSION_SHARED(data)) - Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); - return no_match; } @@ -400,6 +432,7 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session) Curl_free_ssl_config(&session->ssl_config); Curl_safefree(session->name); + Curl_safefree(session->conn_to_host); } } @@ -409,10 +442,7 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session) void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) { size_t i; - struct SessionHandle *data=conn->data; - - if(SSLSESSION_SHARED(data)) - Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); + struct Curl_easy *data=conn->data; for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) { struct curl_ssl_session *check = &data->state.session[i]; @@ -422,9 +452,6 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) break; } } - - if(SSLSESSION_SHARED(data)) - Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); } /* @@ -438,26 +465,40 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, size_t idsize) { size_t i; - struct SessionHandle *data=conn->data; /* the mother of all structs */ + struct Curl_easy *data=conn->data; /* the mother of all structs */ struct curl_ssl_session *store = &data->state.session[0]; long oldest_age=data->state.session[0].age; /* zero if unused */ char *clone_host; + char *clone_conn_to_host; + int conn_to_port; long *general_age; - /* Even though session ID re-use might be disabled, that only disables USING - IT. We still store it here in case the re-using is again enabled for an - upcoming transfer */ + DEBUGASSERT(conn->ssl_config.sessionid); clone_host = strdup(conn->host.name); if(!clone_host) return CURLE_OUT_OF_MEMORY; /* bail out */ + if(conn->bits.conn_to_host) { + clone_conn_to_host = strdup(conn->conn_to_host.name); + if(!clone_conn_to_host) { + free(clone_host); + return CURLE_OUT_OF_MEMORY; /* bail out */ + } + } + else + clone_conn_to_host = NULL; + + if(conn->bits.conn_to_port) + conn_to_port = conn->conn_to_port; + else + conn_to_port = -1; + /* Now we should add the session ID and the host name to the cache, (remove the oldest if necessary) */ /* If using shared SSL session, lock! */ if(SSLSESSION_SHARED(data)) { - Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); general_age = &data->share->sessionage; } else { @@ -484,17 +525,16 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, store->age = *general_age; /* set current age */ /* free it if there's one already present */ free(store->name); + free(store->conn_to_host); store->name = clone_host; /* clone host name */ + store->conn_to_host = clone_conn_to_host; /* clone connect to host name */ + store->conn_to_port = conn_to_port; /* connect to port number */ store->remote_port = conn->remote_port; /* port number */ - - /* Unlock */ - if(SSLSESSION_SHARED(data)) - Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); - if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) { store->sessionid = NULL; /* let caller free sessionid */ free(clone_host); + free(clone_conn_to_host); return CURLE_OUT_OF_MEMORY; } @@ -502,7 +542,7 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, } -void Curl_ssl_close_all(struct SessionHandle *data) +void Curl_ssl_close_all(struct Curl_easy *data) { size_t i; /* kill the session ID cache if not shared */ @@ -540,20 +580,20 @@ CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex) /* Selects an SSL crypto engine */ -CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine) +CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine) { return curlssl_set_engine(data, engine); } /* Selects the default SSL crypto engine */ -CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data) +CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data) { return curlssl_set_engine_default(data); } /* Return list of OpenSSL crypto engine names. */ -struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data) +struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data) { return curlssl_engines_list(data); } @@ -562,7 +602,7 @@ struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data) * This sets up a session ID cache to the specified size. Make sure this code * is agnostic to what underlying SSL technology we use. */ -CURLcode Curl_ssl_initsessions(struct SessionHandle *data, size_t amount) +CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount) { struct curl_ssl_session *session; @@ -605,7 +645,7 @@ bool Curl_ssl_data_pending(const struct connectdata *conn, return curlssl_data_pending(conn, connindex); } -void Curl_ssl_free_certinfo(struct SessionHandle *data) +void Curl_ssl_free_certinfo(struct Curl_easy *data) { int i; struct curl_certinfo *ci = &data->info.certs; @@ -623,7 +663,7 @@ void Curl_ssl_free_certinfo(struct SessionHandle *data) } } -CURLcode Curl_ssl_init_certinfo(struct SessionHandle *data, int num) +CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num) { struct curl_certinfo *ci = &data->info.certs; struct curl_slist **table; @@ -645,7 +685,7 @@ CURLcode Curl_ssl_init_certinfo(struct SessionHandle *data, int num) /* * 'value' is NOT a zero terminated string */ -CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle *data, +CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, int certnum, const char *label, const char *value, @@ -686,7 +726,7 @@ CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle *data, * This is a convenience function for push_certinfo_len that takes a zero * terminated value. */ -CURLcode Curl_ssl_push_certinfo(struct SessionHandle *data, +CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, int certnum, const char *label, const char *value) @@ -696,7 +736,7 @@ CURLcode Curl_ssl_push_certinfo(struct SessionHandle *data, return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen); } -int Curl_ssl_random(struct SessionHandle *data, +int Curl_ssl_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { @@ -765,7 +805,8 @@ static CURLcode pubkey_pem_to_der(const char *pem, * Generic pinned public key check. */ -CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, +CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, + const char *pinnedpubkey, const unsigned char *pubkey, size_t pubkeylen) { FILE *fp; @@ -775,9 +816,10 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, CURLcode pem_read; CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; #ifdef curlssl_sha256sum - size_t pinkeylen; - char *pinkeycopy, *begin_pos, *end_pos; - unsigned char *sha256sumdigest = NULL, *expectedsha256sumdigest = NULL; + CURLcode encode; + size_t encodedlen, pinkeylen; + char *encoded, *pinkeycopy, *begin_pos, *end_pos; + unsigned char *sha256sumdigest = NULL; #endif /* if a path wasn't specified, don't pin */ @@ -786,21 +828,29 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, if(!pubkey || !pubkeylen) return result; -#ifdef curlssl_sha256sum /* only do this if pinnedpubkey starts with "sha256//", length 8 */ if(strncmp(pinnedpubkey, "sha256//", 8) == 0) { +#ifdef curlssl_sha256sum /* compute sha256sum of public key */ sha256sumdigest = malloc(SHA256_DIGEST_LENGTH); if(!sha256sumdigest) return CURLE_OUT_OF_MEMORY; curlssl_sha256sum(pubkey, pubkeylen, sha256sumdigest, SHA256_DIGEST_LENGTH); + encode = Curl_base64_encode(data, (char *)sha256sumdigest, + SHA256_DIGEST_LENGTH, &encoded, &encodedlen); + Curl_safefree(sha256sumdigest); + + if(encode) + return encode; + + infof(data, "\t public key hash: sha256//%s\n", encoded); /* it starts with sha256//, copy so we can modify it */ pinkeylen = strlen(pinnedpubkey) + 1; pinkeycopy = malloc(pinkeylen); if(!pinkeycopy) { - Curl_safefree(sha256sumdigest); + Curl_safefree(encoded); return CURLE_OUT_OF_MEMORY; } memcpy(pinkeycopy, pinnedpubkey, pinkeylen); @@ -815,20 +865,11 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, if(end_pos) end_pos[0] = '\0'; - /* decode base64 pinnedpubkey, 8 is length of "sha256//" */ - pem_read = Curl_base64_decode(begin_pos + 8, - &expectedsha256sumdigest, &size); - /* if not valid base64, don't bother comparing or freeing */ - if(!pem_read) { - /* compare sha256 digests directly */ - if(SHA256_DIGEST_LENGTH == size && - !memcmp(sha256sumdigest, expectedsha256sumdigest, - SHA256_DIGEST_LENGTH)) { - result = CURLE_OK; - Curl_safefree(expectedsha256sumdigest); - break; - } - Curl_safefree(expectedsha256sumdigest); + /* compare base64 sha256 digests, 8 is the length of "sha256//" */ + if(encodedlen == strlen(begin_pos + 8) && + !memcmp(encoded, begin_pos + 8, encodedlen)) { + result = CURLE_OK; + break; } /* @@ -840,11 +881,14 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, begin_pos = strstr(end_pos, "sha256//"); } } while(end_pos && begin_pos); - Curl_safefree(sha256sumdigest); + Curl_safefree(encoded); Curl_safefree(pinkeycopy); +#else + /* without sha256 support, this cannot match */ + (void)data; +#endif return result; } -#endif fp = fopen(pinnedpubkey, "rb"); if(!fp) diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h index 2349e5b..a41ecc3 100644 --- a/lib/vtls/vtls.h +++ b/lib/vtls/vtls.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -32,6 +32,7 @@ #include "cyassl.h" /* CyaSSL versions */ #include "schannel.h" /* Schannel SSPI version */ #include "darwinssl.h" /* SecureTransport (Darwin) version */ +#include "mbedtls.h" /* mbedTLS versions */ #ifndef MAX_PINNED_PUBKEY_SIZE #define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */ @@ -45,7 +46,7 @@ #define SHA256_DIGEST_LENGTH 32 /* fixed size */ #endif -/* see http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */ +/* see https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */ #define ALPN_HTTP_1_1_LENGTH 8 #define ALPN_HTTP_1_1 "http/1.1" @@ -55,7 +56,7 @@ bool Curl_clone_ssl_config(struct ssl_config_data* source, struct ssl_config_data* dest); void Curl_free_ssl_config(struct ssl_config_data* sslc); -unsigned int Curl_rand(struct SessionHandle *); +unsigned int Curl_rand(struct Curl_easy *); int Curl_ssl_backend(void); @@ -68,16 +69,16 @@ CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn, bool *done); /* tell the SSL stuff to close down all open information regarding connections (and thus session ID caching etc) */ -void Curl_ssl_close_all(struct SessionHandle *data); +void Curl_ssl_close_all(struct Curl_easy *data); void Curl_ssl_close(struct connectdata *conn, int sockindex); CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex); -CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine); +CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine); /* Sets engine as default for all SSL operations */ -CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data); -struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data); +CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data); +struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data); /* init the SSL session ID cache */ -CURLcode Curl_ssl_initsessions(struct SessionHandle *, size_t); +CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t); size_t Curl_ssl_version(char *buffer, size_t size); bool Curl_ssl_data_pending(const struct connectdata *conn, int connindex); @@ -85,39 +86,71 @@ int Curl_ssl_check_cxn(struct connectdata *conn); /* Certificate information list handling. */ -void Curl_ssl_free_certinfo(struct SessionHandle *data); -CURLcode Curl_ssl_init_certinfo(struct SessionHandle * data, int num); -CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle * data, int certnum, +void Curl_ssl_free_certinfo(struct Curl_easy *data); +CURLcode Curl_ssl_init_certinfo(struct Curl_easy * data, int num); +CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy * data, int certnum, const char * label, const char * value, size_t valuelen); -CURLcode Curl_ssl_push_certinfo(struct SessionHandle * data, int certnum, +CURLcode Curl_ssl_push_certinfo(struct Curl_easy * data, int certnum, const char * label, const char * value); /* Functions to be used by SSL library adaptation functions */ -/* extract a session ID */ +/* Lock session cache mutex. + * Call this before calling other Curl_ssl_*session* functions + * Caller should unlock this mutex as soon as possible, as it may block + * other SSL connection from making progress. + * The purpose of explicitly locking SSL session cache data is to allow + * individual SSL engines to manage session lifetime in their specific way. + */ +void Curl_ssl_sessionid_lock(struct connectdata *conn); + +/* Unlock session cache mutex */ +void Curl_ssl_sessionid_unlock(struct connectdata *conn); + +/* extract a session ID + * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). + * Caller must make sure that the ownership of returned sessionid object + * is properly taken (e.g. its refcount is incremented + * under sessionid mutex). + */ bool Curl_ssl_getsessionid(struct connectdata *conn, void **ssl_sessionid, - size_t *idsize) /* set 0 if unknown */; -/* add a new session ID */ + size_t *idsize); /* set 0 if unknown */ +/* add a new session ID + * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). + * Caller must ensure that it has properly shared ownership of this sessionid + * object with cache (e.g. incrementing refcount on success) + */ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, size_t idsize); -/* Kill a single session ID entry in the cache */ +/* Kill a single session ID entry in the cache + * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). + * This will call engine-specific curlssl_session_free function, which must + * take sessionid object ownership from sessionid cache + * (e.g. decrement refcount). + */ void Curl_ssl_kill_session(struct curl_ssl_session *session); -/* delete a session from the cache */ +/* delete a session from the cache + * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). + * This will call engine-specific curlssl_session_free function, which must + * take sessionid object ownership from sessionid cache + * (e.g. decrement refcount). + */ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid); /* get N random bytes into the buffer, return 0 if a find random is filled in */ -int Curl_ssl_random(struct SessionHandle *data, unsigned char *buffer, +int Curl_ssl_random(struct Curl_easy *data, unsigned char *buffer, size_t length); CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum, /* output */ size_t md5len); /* Check pinned public key. */ -CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, +CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, + const char *pinnedpubkey, const unsigned char *pubkey, size_t pubkeylen); bool Curl_ssl_cert_status_request(void); diff --git a/lib/warnless.c b/lib/warnless.c index 8c130d3..0c4472e 100644 --- a/lib/warnless.c +++ b/lib/warnless.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -379,6 +379,63 @@ int curlx_sztosi(ssize_t sznum) } /* +** unsigned int to unsigned short +*/ + +unsigned short curlx_uitous(unsigned int uinum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_USHORT); + return (unsigned short) (uinum & (unsigned int) CURL_MASK_USHORT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** unsigned int to unsigned char +*/ + +unsigned char curlx_uitouc(unsigned int uinum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_UCHAR); + return (unsigned char) (uinum & (unsigned int) CURL_MASK_UCHAR); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** unsigned int to signed int +*/ + +int curlx_uitosi(unsigned int uinum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_SINT); + return (int) (uinum & (unsigned int) CURL_MASK_SINT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* ** signed int to unsigned size_t */ diff --git a/lib/warnless.h b/lib/warnless.h index ad77d3c..ab6d299 100644 --- a/lib/warnless.h +++ b/lib/warnless.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -52,6 +52,12 @@ size_t curlx_sotouz(curl_off_t sonum); int curlx_sztosi(ssize_t sznum); +unsigned short curlx_uitous(unsigned int uinum); + +unsigned char curlx_uitouc(unsigned int uinum); + +int curlx_uitosi(unsigned int uinum); + size_t curlx_sitouz(int sinum); #ifdef USE_WINSOCK diff --git a/lib/wildcard.c b/lib/wildcard.c index 6f55839..dbbe45f 100644 --- a/lib/wildcard.c +++ b/lib/wildcard.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -25,9 +25,9 @@ #include "wildcard.h" #include "llist.h" #include "fileinfo.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" CURLcode Curl_wildcard_init(struct WildcardData *wc) diff --git a/lib/wildcard.h b/lib/wildcard.h index 16c80ec..7f61cd1 100644 --- a/lib/wildcard.h +++ b/lib/wildcard.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -53,6 +53,6 @@ struct WildcardData { CURLcode Curl_wildcard_init(struct WildcardData *wc); void Curl_wildcard_dtor(struct WildcardData *wc); -struct SessionHandle; +struct Curl_easy; #endif /* HEADER_CURL_WILDCARD_H */ diff --git a/lib/x509asn1.c b/lib/x509asn1.c index a3dfd64..e17bcd9 100644 --- a/lib/x509asn1.c +++ b/lib/x509asn1.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -23,7 +23,7 @@ #include "curl_setup.h" #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ - defined(USE_CYASSL) + defined(USE_CYASSL) || defined(USE_SCHANNEL) #include #include "urldata.h" @@ -34,9 +34,10 @@ #include "inet_pton.h" #include "curl_base64.h" #include "x509asn1.h" + +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" @@ -783,7 +784,7 @@ static const char * dumpAlgo(curl_asn1Element * param, return OID2str(oid.beg, oid.end, TRUE); } -static void do_pubkey_field(struct SessionHandle * data, int certnum, +static void do_pubkey_field(struct Curl_easy * data, int certnum, const char * label, curl_asn1Element * elem) { const char * output; @@ -800,7 +801,7 @@ static void do_pubkey_field(struct SessionHandle * data, int certnum, } } -static void do_pubkey(struct SessionHandle * data, int certnum, +static void do_pubkey(struct Curl_easy * data, int certnum, const char * algo, curl_asn1Element * param, curl_asn1Element * pubkey) { @@ -870,7 +871,7 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn, const char * end) { curl_X509certificate cert; - struct SessionHandle * data = conn->data; + struct Curl_easy * data = conn->data; curl_asn1Element param; const char * ccp; char * cp1; @@ -1024,7 +1025,7 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn, return CURLE_OK; } -#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL */ +#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */ #if defined(USE_GSKIT) @@ -1055,13 +1056,12 @@ static const char * checkOID(const char * beg, const char * end, CURLcode Curl_verifyhost(struct connectdata * conn, const char * beg, const char * end) { - struct SessionHandle * data = conn->data; + struct Curl_easy * data = conn->data; curl_X509certificate cert; curl_asn1Element dn; curl_asn1Element elem; curl_asn1Element ext; curl_asn1Element name; - int i; const char * p; const char * q; char * dnsname; @@ -1110,16 +1110,13 @@ CURLcode Curl_verifyhost(struct connectdata * conn, q = Curl_getASN1Element(&name, q, elem.end); switch (name.tag) { case 2: /* DNS name. */ - i = 0; len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING, name.beg, name.end); - if(len > 0) - if(strlen(dnsname) == (size_t) len) - i = Curl_cert_hostcheck((const char *) dnsname, conn->host.name); + if(len > 0 && (size_t)len == strlen(dnsname)) + matched = Curl_cert_hostcheck(dnsname, conn->host.name); + else + matched = 0; free(dnsname); - if(!i) - return CURLE_PEER_FAILED_VERIFICATION; - matched = i; break; case 7: /* IP address. */ diff --git a/lib/x509asn1.h b/lib/x509asn1.h index eb23e50..0f2b930 100644 --- a/lib/x509asn1.h +++ b/lib/x509asn1.h @@ -12,7 +12,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,7 +26,7 @@ #include "curl_setup.h" #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ - defined(USE_CYASSL) + defined(USE_CYASSL) || defined(USE_SCHANNEL) #include "urldata.h" @@ -128,5 +128,5 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn, int certnum, CURLcode Curl_verifyhost(struct connectdata * conn, const char * beg, const char * end); -#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL */ +#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */ #endif /* HEADER_CURL_X509ASN1_H */ https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e1c11352f231ae310339cd539ed59cb302bd4dbe commit e1c11352f231ae310339cd539ed59cb302bd4dbe Author: Brad King AuthorDate: Wed Aug 3 11:55:15 2016 -0400 Commit: Brad King CommitDate: Wed Aug 3 14:26:02 2016 -0400 curl: Update script to get curl 7.50.1 diff --git a/Utilities/Scripts/update-curl.bash b/Utilities/Scripts/update-curl.bash index 17a4f2c..0e466cf 100755 --- a/Utilities/Scripts/update-curl.bash +++ b/Utilities/Scripts/update-curl.bash @@ -8,7 +8,7 @@ readonly name="curl" readonly ownership="Curl Upstream " readonly subtree="Utilities/cmcurl" readonly repo="https://github.com/bagder/curl.git" -readonly tag="curl-7_44_0" +readonly tag="curl-7_50_1" readonly shortlog=false readonly paths=" CMake/* @@ -22,6 +22,8 @@ readonly paths=" lib/Makefile.inc lib/curl_config.h.cmake lib/libcurl.rc + lib/vauth/*.c + lib/vauth/*.h lib/vtls/*.c lib/vtls/*.h " https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a51c6c5394169f34480e7261ef666eb4bf898c67 commit a51c6c5394169f34480e7261ef666eb4bf898c67 Merge: 3e9b034 7ec709d Author: Brad King AuthorDate: Wed Aug 3 11:54:18 2016 -0400 Commit: Brad King CommitDate: Wed Aug 3 11:54:18 2016 -0400 Merge branch 'upstream-curl' into update-curl https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7ec709d3d7cc988d4cf6dc2c49713d4c55f09542 commit 7ec709d3d7cc988d4cf6dc2c49713d4c55f09542 Author: Curl Upstream AuthorDate: Tue Aug 11 20:13:01 2015 +0200 Commit: Brad King CommitDate: Wed Aug 3 11:52:06 2016 -0400 curl 2015-08-11 (1a7f66a3) Code extracted from: https://github.com/bagder/curl.git at commit 1a7f66a3de2625d10f65415e6eb3e56067dc0555 (curl-7_44_0). https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3e9b03439f6fa16abf555f37016e0f45f2073b78 commit 3e9b03439f6fa16abf555f37016e0f45f2073b78 Author: Brad King AuthorDate: Wed Aug 3 11:50:27 2016 -0400 Commit: Brad King CommitDate: Wed Aug 3 11:51:27 2016 -0400 Add script to update curl from upstream diff --git a/Utilities/Scripts/update-curl.bash b/Utilities/Scripts/update-curl.bash new file mode 100755 index 0000000..17a4f2c --- /dev/null +++ b/Utilities/Scripts/update-curl.bash @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +set -e +set -x +shopt -s dotglob + +readonly name="curl" +readonly ownership="Curl Upstream " +readonly subtree="Utilities/cmcurl" +readonly repo="https://github.com/bagder/curl.git" +readonly tag="curl-7_44_0" +readonly shortlog=false +readonly paths=" + CMake/* + CMakeLists.txt + COPYING + include/curl/*.h + include/curl/curlbuild.h.cmake + lib/*.c + lib/*.h + lib/CMakeLists.txt + lib/Makefile.inc + lib/curl_config.h.cmake + lib/libcurl.rc + lib/vtls/*.c + lib/vtls/*.h +" + +extract_source () { + git_archive + pushd "${extractdir}/${name}-reduced" + rm lib/config-*.h + popd +} + +. "${BASH_SOURCE%/*}/update-third-party.bash" ----------------------------------------------------------------------- Summary of changes: Utilities/Scripts/update-curl.bash | 38 + Utilities/cmcurl/CMake/CurlTests.c | 2 +- Utilities/cmcurl/CMake/OtherTests.cmake | 2 +- Utilities/cmcurl/CMakeLists.txt | 182 +-- Utilities/cmcurl/COPYING | 3 +- Utilities/cmcurl/README-CMake.txt | 66 - Utilities/cmcurl/include/curl/curl.h | 243 ++-- Utilities/cmcurl/include/curl/curlbuild.h.cmake | 4 +- Utilities/cmcurl/include/curl/curlrules.h | 4 +- Utilities/cmcurl/include/curl/curlver.h | 14 +- Utilities/cmcurl/include/curl/easy.h | 2 +- Utilities/cmcurl/include/curl/mprintf.h | 30 +- Utilities/cmcurl/include/curl/multi.h | 8 +- Utilities/cmcurl/include/curl/stdcheaders.h | 2 +- Utilities/cmcurl/include/curl/typecheck-gcc.h | 124 +- Utilities/cmcurl/lib/Makefile.inc | 41 +- Utilities/cmcurl/lib/amigaos.c | 6 +- Utilities/cmcurl/lib/amigaos.h | 2 +- Utilities/cmcurl/lib/arpa_telnet.h | 2 +- Utilities/cmcurl/lib/asyn-ares.c | 24 +- Utilities/cmcurl/lib/asyn-thread.c | 31 +- Utilities/cmcurl/lib/asyn.h | 4 +- Utilities/cmcurl/lib/base64.c | 44 +- Utilities/cmcurl/lib/conncache.c | 24 +- Utilities/cmcurl/lib/conncache.h | 2 +- Utilities/cmcurl/lib/connect.c | 133 +- Utilities/cmcurl/lib/connect.h | 14 +- Utilities/cmcurl/lib/content_encoding.c | 6 +- Utilities/cmcurl/lib/content_encoding.h | 2 +- Utilities/cmcurl/lib/cookie.c | 122 +- Utilities/cmcurl/lib/cookie.h | 14 +- Utilities/cmcurl/lib/curl_addrinfo.c | 44 +- Utilities/cmcurl/lib/curl_addrinfo.h | 15 +- Utilities/cmcurl/lib/curl_base64.h | 6 +- Utilities/cmcurl/lib/curl_config.h.cmake | 27 + Utilities/cmcurl/lib/curl_des.c | 6 +- Utilities/cmcurl/lib/curl_des.h | 6 +- Utilities/cmcurl/lib/curl_endian.c | 2 +- Utilities/cmcurl/lib/curl_endian.h | 2 +- Utilities/cmcurl/lib/curl_fnmatch.c | 6 +- Utilities/cmcurl/lib/curl_fnmatch.h | 2 +- Utilities/cmcurl/lib/curl_gethostname.c | 2 +- Utilities/cmcurl/lib/curl_gethostname.h | 2 +- Utilities/cmcurl/lib/curl_gssapi.c | 65 +- Utilities/cmcurl/lib/curl_gssapi.h | 8 +- Utilities/cmcurl/lib/curl_hmac.h | 2 +- Utilities/cmcurl/lib/curl_ldap.h | 2 +- Utilities/cmcurl/lib/curl_md4.h | 2 +- Utilities/cmcurl/lib/curl_md5.h | 2 +- Utilities/cmcurl/lib/curl_memory.h | 19 +- Utilities/cmcurl/lib/curl_memrchr.c | 7 +- Utilities/cmcurl/lib/curl_memrchr.h | 2 +- Utilities/cmcurl/lib/curl_multibyte.c | 4 +- Utilities/cmcurl/lib/curl_multibyte.h | 2 +- Utilities/cmcurl/lib/curl_ntlm_core.c | 34 +- Utilities/cmcurl/lib/curl_ntlm_core.h | 6 +- Utilities/cmcurl/lib/curl_ntlm_wb.c | 15 +- Utilities/cmcurl/lib/curl_ntlm_wb.h | 2 +- Utilities/cmcurl/lib/curl_printf.h | 2 +- Utilities/cmcurl/lib/curl_rtmp.c | 4 +- Utilities/cmcurl/lib/curl_rtmp.h | 2 +- Utilities/cmcurl/lib/curl_sasl.c | 1332 ++---------------- Utilities/cmcurl/lib/curl_sasl.h | 143 +- Utilities/cmcurl/lib/curl_sasl_sspi.c | 1281 ----------------- Utilities/cmcurl/lib/curl_sec.h | 2 +- Utilities/cmcurl/lib/curl_setup.h | 49 +- Utilities/cmcurl/lib/curl_setup_once.h | 2 +- Utilities/cmcurl/lib/curl_sspi.c | 52 +- Utilities/cmcurl/lib/curl_sspi.h | 6 +- Utilities/cmcurl/lib/curl_threads.c | 6 +- Utilities/cmcurl/lib/curl_threads.h | 2 +- Utilities/cmcurl/lib/curlx.h | 2 +- Utilities/cmcurl/lib/dict.c | 6 +- Utilities/cmcurl/lib/dict.h | 2 +- Utilities/cmcurl/lib/dotdot.c | 17 +- Utilities/cmcurl/lib/dotdot.h | 2 +- Utilities/cmcurl/lib/easy.c | 181 +-- Utilities/cmcurl/lib/easyif.h | 6 +- Utilities/cmcurl/lib/escape.c | 24 +- Utilities/cmcurl/lib/escape.h | 4 +- Utilities/cmcurl/lib/file.c | 93 +- Utilities/cmcurl/lib/file.h | 2 +- Utilities/cmcurl/lib/fileinfo.c | 2 +- Utilities/cmcurl/lib/fileinfo.h | 2 +- Utilities/cmcurl/lib/formdata.c | 121 +- Utilities/cmcurl/lib/formdata.h | 12 +- Utilities/cmcurl/lib/ftp.c | 181 +-- Utilities/cmcurl/lib/ftp.h | 6 +- Utilities/cmcurl/lib/ftplistparser.c | 36 +- Utilities/cmcurl/lib/ftplistparser.h | 2 +- Utilities/cmcurl/lib/getenv.c | 2 +- Utilities/cmcurl/lib/getinfo.c | 128 +- Utilities/cmcurl/lib/getinfo.h | 6 +- Utilities/cmcurl/lib/gopher.c | 12 +- Utilities/cmcurl/lib/gopher.h | 2 +- Utilities/cmcurl/lib/hash.c | 30 +- Utilities/cmcurl/lib/hash.h | 2 +- Utilities/cmcurl/lib/hmac.c | 7 +- Utilities/cmcurl/lib/hostasyn.c | 4 +- Utilities/cmcurl/lib/hostcheck.c | 4 +- Utilities/cmcurl/lib/hostcheck.h | 2 +- Utilities/cmcurl/lib/hostip.c | 29 +- Utilities/cmcurl/lib/hostip.h | 24 +- Utilities/cmcurl/lib/hostip4.c | 6 +- Utilities/cmcurl/lib/hostip6.c | 31 +- Utilities/cmcurl/lib/hostsyn.c | 10 +- Utilities/cmcurl/lib/http.c | 361 ++--- Utilities/cmcurl/lib/http.h | 12 +- Utilities/cmcurl/lib/http2.c | 800 ++++++++--- Utilities/cmcurl/lib/http2.h | 10 +- Utilities/cmcurl/lib/http_chunks.c | 8 +- Utilities/cmcurl/lib/http_chunks.h | 2 +- Utilities/cmcurl/lib/http_digest.c | 25 +- Utilities/cmcurl/lib/http_digest.h | 4 +- Utilities/cmcurl/lib/http_negotiate.c | 193 +-- Utilities/cmcurl/lib/http_negotiate.h | 8 +- Utilities/cmcurl/lib/http_negotiate_sspi.c | 300 ---- Utilities/cmcurl/lib/{curl_ntlm.c => http_ntlm.c} | 27 +- Utilities/cmcurl/lib/{curl_ntlm.h => http_ntlm.h} | 2 +- Utilities/cmcurl/lib/http_proxy.c | 45 +- Utilities/cmcurl/lib/http_proxy.h | 2 +- Utilities/cmcurl/lib/idn_win32.c | 63 +- Utilities/cmcurl/lib/if2ip.c | 19 +- Utilities/cmcurl/lib/if2ip.h | 2 +- Utilities/cmcurl/lib/imap.c | 148 +- Utilities/cmcurl/lib/imap.h | 6 +- Utilities/cmcurl/lib/inet_ntop.c | 11 +- Utilities/cmcurl/lib/inet_ntop.h | 2 +- Utilities/cmcurl/lib/inet_pton.c | 8 +- Utilities/cmcurl/lib/inet_pton.h | 2 +- Utilities/cmcurl/lib/krb5.c | 28 +- Utilities/cmcurl/lib/ldap.c | 13 +- Utilities/cmcurl/lib/libcurl.rc | 6 +- Utilities/cmcurl/lib/llist.c | 6 +- Utilities/cmcurl/lib/llist.h | 2 +- Utilities/cmcurl/lib/md5.c | 6 +- Utilities/cmcurl/lib/memdebug.c | 15 +- Utilities/cmcurl/lib/memdebug.h | 17 +- Utilities/cmcurl/lib/mprintf.c | 184 +-- Utilities/cmcurl/lib/multi.c | 709 +++++++--- Utilities/cmcurl/lib/multihandle.h | 10 +- Utilities/cmcurl/lib/multiif.h | 14 +- Utilities/cmcurl/lib/netrc.c | 8 +- Utilities/cmcurl/lib/netrc.h | 2 +- Utilities/cmcurl/lib/non-ascii.c | 24 +- Utilities/cmcurl/lib/non-ascii.h | 18 +- Utilities/cmcurl/lib/nonblock.c | 6 +- Utilities/cmcurl/lib/nonblock.h | 2 +- Utilities/cmcurl/lib/nwlib.c | 50 +- Utilities/cmcurl/lib/nwos.c | 12 +- Utilities/cmcurl/lib/openldap.c | 109 +- Utilities/cmcurl/lib/parsedate.c | 2 +- Utilities/cmcurl/lib/parsedate.h | 2 +- Utilities/cmcurl/lib/pingpong.c | 18 +- Utilities/cmcurl/lib/pingpong.h | 2 +- Utilities/cmcurl/lib/pipeline.c | 46 +- Utilities/cmcurl/lib/pipeline.h | 20 +- Utilities/cmcurl/lib/pop3.c | 74 +- Utilities/cmcurl/lib/pop3.h | 6 +- Utilities/cmcurl/lib/progress.c | 20 +- Utilities/cmcurl/lib/progress.h | 16 +- Utilities/cmcurl/lib/rawstr.c | 12 +- Utilities/cmcurl/lib/rawstr.h | 2 +- Utilities/cmcurl/lib/rtsp.c | 48 +- Utilities/cmcurl/lib/rtsp.h | 2 +- Utilities/cmcurl/lib/security.c | 2 +- Utilities/cmcurl/lib/select.c | 22 +- Utilities/cmcurl/lib/select.h | 2 +- Utilities/cmcurl/lib/sendf.c | 154 ++- Utilities/cmcurl/lib/sendf.h | 8 +- Utilities/cmcurl/lib/setup-os400.h | 2 +- Utilities/cmcurl/lib/setup-vms.h | 2 +- Utilities/cmcurl/lib/share.c | 23 +- Utilities/cmcurl/lib/share.h | 6 +- Utilities/cmcurl/lib/sigpipe.h | 6 +- Utilities/cmcurl/lib/slist.c | 6 +- Utilities/cmcurl/lib/slist.h | 2 +- Utilities/cmcurl/lib/smb.c | 13 +- Utilities/cmcurl/lib/smb.h | 2 +- Utilities/cmcurl/lib/smtp.c | 85 +- Utilities/cmcurl/lib/smtp.h | 6 +- Utilities/cmcurl/lib/sockaddr.h | 2 +- Utilities/cmcurl/lib/socks.c | 44 +- Utilities/cmcurl/lib/socks.h | 2 +- Utilities/cmcurl/lib/socks_gssapi.c | 14 +- Utilities/cmcurl/lib/socks_sspi.c | 17 +- Utilities/cmcurl/lib/speedcheck.c | 6 +- Utilities/cmcurl/lib/speedcheck.h | 6 +- Utilities/cmcurl/lib/splay.c | 2 +- Utilities/cmcurl/lib/splay.h | 6 +- Utilities/cmcurl/lib/ssh.c | 173 ++- Utilities/cmcurl/lib/ssh.h | 7 +- Utilities/cmcurl/lib/strdup.c | 8 +- Utilities/cmcurl/lib/strdup.h | 2 +- Utilities/cmcurl/lib/strequal.c | 2 +- Utilities/cmcurl/lib/strequal.h | 2 +- Utilities/cmcurl/lib/strerror.c | 20 +- Utilities/cmcurl/lib/strerror.h | 2 +- Utilities/cmcurl/lib/strtok.c | 2 +- Utilities/cmcurl/lib/strtok.h | 2 +- Utilities/cmcurl/lib/strtoofft.c | 2 +- Utilities/cmcurl/lib/strtoofft.h | 2 +- Utilities/cmcurl/lib/system_win32.c | 294 ++++ Utilities/cmcurl/lib/system_win32.h | 61 + Utilities/cmcurl/lib/telnet.c | 46 +- Utilities/cmcurl/lib/telnet.h | 2 +- Utilities/cmcurl/lib/tftp.c | 99 +- Utilities/cmcurl/lib/tftp.h | 2 +- Utilities/cmcurl/lib/timeval.c | 14 +- Utilities/cmcurl/lib/timeval.h | 2 +- Utilities/cmcurl/lib/transfer.c | 219 ++- Utilities/cmcurl/lib/transfer.h | 17 +- Utilities/cmcurl/lib/url.c | 1449 ++++++++++++-------- Utilities/cmcurl/lib/url.h | 40 +- Utilities/cmcurl/lib/urldata.h | 187 ++- Utilities/cmcurl/lib/vauth/cleartext.c | 157 +++ Utilities/cmcurl/lib/vauth/cram.c | 138 ++ Utilities/cmcurl/lib/vauth/digest.c | 883 ++++++++++++ .../cmcurl/lib/{strequal.h => vauth/digest.h} | 26 +- Utilities/cmcurl/lib/vauth/digest_sspi.c | 533 +++++++ .../{curl_sasl_gssapi.c => vauth/krb5_gssapi.c} | 175 ++- Utilities/cmcurl/lib/vauth/krb5_sspi.c | 496 +++++++ .../cmcurl/lib/{curl_ntlm_msgs.c => vauth/ntlm.c} | 65 +- .../cmcurl/lib/{curl_ntlm_msgs.h => vauth/ntlm.h} | 10 +- Utilities/cmcurl/lib/vauth/ntlm_sspi.c | 314 +++++ Utilities/cmcurl/lib/vauth/oauth2.c | 86 ++ Utilities/cmcurl/lib/vauth/spnego_gssapi.c | 260 ++++ Utilities/cmcurl/lib/vauth/spnego_sspi.c | 297 ++++ Utilities/cmcurl/lib/vauth/vauth.c | 106 ++ Utilities/cmcurl/lib/vauth/vauth.h | 189 +++ Utilities/cmcurl/lib/version.c | 40 +- Utilities/cmcurl/lib/vtls/axtls.c | 58 +- Utilities/cmcurl/lib/vtls/axtls.h | 4 +- Utilities/cmcurl/lib/vtls/cyassl.c | 203 ++- Utilities/cmcurl/lib/vtls/cyassl.h | 23 +- Utilities/cmcurl/lib/vtls/darwinssl.c | 111 +- Utilities/cmcurl/lib/vtls/darwinssl.h | 2 +- Utilities/cmcurl/lib/vtls/gskit.c | 36 +- Utilities/cmcurl/lib/vtls/gskit.h | 2 +- Utilities/cmcurl/lib/vtls/gtls.c | 116 +- Utilities/cmcurl/lib/vtls/gtls.h | 9 +- Utilities/cmcurl/lib/vtls/mbedtls.c | 871 ++++++++++++ Utilities/cmcurl/lib/vtls/mbedtls.h | 80 ++ Utilities/cmcurl/lib/vtls/nss.c | 113 +- Utilities/cmcurl/lib/vtls/nssg.h | 13 +- Utilities/cmcurl/lib/vtls/openssl.c | 998 +++++++------- Utilities/cmcurl/lib/vtls/openssl.h | 21 +- Utilities/cmcurl/lib/vtls/polarssl.c | 191 ++- Utilities/cmcurl/lib/vtls/polarssl.h | 18 +- Utilities/cmcurl/lib/vtls/polarssl_threadlock.c | 16 +- Utilities/cmcurl/lib/vtls/polarssl_threadlock.h | 22 +- Utilities/cmcurl/lib/vtls/schannel.c | 297 ++-- Utilities/cmcurl/lib/vtls/schannel.h | 5 +- Utilities/cmcurl/lib/vtls/vtls.c | 168 ++- Utilities/cmcurl/lib/vtls/vtls.h | 73 +- Utilities/cmcurl/lib/warnless.c | 61 +- Utilities/cmcurl/lib/warnless.h | 10 +- Utilities/cmcurl/lib/wildcard.c | 6 +- Utilities/cmcurl/lib/wildcard.h | 4 +- Utilities/cmcurl/lib/x509asn1.c | 31 +- Utilities/cmcurl/lib/x509asn1.h | 6 +- 261 files changed, 11892 insertions(+), 7488 deletions(-) create mode 100755 Utilities/Scripts/update-curl.bash delete mode 100644 Utilities/cmcurl/README-CMake.txt delete mode 100644 Utilities/cmcurl/lib/curl_sasl_sspi.c delete mode 100644 Utilities/cmcurl/lib/http_negotiate_sspi.c rename Utilities/cmcurl/lib/{curl_ntlm.c => http_ntlm.c} (91%) rename Utilities/cmcurl/lib/{curl_ntlm.h => http_ntlm.h} (95%) create mode 100644 Utilities/cmcurl/lib/system_win32.c create mode 100644 Utilities/cmcurl/lib/system_win32.h create mode 100644 Utilities/cmcurl/lib/vauth/cleartext.c create mode 100644 Utilities/cmcurl/lib/vauth/cram.c create mode 100644 Utilities/cmcurl/lib/vauth/digest.c copy Utilities/cmcurl/lib/{strequal.h => vauth/digest.h} (59%) create mode 100644 Utilities/cmcurl/lib/vauth/digest_sspi.c rename Utilities/cmcurl/lib/{curl_sasl_gssapi.c => vauth/krb5_gssapi.c} (66%) create mode 100644 Utilities/cmcurl/lib/vauth/krb5_sspi.c rename Utilities/cmcurl/lib/{curl_ntlm_msgs.c => vauth/ntlm.c} (94%) rename Utilities/cmcurl/lib/{curl_ntlm_msgs.h => vauth/ntlm.h} (95%) create mode 100644 Utilities/cmcurl/lib/vauth/ntlm_sspi.c create mode 100644 Utilities/cmcurl/lib/vauth/oauth2.c create mode 100644 Utilities/cmcurl/lib/vauth/spnego_gssapi.c create mode 100644 Utilities/cmcurl/lib/vauth/spnego_sspi.c create mode 100644 Utilities/cmcurl/lib/vauth/vauth.c create mode 100644 Utilities/cmcurl/lib/vauth/vauth.h create mode 100644 Utilities/cmcurl/lib/vtls/mbedtls.c create mode 100644 Utilities/cmcurl/lib/vtls/mbedtls.h hooks/post-receive -- CMake From kwrobot at kitware.com Thu Aug 4 00:01:09 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Thu, 4 Aug 2016 00:01:09 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-540-g2c0e87f Message-ID: <20160804040109.38ECCF5377@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 2c0e87fff3347189db7454cf55669eec45819d9a (commit) from 382c4fca6b895c2c7a68445918a8fd73a15e1f91 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2c0e87fff3347189db7454cf55669eec45819d9a commit 2c0e87fff3347189db7454cf55669eec45819d9a Author: Kitware Robot AuthorDate: Thu Aug 4 00:01:06 2016 -0400 Commit: Kitware Robot CommitDate: Thu Aug 4 00:01:06 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index a742e33..f8782b2 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160803) +set(CMake_VERSION_PATCH 20160804) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 4 09:52:44 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 4 Aug 2016 09:52:44 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1105-g5d4a3ed Message-ID: <20160804135245.D374FF501C@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 5d4a3eda276b5dc2f98b61d5ed532e199e4c0ca8 (commit) via e555480c60e95073840fe1a5f52004fd8ce81f9c (commit) via 2c0e87fff3347189db7454cf55669eec45819d9a (commit) from 13ce471eee787ca728646f4eec102f5ffc327efa (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5d4a3eda276b5dc2f98b61d5ed532e199e4c0ca8 commit 5d4a3eda276b5dc2f98b61d5ed532e199e4c0ca8 Merge: 13ce471 e555480 Author: Brad King AuthorDate: Thu Aug 4 09:52:42 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 4 09:52:42 2016 -0400 Merge topic 'ninja-clang-rsp-format' into next e555480c Ninja: Fix response file format for GNU-like Clang on Windows 2c0e87ff CMake Nightly Date Stamp https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e555480c60e95073840fe1a5f52004fd8ce81f9c commit e555480c60e95073840fe1a5f52004fd8ce81f9c Author: Brad King AuthorDate: Thu Aug 4 09:41:10 2016 -0400 Commit: Brad King CommitDate: Thu Aug 4 09:44:56 2016 -0400 Ninja: Fix response file format for GNU-like Clang on Windows The `CMAKE__SIMULATE_ID` variables are not set to "GNU" for a GNU-like Clang compiler on Windows. They are only set to "MSVC" for a MSVC-like Clang. Revise our response file format selection accordingly. Reported-by: Chaoren Lin diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 51175c7..44418f2 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -554,11 +554,13 @@ void cmGlobalNinjaGenerator::EnableLanguage( this->ResolveLanguageCompiler(*l, mf, optional); } #ifdef _WIN32 - if (mf->IsOn("CMAKE_COMPILER_IS_MINGW") || - strcmp(mf->GetSafeDefinition("CMAKE_C_COMPILER_ID"), "GNU") == 0 || - strcmp(mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID"), "GNU") == 0 || - strcmp(mf->GetSafeDefinition("CMAKE_C_SIMULATE_ID"), "GNU") == 0 || - strcmp(mf->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID"), "GNU") == 0) { + if (strcmp(mf->GetSafeDefinition("CMAKE_C_SIMULATE_ID"), "MSVC") != 0 && + strcmp(mf->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID"), "MSVC") != 0 && + (mf->IsOn("CMAKE_COMPILER_IS_MINGW") || + strcmp(mf->GetSafeDefinition("CMAKE_C_COMPILER_ID"), "GNU") == 0 || + strcmp(mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID"), "GNU") == 0 || + strcmp(mf->GetSafeDefinition("CMAKE_C_COMPILER_ID"), "Clang") == 0 || + strcmp(mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID"), "Clang") == 0)) { this->UsingGCCOnWindows = true; } #endif ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- Source/cmGlobalNinjaGenerator.cxx | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 4 09:56:42 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 4 Aug 2016 09:56:42 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-548-g85d966d Message-ID: <20160804135642.A68F2F515D@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 85d966dcd7a29a17e42fde7b1c109e642f063d82 (commit) via f59ab43370dc9bff7e6480032c95505cdd00e3cd (commit) via f53f4a8a2d215dac634effea575a27e000dfcb29 (commit) via 202adcfe056681109fe61569ecdb3bd69f0b4f97 (commit) via e1c11352f231ae310339cd539ed59cb302bd4dbe (commit) via a51c6c5394169f34480e7261ef666eb4bf898c67 (commit) via 7ec709d3d7cc988d4cf6dc2c49713d4c55f09542 (commit) via 3e9b03439f6fa16abf555f37016e0f45f2073b78 (commit) from 2c0e87fff3347189db7454cf55669eec45819d9a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=85d966dcd7a29a17e42fde7b1c109e642f063d82 commit 85d966dcd7a29a17e42fde7b1c109e642f063d82 Merge: 2c0e87f f59ab43 Author: Brad King AuthorDate: Thu Aug 4 09:56:39 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 4 09:56:39 2016 -0400 Merge topic 'update-curl' f59ab433 curl: Remove CMake-specific README f53f4a8a Merge branch 'upstream-curl' into update-curl 202adcfe curl 2016-08-03 (f2cb3a01) e1c11352 curl: Update script to get curl 7.50.1 a51c6c53 Merge branch 'upstream-curl' into update-curl 7ec709d3 curl 2015-08-11 (1a7f66a3) 3e9b0343 Add script to update curl from upstream ----------------------------------------------------------------------- Summary of changes: Utilities/Scripts/update-curl.bash | 38 + Utilities/cmcurl/CMake/CurlTests.c | 2 +- Utilities/cmcurl/CMake/OtherTests.cmake | 2 +- Utilities/cmcurl/CMakeLists.txt | 182 +-- Utilities/cmcurl/COPYING | 3 +- Utilities/cmcurl/README-CMake.txt | 66 - Utilities/cmcurl/include/curl/curl.h | 243 ++-- Utilities/cmcurl/include/curl/curlbuild.h.cmake | 4 +- Utilities/cmcurl/include/curl/curlrules.h | 4 +- Utilities/cmcurl/include/curl/curlver.h | 14 +- Utilities/cmcurl/include/curl/easy.h | 2 +- Utilities/cmcurl/include/curl/mprintf.h | 30 +- Utilities/cmcurl/include/curl/multi.h | 8 +- Utilities/cmcurl/include/curl/stdcheaders.h | 2 +- Utilities/cmcurl/include/curl/typecheck-gcc.h | 124 +- Utilities/cmcurl/lib/Makefile.inc | 41 +- Utilities/cmcurl/lib/amigaos.c | 6 +- Utilities/cmcurl/lib/amigaos.h | 2 +- Utilities/cmcurl/lib/arpa_telnet.h | 2 +- Utilities/cmcurl/lib/asyn-ares.c | 24 +- Utilities/cmcurl/lib/asyn-thread.c | 31 +- Utilities/cmcurl/lib/asyn.h | 4 +- Utilities/cmcurl/lib/base64.c | 44 +- Utilities/cmcurl/lib/conncache.c | 24 +- Utilities/cmcurl/lib/conncache.h | 2 +- Utilities/cmcurl/lib/connect.c | 133 +- Utilities/cmcurl/lib/connect.h | 14 +- Utilities/cmcurl/lib/content_encoding.c | 6 +- Utilities/cmcurl/lib/content_encoding.h | 2 +- Utilities/cmcurl/lib/cookie.c | 122 +- Utilities/cmcurl/lib/cookie.h | 14 +- Utilities/cmcurl/lib/curl_addrinfo.c | 44 +- Utilities/cmcurl/lib/curl_addrinfo.h | 15 +- Utilities/cmcurl/lib/curl_base64.h | 6 +- Utilities/cmcurl/lib/curl_config.h.cmake | 27 + Utilities/cmcurl/lib/curl_des.c | 6 +- Utilities/cmcurl/lib/curl_des.h | 6 +- Utilities/cmcurl/lib/curl_endian.c | 2 +- Utilities/cmcurl/lib/curl_endian.h | 2 +- Utilities/cmcurl/lib/curl_fnmatch.c | 6 +- Utilities/cmcurl/lib/curl_fnmatch.h | 2 +- Utilities/cmcurl/lib/curl_gethostname.c | 2 +- Utilities/cmcurl/lib/curl_gethostname.h | 2 +- Utilities/cmcurl/lib/curl_gssapi.c | 65 +- Utilities/cmcurl/lib/curl_gssapi.h | 8 +- Utilities/cmcurl/lib/curl_hmac.h | 2 +- Utilities/cmcurl/lib/curl_ldap.h | 2 +- Utilities/cmcurl/lib/curl_md4.h | 2 +- Utilities/cmcurl/lib/curl_md5.h | 2 +- Utilities/cmcurl/lib/curl_memory.h | 19 +- Utilities/cmcurl/lib/curl_memrchr.c | 7 +- Utilities/cmcurl/lib/curl_memrchr.h | 2 +- Utilities/cmcurl/lib/curl_multibyte.c | 4 +- Utilities/cmcurl/lib/curl_multibyte.h | 2 +- Utilities/cmcurl/lib/curl_ntlm_core.c | 34 +- Utilities/cmcurl/lib/curl_ntlm_core.h | 6 +- Utilities/cmcurl/lib/curl_ntlm_wb.c | 15 +- Utilities/cmcurl/lib/curl_ntlm_wb.h | 2 +- Utilities/cmcurl/lib/curl_printf.h | 2 +- Utilities/cmcurl/lib/curl_rtmp.c | 4 +- Utilities/cmcurl/lib/curl_rtmp.h | 2 +- Utilities/cmcurl/lib/curl_sasl.c | 1332 ++---------------- Utilities/cmcurl/lib/curl_sasl.h | 143 +- Utilities/cmcurl/lib/curl_sasl_sspi.c | 1281 ----------------- Utilities/cmcurl/lib/curl_sec.h | 2 +- Utilities/cmcurl/lib/curl_setup.h | 49 +- Utilities/cmcurl/lib/curl_setup_once.h | 2 +- Utilities/cmcurl/lib/curl_sspi.c | 52 +- Utilities/cmcurl/lib/curl_sspi.h | 6 +- Utilities/cmcurl/lib/curl_threads.c | 6 +- Utilities/cmcurl/lib/curl_threads.h | 2 +- Utilities/cmcurl/lib/curlx.h | 2 +- Utilities/cmcurl/lib/dict.c | 6 +- Utilities/cmcurl/lib/dict.h | 2 +- Utilities/cmcurl/lib/dotdot.c | 17 +- Utilities/cmcurl/lib/dotdot.h | 2 +- Utilities/cmcurl/lib/easy.c | 181 +-- Utilities/cmcurl/lib/easyif.h | 6 +- Utilities/cmcurl/lib/escape.c | 24 +- Utilities/cmcurl/lib/escape.h | 4 +- Utilities/cmcurl/lib/file.c | 93 +- Utilities/cmcurl/lib/file.h | 2 +- Utilities/cmcurl/lib/fileinfo.c | 2 +- Utilities/cmcurl/lib/fileinfo.h | 2 +- Utilities/cmcurl/lib/formdata.c | 121 +- Utilities/cmcurl/lib/formdata.h | 12 +- Utilities/cmcurl/lib/ftp.c | 181 +-- Utilities/cmcurl/lib/ftp.h | 6 +- Utilities/cmcurl/lib/ftplistparser.c | 36 +- Utilities/cmcurl/lib/ftplistparser.h | 2 +- Utilities/cmcurl/lib/getenv.c | 2 +- Utilities/cmcurl/lib/getinfo.c | 128 +- Utilities/cmcurl/lib/getinfo.h | 6 +- Utilities/cmcurl/lib/gopher.c | 12 +- Utilities/cmcurl/lib/gopher.h | 2 +- Utilities/cmcurl/lib/hash.c | 30 +- Utilities/cmcurl/lib/hash.h | 2 +- Utilities/cmcurl/lib/hmac.c | 7 +- Utilities/cmcurl/lib/hostasyn.c | 4 +- Utilities/cmcurl/lib/hostcheck.c | 4 +- Utilities/cmcurl/lib/hostcheck.h | 2 +- Utilities/cmcurl/lib/hostip.c | 29 +- Utilities/cmcurl/lib/hostip.h | 24 +- Utilities/cmcurl/lib/hostip4.c | 6 +- Utilities/cmcurl/lib/hostip6.c | 31 +- Utilities/cmcurl/lib/hostsyn.c | 10 +- Utilities/cmcurl/lib/http.c | 361 ++--- Utilities/cmcurl/lib/http.h | 12 +- Utilities/cmcurl/lib/http2.c | 800 ++++++++--- Utilities/cmcurl/lib/http2.h | 10 +- Utilities/cmcurl/lib/http_chunks.c | 8 +- Utilities/cmcurl/lib/http_chunks.h | 2 +- Utilities/cmcurl/lib/http_digest.c | 25 +- Utilities/cmcurl/lib/http_digest.h | 4 +- Utilities/cmcurl/lib/http_negotiate.c | 193 +-- Utilities/cmcurl/lib/http_negotiate.h | 8 +- Utilities/cmcurl/lib/http_negotiate_sspi.c | 300 ---- Utilities/cmcurl/lib/{curl_ntlm.c => http_ntlm.c} | 27 +- Utilities/cmcurl/lib/{curl_ntlm.h => http_ntlm.h} | 2 +- Utilities/cmcurl/lib/http_proxy.c | 45 +- Utilities/cmcurl/lib/http_proxy.h | 2 +- Utilities/cmcurl/lib/idn_win32.c | 63 +- Utilities/cmcurl/lib/if2ip.c | 19 +- Utilities/cmcurl/lib/if2ip.h | 2 +- Utilities/cmcurl/lib/imap.c | 148 +- Utilities/cmcurl/lib/imap.h | 6 +- Utilities/cmcurl/lib/inet_ntop.c | 11 +- Utilities/cmcurl/lib/inet_ntop.h | 2 +- Utilities/cmcurl/lib/inet_pton.c | 8 +- Utilities/cmcurl/lib/inet_pton.h | 2 +- Utilities/cmcurl/lib/krb5.c | 28 +- Utilities/cmcurl/lib/ldap.c | 13 +- Utilities/cmcurl/lib/libcurl.rc | 6 +- Utilities/cmcurl/lib/llist.c | 6 +- Utilities/cmcurl/lib/llist.h | 2 +- Utilities/cmcurl/lib/md5.c | 6 +- Utilities/cmcurl/lib/memdebug.c | 15 +- Utilities/cmcurl/lib/memdebug.h | 17 +- Utilities/cmcurl/lib/mprintf.c | 184 +-- Utilities/cmcurl/lib/multi.c | 709 +++++++--- Utilities/cmcurl/lib/multihandle.h | 10 +- Utilities/cmcurl/lib/multiif.h | 14 +- Utilities/cmcurl/lib/netrc.c | 8 +- Utilities/cmcurl/lib/netrc.h | 2 +- Utilities/cmcurl/lib/non-ascii.c | 24 +- Utilities/cmcurl/lib/non-ascii.h | 18 +- Utilities/cmcurl/lib/nonblock.c | 6 +- Utilities/cmcurl/lib/nonblock.h | 2 +- Utilities/cmcurl/lib/nwlib.c | 50 +- Utilities/cmcurl/lib/nwos.c | 12 +- Utilities/cmcurl/lib/openldap.c | 109 +- Utilities/cmcurl/lib/parsedate.c | 2 +- Utilities/cmcurl/lib/parsedate.h | 2 +- Utilities/cmcurl/lib/pingpong.c | 18 +- Utilities/cmcurl/lib/pingpong.h | 2 +- Utilities/cmcurl/lib/pipeline.c | 46 +- Utilities/cmcurl/lib/pipeline.h | 20 +- Utilities/cmcurl/lib/pop3.c | 74 +- Utilities/cmcurl/lib/pop3.h | 6 +- Utilities/cmcurl/lib/progress.c | 20 +- Utilities/cmcurl/lib/progress.h | 16 +- Utilities/cmcurl/lib/rawstr.c | 12 +- Utilities/cmcurl/lib/rawstr.h | 2 +- Utilities/cmcurl/lib/rtsp.c | 48 +- Utilities/cmcurl/lib/rtsp.h | 2 +- Utilities/cmcurl/lib/security.c | 2 +- Utilities/cmcurl/lib/select.c | 22 +- Utilities/cmcurl/lib/select.h | 2 +- Utilities/cmcurl/lib/sendf.c | 154 ++- Utilities/cmcurl/lib/sendf.h | 8 +- Utilities/cmcurl/lib/setup-os400.h | 2 +- Utilities/cmcurl/lib/setup-vms.h | 2 +- Utilities/cmcurl/lib/share.c | 23 +- Utilities/cmcurl/lib/share.h | 6 +- Utilities/cmcurl/lib/sigpipe.h | 6 +- Utilities/cmcurl/lib/slist.c | 6 +- Utilities/cmcurl/lib/slist.h | 2 +- Utilities/cmcurl/lib/smb.c | 13 +- Utilities/cmcurl/lib/smb.h | 2 +- Utilities/cmcurl/lib/smtp.c | 85 +- Utilities/cmcurl/lib/smtp.h | 6 +- Utilities/cmcurl/lib/sockaddr.h | 2 +- Utilities/cmcurl/lib/socks.c | 44 +- Utilities/cmcurl/lib/socks.h | 2 +- Utilities/cmcurl/lib/socks_gssapi.c | 14 +- Utilities/cmcurl/lib/socks_sspi.c | 17 +- Utilities/cmcurl/lib/speedcheck.c | 6 +- Utilities/cmcurl/lib/speedcheck.h | 6 +- Utilities/cmcurl/lib/splay.c | 2 +- Utilities/cmcurl/lib/splay.h | 6 +- Utilities/cmcurl/lib/ssh.c | 173 ++- Utilities/cmcurl/lib/ssh.h | 7 +- Utilities/cmcurl/lib/strdup.c | 8 +- Utilities/cmcurl/lib/strdup.h | 2 +- Utilities/cmcurl/lib/strequal.c | 2 +- Utilities/cmcurl/lib/strequal.h | 2 +- Utilities/cmcurl/lib/strerror.c | 20 +- Utilities/cmcurl/lib/strerror.h | 2 +- Utilities/cmcurl/lib/strtok.c | 2 +- Utilities/cmcurl/lib/strtok.h | 2 +- Utilities/cmcurl/lib/strtoofft.c | 2 +- Utilities/cmcurl/lib/strtoofft.h | 2 +- Utilities/cmcurl/lib/system_win32.c | 294 ++++ Utilities/cmcurl/lib/system_win32.h | 61 + Utilities/cmcurl/lib/telnet.c | 46 +- Utilities/cmcurl/lib/telnet.h | 2 +- Utilities/cmcurl/lib/tftp.c | 99 +- Utilities/cmcurl/lib/tftp.h | 2 +- Utilities/cmcurl/lib/timeval.c | 14 +- Utilities/cmcurl/lib/timeval.h | 2 +- Utilities/cmcurl/lib/transfer.c | 219 ++- Utilities/cmcurl/lib/transfer.h | 17 +- Utilities/cmcurl/lib/url.c | 1449 ++++++++++++-------- Utilities/cmcurl/lib/url.h | 40 +- Utilities/cmcurl/lib/urldata.h | 187 ++- Utilities/cmcurl/lib/vauth/cleartext.c | 157 +++ Utilities/cmcurl/lib/vauth/cram.c | 138 ++ Utilities/cmcurl/lib/vauth/digest.c | 883 ++++++++++++ .../cmcurl/lib/{strequal.h => vauth/digest.h} | 26 +- Utilities/cmcurl/lib/vauth/digest_sspi.c | 533 +++++++ .../{curl_sasl_gssapi.c => vauth/krb5_gssapi.c} | 175 ++- Utilities/cmcurl/lib/vauth/krb5_sspi.c | 496 +++++++ .../cmcurl/lib/{curl_ntlm_msgs.c => vauth/ntlm.c} | 65 +- .../cmcurl/lib/{curl_ntlm_msgs.h => vauth/ntlm.h} | 10 +- Utilities/cmcurl/lib/vauth/ntlm_sspi.c | 314 +++++ Utilities/cmcurl/lib/vauth/oauth2.c | 86 ++ Utilities/cmcurl/lib/vauth/spnego_gssapi.c | 260 ++++ Utilities/cmcurl/lib/vauth/spnego_sspi.c | 297 ++++ Utilities/cmcurl/lib/vauth/vauth.c | 106 ++ Utilities/cmcurl/lib/vauth/vauth.h | 189 +++ Utilities/cmcurl/lib/version.c | 40 +- Utilities/cmcurl/lib/vtls/axtls.c | 58 +- Utilities/cmcurl/lib/vtls/axtls.h | 4 +- Utilities/cmcurl/lib/vtls/cyassl.c | 203 ++- Utilities/cmcurl/lib/vtls/cyassl.h | 23 +- Utilities/cmcurl/lib/vtls/darwinssl.c | 111 +- Utilities/cmcurl/lib/vtls/darwinssl.h | 2 +- Utilities/cmcurl/lib/vtls/gskit.c | 36 +- Utilities/cmcurl/lib/vtls/gskit.h | 2 +- Utilities/cmcurl/lib/vtls/gtls.c | 116 +- Utilities/cmcurl/lib/vtls/gtls.h | 9 +- Utilities/cmcurl/lib/vtls/mbedtls.c | 871 ++++++++++++ Utilities/cmcurl/lib/vtls/mbedtls.h | 80 ++ Utilities/cmcurl/lib/vtls/nss.c | 113 +- Utilities/cmcurl/lib/vtls/nssg.h | 13 +- Utilities/cmcurl/lib/vtls/openssl.c | 998 +++++++------- Utilities/cmcurl/lib/vtls/openssl.h | 21 +- Utilities/cmcurl/lib/vtls/polarssl.c | 191 ++- Utilities/cmcurl/lib/vtls/polarssl.h | 18 +- Utilities/cmcurl/lib/vtls/polarssl_threadlock.c | 16 +- Utilities/cmcurl/lib/vtls/polarssl_threadlock.h | 22 +- Utilities/cmcurl/lib/vtls/schannel.c | 297 ++-- Utilities/cmcurl/lib/vtls/schannel.h | 5 +- Utilities/cmcurl/lib/vtls/vtls.c | 168 ++- Utilities/cmcurl/lib/vtls/vtls.h | 73 +- Utilities/cmcurl/lib/warnless.c | 61 +- Utilities/cmcurl/lib/warnless.h | 10 +- Utilities/cmcurl/lib/wildcard.c | 6 +- Utilities/cmcurl/lib/wildcard.h | 4 +- Utilities/cmcurl/lib/x509asn1.c | 31 +- Utilities/cmcurl/lib/x509asn1.h | 6 +- 261 files changed, 11892 insertions(+), 7488 deletions(-) create mode 100755 Utilities/Scripts/update-curl.bash delete mode 100644 Utilities/cmcurl/README-CMake.txt delete mode 100644 Utilities/cmcurl/lib/curl_sasl_sspi.c delete mode 100644 Utilities/cmcurl/lib/http_negotiate_sspi.c rename Utilities/cmcurl/lib/{curl_ntlm.c => http_ntlm.c} (91%) rename Utilities/cmcurl/lib/{curl_ntlm.h => http_ntlm.h} (95%) create mode 100644 Utilities/cmcurl/lib/system_win32.c create mode 100644 Utilities/cmcurl/lib/system_win32.h create mode 100644 Utilities/cmcurl/lib/vauth/cleartext.c create mode 100644 Utilities/cmcurl/lib/vauth/cram.c create mode 100644 Utilities/cmcurl/lib/vauth/digest.c copy Utilities/cmcurl/lib/{strequal.h => vauth/digest.h} (59%) create mode 100644 Utilities/cmcurl/lib/vauth/digest_sspi.c rename Utilities/cmcurl/lib/{curl_sasl_gssapi.c => vauth/krb5_gssapi.c} (66%) create mode 100644 Utilities/cmcurl/lib/vauth/krb5_sspi.c rename Utilities/cmcurl/lib/{curl_ntlm_msgs.c => vauth/ntlm.c} (94%) rename Utilities/cmcurl/lib/{curl_ntlm_msgs.h => vauth/ntlm.h} (95%) create mode 100644 Utilities/cmcurl/lib/vauth/ntlm_sspi.c create mode 100644 Utilities/cmcurl/lib/vauth/oauth2.c create mode 100644 Utilities/cmcurl/lib/vauth/spnego_gssapi.c create mode 100644 Utilities/cmcurl/lib/vauth/spnego_sspi.c create mode 100644 Utilities/cmcurl/lib/vauth/vauth.c create mode 100644 Utilities/cmcurl/lib/vauth/vauth.h create mode 100644 Utilities/cmcurl/lib/vtls/mbedtls.c create mode 100644 Utilities/cmcurl/lib/vtls/mbedtls.h hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 4 09:56:46 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 4 Aug 2016 09:56:46 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-551-gac7c12e Message-ID: <20160804135646.B1109F5160@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via ac7c12eced7ab3ba6d70a2c6cb95bb0e6ebbe024 (commit) via b602cb85c90bba26bff04d570bf108658016cf07 (commit) via 3e6ec47c421808123efac2cf67850f8b75839c67 (commit) from 85d966dcd7a29a17e42fde7b1c109e642f063d82 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ac7c12eced7ab3ba6d70a2c6cb95bb0e6ebbe024 commit ac7c12eced7ab3ba6d70a2c6cb95bb0e6ebbe024 Merge: 85d966d b602cb8 Author: Brad King AuthorDate: Thu Aug 4 09:56:44 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 4 09:56:44 2016 -0400 Merge topic 'update-kwsys' b602cb85 Merge branch 'upstream-KWSys' into update-kwsys 3e6ec47c KWSys 2016-08-02 (3f55579d) ----------------------------------------------------------------------- Summary of changes: Source/kwsys/SystemInformation.cxx | 15 +++------------ Source/kwsys/SystemTools.cxx | 5 +++++ 2 files changed, 8 insertions(+), 12 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 4 09:56:50 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 4 Aug 2016 09:56:50 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-554-g2df3719 Message-ID: <20160804135650.E7F13F51A9@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 2df3719d2c6d3426f5a6562c11cd8b0ef9830184 (commit) via cd52a225d298dc1a4924b82ebac0ac74fccf3356 (commit) via a354f60ce07cd67bd60161824a4e74bf9068fea4 (commit) from ac7c12eced7ab3ba6d70a2c6cb95bb0e6ebbe024 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2df3719d2c6d3426f5a6562c11cd8b0ef9830184 commit 2df3719d2c6d3426f5a6562c11cd8b0ef9830184 Merge: ac7c12e cd52a22 Author: Brad King AuthorDate: Thu Aug 4 09:56:47 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 4 09:56:47 2016 -0400 Merge topic 'extra-generator-factories' cd52a225 Report more information about extra generators in generator factories a354f60c Refactor extra generator registration to use factories ----------------------------------------------------------------------- Summary of changes: Source/cmExternalMakefileProjectGenerator.cxx | 49 ++++---- Source/cmExternalMakefileProjectGenerator.h | 55 +++++++-- Source/cmExtraCodeBlocksGenerator.cxx | 28 +++-- Source/cmExtraCodeBlocksGenerator.h | 13 +-- Source/cmExtraCodeLiteGenerator.cxx | 28 +++-- Source/cmExtraCodeLiteGenerator.h | 13 +-- Source/cmExtraEclipseCDT4Generator.cxx | 33 +++--- Source/cmExtraEclipseCDT4Generator.h | 14 +-- Source/cmExtraKateGenerator.cxx | 26 +++-- Source/cmExtraKateGenerator.h | 13 +-- Source/cmExtraSublimeTextGenerator.cxx | 30 +++-- Source/cmExtraSublimeTextGenerator.h | 14 +-- Source/cmGlobalKdevelopGenerator.cxx | 24 ++-- Source/cmGlobalKdevelopGenerator.h | 13 +-- Source/cmake.cxx | 152 +++++++++++++++---------- Source/cmake.h | 15 ++- 16 files changed, 285 insertions(+), 235 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 4 09:56:54 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 4 Aug 2016 09:56:54 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-556-g995b542 Message-ID: <20160804135654.A9443F5170@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 995b54256ede7752b5d6fde049097d15aa16c405 (commit) via ff386d1121ec52854d522d3bb9c86fab286d58ef (commit) from 2df3719d2c6d3426f5a6562c11cd8b0ef9830184 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=995b54256ede7752b5d6fde049097d15aa16c405 commit 995b54256ede7752b5d6fde049097d15aa16c405 Merge: 2df3719 ff386d1 Author: Brad King AuthorDate: Thu Aug 4 09:56:51 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 4 09:56:51 2016 -0400 Merge topic 'find-module-imported-fallback-to-release' ff386d11 Modules: Make imported targets fall back to `Release` ----------------------------------------------------------------------- Summary of changes: Modules/FindGTest.cmake | 28 ++++++++++++++-------------- Modules/FindIce.cmake | 14 +++++++------- Modules/FindOpenSSL.cmake | 28 ++++++++++++++-------------- Modules/FindPNG.cmake | 14 +++++++------- Modules/FindTIFF.cmake | 14 +++++++------- Modules/FindXalanC.cmake | 14 +++++++------- Modules/FindXercesC.cmake | 14 +++++++------- 7 files changed, 63 insertions(+), 63 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 4 09:58:53 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 4 Aug 2016 09:58:53 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1110-g448c588 Message-ID: <20160804135853.D440DF518A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 448c5887d042e2cd6ce938e939602134c1a7830a (commit) via 995b54256ede7752b5d6fde049097d15aa16c405 (commit) via 2df3719d2c6d3426f5a6562c11cd8b0ef9830184 (commit) via ac7c12eced7ab3ba6d70a2c6cb95bb0e6ebbe024 (commit) via 85d966dcd7a29a17e42fde7b1c109e642f063d82 (commit) from 5d4a3eda276b5dc2f98b61d5ed532e199e4c0ca8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=448c5887d042e2cd6ce938e939602134c1a7830a commit 448c5887d042e2cd6ce938e939602134c1a7830a Merge: 5d4a3ed 995b542 Author: Brad King AuthorDate: Thu Aug 4 09:58:45 2016 -0400 Commit: Brad King CommitDate: Thu Aug 4 09:58:45 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 4 10:19:18 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 4 Aug 2016 10:19:18 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1113-g144396b Message-ID: <20160804141919.5DFE0F45E2@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 144396b37723d63ddfbe3c6245adea884beb227a (commit) via 8abca14034c22014aead0fd4f3be737cd3835ce4 (commit) via 6c0820a8748e24155d3b7ce6991a90f5a396f524 (commit) from 448c5887d042e2cd6ce938e939602134c1a7830a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=144396b37723d63ddfbe3c6245adea884beb227a commit 144396b37723d63ddfbe3c6245adea884beb227a Merge: 448c588 8abca14 Author: Brad King AuthorDate: Thu Aug 4 10:19:15 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 4 10:19:15 2016 -0400 Merge topic 'update-kwsys' into next 8abca140 Merge branch 'upstream-KWSys' into update-kwsys 6c0820a8 KWSys 2016-08-03 (6d23dd7e) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8abca14034c22014aead0fd4f3be737cd3835ce4 commit 8abca14034c22014aead0fd4f3be737cd3835ce4 Merge: 995b542 6c0820a Author: Brad King AuthorDate: Thu Aug 4 10:11:07 2016 -0400 Commit: Brad King CommitDate: Thu Aug 4 10:11:07 2016 -0400 Merge branch 'upstream-KWSys' into update-kwsys * upstream-KWSys: KWSys 2016-08-03 (6d23dd7e) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6c0820a8748e24155d3b7ce6991a90f5a396f524 commit 6c0820a8748e24155d3b7ce6991a90f5a396f524 Author: KWSys Upstream AuthorDate: Wed Aug 3 12:32:48 2016 -0400 Commit: Brad King CommitDate: Thu Aug 4 10:11:06 2016 -0400 KWSys 2016-08-03 (6d23dd7e) Code extracted from: http://public.kitware.com/KWSys.git at commit 6d23dd7e455a7b2088c4ec6dce760d8243b84ee6 (master). Upstream Shortlog ----------------- Ben Boeckel (1): 6d23dd7e SystemTools: add a PathExists method diff --git a/SystemTools.cxx b/SystemTools.cxx index d479ee1..eb2bec6 100644 --- a/SystemTools.cxx +++ b/SystemTools.cxx @@ -1292,6 +1292,32 @@ bool SystemTools::SameFile(const std::string& file1, const std::string& file2) } //---------------------------------------------------------------------------- +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( + SystemTools::ConvertToWindowsExtendedPath(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) diff --git a/SystemTools.hxx.in b/SystemTools.hxx.in index aa1bf1b..28ff0b3 100644 --- a/SystemTools.hxx.in +++ b/SystemTools.hxx.in @@ -306,6 +306,11 @@ public: 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 diff --git a/testSystemTools.cxx b/testSystemTools.cxx index 4dab347..9252ea6 100644 --- a/testSystemTools.cxx +++ b/testSystemTools.cxx @@ -204,6 +204,14 @@ static bool CheckFileOperations() << 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)) { @@ -221,6 +229,15 @@ static bool CheckFileOperations() << 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())) { @@ -329,6 +346,31 @@ static bool CheckFileOperations() 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: " + << testNewDir << std::endl; + res = false; + } + // Reset umask #if defined(_WIN32) && !defined(__CYGWIN__) // NOTE: Windows doesn't support toggling _S_IREAD. ----------------------------------------------------------------------- Summary of changes: Source/kwsys/SystemTools.cxx | 26 +++++++++++++++++++++++ Source/kwsys/SystemTools.hxx.in | 5 +++++ Source/kwsys/testSystemTools.cxx | 42 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 4 11:41:30 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 4 Aug 2016 11:41:30 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1115-ga67e5b8 Message-ID: <20160804154131.14016B217E@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via a67e5b8ce377c119914fa8e0983defbbd3daf146 (commit) via 4ada475ef5e15fa72a2f075ec1efafce321c313c (commit) from 144396b37723d63ddfbe3c6245adea884beb227a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a67e5b8ce377c119914fa8e0983defbbd3daf146 commit a67e5b8ce377c119914fa8e0983defbbd3daf146 Merge: 144396b 4ada475 Author: Brad King AuthorDate: Thu Aug 4 11:41:28 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 4 11:41:28 2016 -0400 Merge topic 'vs14-debug-enum-older-toolsets' into next 4ada475e VS: Fix VS 2015 .vcxproj debug setting for Windows7.1SDK toolset diff --cc Source/cmVisualStudio10TargetGenerator.cxx index 7624f78,15fae42..b1885e5 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@@ -42,8 -42,10 +42,10 @@@ #include "cmVisualStudioGeneratorOptions.h" #include "windows.h" -#include +#include + static std::string const kWINDOWS_7_1_SDK = "Windows7.1SDK"; + cmIDEFlagTable const* cmVisualStudio10TargetGenerator::GetClFlagTable() const { if (this->MSTools) { https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4ada475ef5e15fa72a2f075ec1efafce321c313c commit 4ada475ef5e15fa72a2f075ec1efafce321c313c Author: Brad King AuthorDate: Thu Aug 4 11:40:09 2016 -0400 Commit: Brad King CommitDate: Thu Aug 4 11:40:09 2016 -0400 VS: Fix VS 2015 .vcxproj debug setting for Windows7.1SDK toolset Closes: #16213 diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index fb05976..15fae42 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -44,6 +44,8 @@ #include +static std::string const kWINDOWS_7_1_SDK = "Windows7.1SDK"; + cmIDEFlagTable const* cmVisualStudio10TargetGenerator::GetClFlagTable() const { if (this->MSTools) { @@ -2354,7 +2356,8 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( cmGlobalVisualStudio10Generator* gg = static_cast(this->GlobalGenerator); const char* toolset = gg->GetPlatformToolset(); - if (toolset && (cmHasLiteralPrefix(toolset, "v90") || + if (toolset && (toolset == kWINDOWS_7_1_SDK || + cmHasLiteralPrefix(toolset, "v90") || cmHasLiteralPrefix(toolset, "v100") || cmHasLiteralPrefix(toolset, "v110") || cmHasLiteralPrefix(toolset, "v120"))) { ----------------------------------------------------------------------- Summary of changes: Source/cmVisualStudio10TargetGenerator.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) hooks/post-receive -- CMake From chuck.atkins at kitware.com Thu Aug 4 15:26:54 2016 From: chuck.atkins at kitware.com (Chuck Atkins) Date: Thu, 4 Aug 2016 15:26:54 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1117-gf6773d2 Message-ID: <20160804192654.C0267F41FE@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via f6773d23c4ca2cf59726734aba131f2be36307f0 (commit) via 388147085e26ec8e8589640f2492cccfe14f3f8b (commit) from a67e5b8ce377c119914fa8e0983defbbd3daf146 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f6773d23c4ca2cf59726734aba131f2be36307f0 commit f6773d23c4ca2cf59726734aba131f2be36307f0 Merge: a67e5b8 3881470 Author: Chuck Atkins AuthorDate: Thu Aug 4 15:26:52 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 4 15:26:52 2016 -0400 Merge topic 'update-cle-version-info' into next 38814708 CrayLinuxEnvironment: Add alternative methods to retrive version info https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=388147085e26ec8e8589640f2492cccfe14f3f8b commit 388147085e26ec8e8589640f2492cccfe14f3f8b Author: Chuck Atkins AuthorDate: Thu Aug 4 14:46:10 2016 -0400 Commit: Chuck Atkins CommitDate: Thu Aug 4 13:20:37 2016 -0600 CrayLinuxEnvironment: Add alternative methods to retrive version info diff --git a/Modules/Platform/CrayLinuxEnvironment.cmake b/Modules/Platform/CrayLinuxEnvironment.cmake index 97771a2..301eb85 100644 --- a/Modules/Platform/CrayLinuxEnvironment.cmake +++ b/Modules/Platform/CrayLinuxEnvironment.cmake @@ -8,14 +8,22 @@ if(DEFINED ENV{CRAYOS_VERSION}) set(CMAKE_SYSTEM_VERSION "$ENV{CRAYOS_VERSION}") elseif(DEFINED ENV{XTOS_VERSION}) set(CMAKE_SYSTEM_VERSION "$ENV{XTOS_VERSION}") -else() - message(FATAL_ERROR "Neither the CRAYOS_VERSION or XTOS_VERSION environment variables are defined. This platform file should be used inside the Cray Linux Environment for targeting compute nodes (NIDs)") +elseif(EXISTS /etc/opt/cray/release/cle-release) + file(STRINGS /etc/opt/cray/release/cle-release release REGEX "^RELEASE=.*") + string(REGEX REPLACE "^RELEASE=(.*)$" "\\1" CMAKE_SYSTEM_VERSION "${release}") + unset(release) +elseif(EXISTS /etc/opt/cray/release/clerelease) + file(READ /etc/opt/cray/release/clerelease CMAKE_SYSTEM_VERSION) endif() # Guard against multiple messages if(NOT __CrayLinuxEnvironment_message) - set(__CrayLinuxEnvironment_message 1) - message(STATUS "Cray Linux Environment ${CMAKE_SYSTEM_VERSION}") + set(__CrayLinuxEnvironment_message 1 CACHE BOOL "" FORCE) + if(NOT CMAKE_SYSTEM_VERSION) + message(STATUS "CrayLinuxEnvironment: Unable to determine CLE version. This platform file should only be used from inside the Cray Linux Environment for targeting compute nodes (NIDs).") + else() + message(STATUS "Cray Linux Environment ${CMAKE_SYSTEM_VERSION}") + endif() endif() # All cray systems are x86 CPUs and have been for quite some time ----------------------------------------------------------------------- Summary of changes: Modules/Platform/CrayLinuxEnvironment.cmake | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) hooks/post-receive -- CMake From kwrobot at kitware.com Fri Aug 5 00:01:13 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Fri, 5 Aug 2016 00:01:13 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-557-g9bc6202 Message-ID: <20160805040113.15240F4BA9@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 9bc62024ac30d2adc69fd86c88c6d772769b79ac (commit) from 995b54256ede7752b5d6fde049097d15aa16c405 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9bc62024ac30d2adc69fd86c88c6d772769b79ac commit 9bc62024ac30d2adc69fd86c88c6d772769b79ac Author: Kitware Robot AuthorDate: Fri Aug 5 00:01:09 2016 -0400 Commit: Kitware Robot CommitDate: Fri Aug 5 00:01:09 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index f8782b2..6383bf6 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160804) +set(CMake_VERSION_PATCH 20160805) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 5 08:50:23 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 5 Aug 2016 08:50:23 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-559-gb06118f Message-ID: <20160805125023.CD715F4817@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via b06118f8f1f2dd13ee055f35d18068ece9ff6615 (commit) via 4ada475ef5e15fa72a2f075ec1efafce321c313c (commit) from 9bc62024ac30d2adc69fd86c88c6d772769b79ac (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b06118f8f1f2dd13ee055f35d18068ece9ff6615 commit b06118f8f1f2dd13ee055f35d18068ece9ff6615 Merge: 9bc6202 4ada475 Author: Brad King AuthorDate: Fri Aug 5 08:50:20 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 5 08:50:20 2016 -0400 Merge topic 'vs14-debug-enum-older-toolsets' 4ada475e VS: Fix VS 2015 .vcxproj debug setting for Windows7.1SDK toolset diff --cc Source/cmVisualStudio10TargetGenerator.cxx index 7624f78,15fae42..b1885e5 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@@ -42,8 -42,10 +42,10 @@@ #include "cmVisualStudioGeneratorOptions.h" #include "windows.h" -#include +#include + static std::string const kWINDOWS_7_1_SDK = "Windows7.1SDK"; + cmIDEFlagTable const* cmVisualStudio10TargetGenerator::GetClFlagTable() const { if (this->MSTools) { ----------------------------------------------------------------------- Summary of changes: Source/cmVisualStudio10TargetGenerator.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 5 08:50:27 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 5 Aug 2016 08:50:27 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-562-gbaa6032 Message-ID: <20160805125027.E2C21F4862@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via baa60321692b4991fbee54e448e9bc420105fe68 (commit) via 8abca14034c22014aead0fd4f3be737cd3835ce4 (commit) via 6c0820a8748e24155d3b7ce6991a90f5a396f524 (commit) from b06118f8f1f2dd13ee055f35d18068ece9ff6615 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=baa60321692b4991fbee54e448e9bc420105fe68 commit baa60321692b4991fbee54e448e9bc420105fe68 Merge: b06118f 8abca14 Author: Brad King AuthorDate: Fri Aug 5 08:50:25 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 5 08:50:25 2016 -0400 Merge topic 'update-kwsys' 8abca140 Merge branch 'upstream-KWSys' into update-kwsys 6c0820a8 KWSys 2016-08-03 (6d23dd7e) ----------------------------------------------------------------------- Summary of changes: Source/kwsys/SystemTools.cxx | 26 +++++++++++++++++++++++ Source/kwsys/SystemTools.hxx.in | 5 +++++ Source/kwsys/testSystemTools.cxx | 42 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 5 08:50:31 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 5 Aug 2016 08:50:31 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-564-g93b705a Message-ID: <20160805125031.910E4F4864@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 93b705a396c23f771ba203efb6f2f4934ae027b7 (commit) via e555480c60e95073840fe1a5f52004fd8ce81f9c (commit) from baa60321692b4991fbee54e448e9bc420105fe68 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=93b705a396c23f771ba203efb6f2f4934ae027b7 commit 93b705a396c23f771ba203efb6f2f4934ae027b7 Merge: baa6032 e555480 Author: Brad King AuthorDate: Fri Aug 5 08:50:29 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 5 08:50:29 2016 -0400 Merge topic 'ninja-clang-rsp-format' e555480c Ninja: Fix response file format for GNU-like Clang on Windows ----------------------------------------------------------------------- Summary of changes: Source/cmGlobalNinjaGenerator.cxx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 5 08:50:47 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 5 Aug 2016 08:50:47 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1122-g3e5ed14 Message-ID: <20160805125048.2855CF4838@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 3e5ed14eddd17e6f98aa6c3acdc342d4cb2b9c8a (commit) via 93b705a396c23f771ba203efb6f2f4934ae027b7 (commit) via baa60321692b4991fbee54e448e9bc420105fe68 (commit) via b06118f8f1f2dd13ee055f35d18068ece9ff6615 (commit) via 9bc62024ac30d2adc69fd86c88c6d772769b79ac (commit) from f6773d23c4ca2cf59726734aba131f2be36307f0 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3e5ed14eddd17e6f98aa6c3acdc342d4cb2b9c8a commit 3e5ed14eddd17e6f98aa6c3acdc342d4cb2b9c8a Merge: f6773d2 93b705a Author: Brad King AuthorDate: Fri Aug 5 08:50:39 2016 -0400 Commit: Brad King CommitDate: Fri Aug 5 08:50:39 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 5 08:55:02 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 5 Aug 2016 08:55:02 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1124-g721ea79 Message-ID: <20160805125503.47DC7F4C3F@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 721ea794cd31ba2c2e96d35eb7b15d97db5c4642 (commit) via fe7f117ad22c1f2884c47cb961ea33f1c88206a4 (commit) from 3e5ed14eddd17e6f98aa6c3acdc342d4cb2b9c8a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=721ea794cd31ba2c2e96d35eb7b15d97db5c4642 commit 721ea794cd31ba2c2e96d35eb7b15d97db5c4642 Merge: 3e5ed14 fe7f117 Author: Brad King AuthorDate: Fri Aug 5 08:55:00 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 5 08:55:00 2016 -0400 Merge topic 'bash-completion-fix-E-lookup' into next fe7f117a bash-completion: Fix cmake -E lookup https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=fe7f117ad22c1f2884c47cb961ea33f1c88206a4 commit fe7f117ad22c1f2884c47cb961ea33f1c88206a4 Author: Sylvain Joubert AuthorDate: Thu Aug 4 18:59:21 2016 +0200 Commit: Brad King CommitDate: Fri Aug 5 08:54:09 2016 -0400 bash-completion: Fix cmake -E lookup In case of long ' ' the description text is wrapped and indented on the next line. Avoid taking these lines into account by explicitly requiring the third character to be a non-space. diff --git a/Auxiliary/bash-completion/cmake b/Auxiliary/bash-completion/cmake index 6061129..0a862fa 100644 --- a/Auxiliary/bash-completion/cmake +++ b/Auxiliary/bash-completion/cmake @@ -102,7 +102,7 @@ _cmake() ;; -E) COMPREPLY=( $( compgen -W "$( cmake -E help |& sed -n \ - '/^ /{s|^ \([^ ]\{1,\}\) .*$|\1|;p}' 2>/dev/null )" \ + '/^ [^ ]/{s|^ \([^ ]\{1,\}\) .*$|\1|;p}' 2>/dev/null )" \ -- "$cur" ) ) return ;; ----------------------------------------------------------------------- Summary of changes: Auxiliary/bash-completion/cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From chuck.atkins at kitware.com Fri Aug 5 09:00:56 2016 From: chuck.atkins at kitware.com (Chuck Atkins) Date: Fri, 5 Aug 2016 09:00:56 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1126-gf4cc3c3 Message-ID: <20160805130056.AC652F50B8@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via f4cc3c36d7a704951d87abfd3031182871aa0d41 (commit) via 7e29fda9fc6f0081825d1961249d3e572f460b9f (commit) from 721ea794cd31ba2c2e96d35eb7b15d97db5c4642 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f4cc3c36d7a704951d87abfd3031182871aa0d41 commit f4cc3c36d7a704951d87abfd3031182871aa0d41 Merge: 721ea79 7e29fda Author: Chuck Atkins AuthorDate: Fri Aug 5 09:00:54 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 5 09:00:54 2016 -0400 Merge topic 'update-cle-version-info' into next 7e29fda9 Closes: #16229 https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7e29fda9fc6f0081825d1961249d3e572f460b9f commit 7e29fda9fc6f0081825d1961249d3e572f460b9f Author: Chuck Atkins AuthorDate: Fri Aug 5 08:58:27 2016 -0400 Commit: Chuck Atkins CommitDate: Fri Aug 5 08:59:55 2016 -0400 Closes: #16229 diff --git a/Modules/Compiler/CrayPrgEnv.cmake b/Modules/Compiler/CrayPrgEnv.cmake index fa39b00..9f8befd 100644 --- a/Modules/Compiler/CrayPrgEnv.cmake +++ b/Modules/Compiler/CrayPrgEnv.cmake @@ -56,6 +56,8 @@ macro(__CrayPrgEnv_setup lang test_src compiler_cmd link_cmd) message(STATUS "Cray Programming Environment $ENV{CRAYPE_VERSION} ${lang}") elseif(DEFINED ENV{ASYNCPE_VERSION}) message(STATUS "Cray XT Programming Environment $ENV{ASYNCPE_VERSION} ${lang}") + else() + message(STATUS "Cray Programming Environment (unknown version) ${lang}") endif() # Flags for the Cray wrappers diff --git a/Modules/Platform/CrayLinuxEnvironment.cmake b/Modules/Platform/CrayLinuxEnvironment.cmake index 301eb85..a1a3d3f 100644 --- a/Modules/Platform/CrayLinuxEnvironment.cmake +++ b/Modules/Platform/CrayLinuxEnvironment.cmake @@ -18,7 +18,7 @@ endif() # Guard against multiple messages if(NOT __CrayLinuxEnvironment_message) - set(__CrayLinuxEnvironment_message 1 CACHE BOOL "" FORCE) + set(__CrayLinuxEnvironment_message 1 CACHE INTERNAL "") if(NOT CMAKE_SYSTEM_VERSION) message(STATUS "CrayLinuxEnvironment: Unable to determine CLE version. This platform file should only be used from inside the Cray Linux Environment for targeting compute nodes (NIDs).") else() ----------------------------------------------------------------------- Summary of changes: Modules/Compiler/CrayPrgEnv.cmake | 2 ++ Modules/Platform/CrayLinuxEnvironment.cmake | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) hooks/post-receive -- CMake From chuck.atkins at kitware.com Fri Aug 5 09:02:49 2016 From: chuck.atkins at kitware.com (Chuck Atkins) Date: Fri, 5 Aug 2016 09:02:49 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1128-g05c29d6 Message-ID: <20160805130249.E1557F4D15@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 05c29d64b440766b28622db87d5ab91069ec2af7 (commit) via e52302d6cbee72c9d680affcf1f253bfa61f1891 (commit) from f4cc3c36d7a704951d87abfd3031182871aa0d41 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=05c29d64b440766b28622db87d5ab91069ec2af7 commit 05c29d64b440766b28622db87d5ab91069ec2af7 Merge: f4cc3c3 e52302d Author: Chuck Atkins AuthorDate: Fri Aug 5 09:02:49 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 5 09:02:49 2016 -0400 Merge topic 'update-cle-version-info' into next e52302d6 CrayLinuxEnvironment: Add alternative methods to get version info https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e52302d6cbee72c9d680affcf1f253bfa61f1891 commit e52302d6cbee72c9d680affcf1f253bfa61f1891 Author: Chuck Atkins AuthorDate: Thu Aug 4 14:46:10 2016 -0400 Commit: Chuck Atkins CommitDate: Fri Aug 5 09:01:43 2016 -0400 CrayLinuxEnvironment: Add alternative methods to get version info Closes: #16229 diff --git a/Modules/Compiler/CrayPrgEnv.cmake b/Modules/Compiler/CrayPrgEnv.cmake index fa39b00..9f8befd 100644 --- a/Modules/Compiler/CrayPrgEnv.cmake +++ b/Modules/Compiler/CrayPrgEnv.cmake @@ -56,6 +56,8 @@ macro(__CrayPrgEnv_setup lang test_src compiler_cmd link_cmd) message(STATUS "Cray Programming Environment $ENV{CRAYPE_VERSION} ${lang}") elseif(DEFINED ENV{ASYNCPE_VERSION}) message(STATUS "Cray XT Programming Environment $ENV{ASYNCPE_VERSION} ${lang}") + else() + message(STATUS "Cray Programming Environment (unknown version) ${lang}") endif() # Flags for the Cray wrappers diff --git a/Modules/Platform/CrayLinuxEnvironment.cmake b/Modules/Platform/CrayLinuxEnvironment.cmake index 97771a2..a1a3d3f 100644 --- a/Modules/Platform/CrayLinuxEnvironment.cmake +++ b/Modules/Platform/CrayLinuxEnvironment.cmake @@ -8,14 +8,22 @@ if(DEFINED ENV{CRAYOS_VERSION}) set(CMAKE_SYSTEM_VERSION "$ENV{CRAYOS_VERSION}") elseif(DEFINED ENV{XTOS_VERSION}) set(CMAKE_SYSTEM_VERSION "$ENV{XTOS_VERSION}") -else() - message(FATAL_ERROR "Neither the CRAYOS_VERSION or XTOS_VERSION environment variables are defined. This platform file should be used inside the Cray Linux Environment for targeting compute nodes (NIDs)") +elseif(EXISTS /etc/opt/cray/release/cle-release) + file(STRINGS /etc/opt/cray/release/cle-release release REGEX "^RELEASE=.*") + string(REGEX REPLACE "^RELEASE=(.*)$" "\\1" CMAKE_SYSTEM_VERSION "${release}") + unset(release) +elseif(EXISTS /etc/opt/cray/release/clerelease) + file(READ /etc/opt/cray/release/clerelease CMAKE_SYSTEM_VERSION) endif() # Guard against multiple messages if(NOT __CrayLinuxEnvironment_message) - set(__CrayLinuxEnvironment_message 1) - message(STATUS "Cray Linux Environment ${CMAKE_SYSTEM_VERSION}") + set(__CrayLinuxEnvironment_message 1 CACHE INTERNAL "") + if(NOT CMAKE_SYSTEM_VERSION) + message(STATUS "CrayLinuxEnvironment: Unable to determine CLE version. This platform file should only be used from inside the Cray Linux Environment for targeting compute nodes (NIDs).") + else() + message(STATUS "Cray Linux Environment ${CMAKE_SYSTEM_VERSION}") + endif() endif() # All cray systems are x86 CPUs and have been for quite some time ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 5 15:21:03 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 5 Aug 2016 15:21:03 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1130-g435e2ab Message-ID: <20160805192103.822A9F4E72@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 435e2ab79c7f293254eab39a5a4150883e9066ca (commit) via 038e3a4f718bcf6936065beecf886f7c1fc178cc (commit) from 05c29d64b440766b28622db87d5ab91069ec2af7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=435e2ab79c7f293254eab39a5a4150883e9066ca commit 435e2ab79c7f293254eab39a5a4150883e9066ca Merge: 05c29d6 038e3a4 Author: Brad King AuthorDate: Fri Aug 5 15:21:00 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 5 15:21:00 2016 -0400 Merge topic 'vs14-debug-enum-older-toolsets' into next 038e3a4f cmVisualStudio10TargetGenerator: Run clang-format https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=038e3a4f718bcf6936065beecf886f7c1fc178cc commit 038e3a4f718bcf6936065beecf886f7c1fc178cc Author: Brad King AuthorDate: Fri Aug 5 15:20:20 2016 -0400 Commit: Brad King CommitDate: Fri Aug 5 15:20:20 2016 -0400 cmVisualStudio10TargetGenerator: Run clang-format diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 15fae42..11dc28c 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2356,11 +2356,11 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( cmGlobalVisualStudio10Generator* gg = static_cast(this->GlobalGenerator); const char* toolset = gg->GetPlatformToolset(); - if (toolset && (toolset == kWINDOWS_7_1_SDK || - cmHasLiteralPrefix(toolset, "v90") || - cmHasLiteralPrefix(toolset, "v100") || - cmHasLiteralPrefix(toolset, "v110") || - cmHasLiteralPrefix(toolset, "v120"))) { + if (toolset && + (toolset == kWINDOWS_7_1_SDK || cmHasLiteralPrefix(toolset, "v90") || + cmHasLiteralPrefix(toolset, "v100") || + cmHasLiteralPrefix(toolset, "v110") || + cmHasLiteralPrefix(toolset, "v120"))) { if (const char* debug = linkOptions.GetFlag("GenerateDebugInformation")) { // Convert value from enumeration back to boolean for older toolsets. ----------------------------------------------------------------------- Summary of changes: Source/cmVisualStudio10TargetGenerator.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) hooks/post-receive -- CMake From kwrobot at kitware.com Sat Aug 6 00:01:06 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Sat, 6 Aug 2016 00:01:06 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-565-g6da5fb8 Message-ID: <20160806040106.876D6F518A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 6da5fb8379dd1ced9a39c51c534e0252da111950 (commit) from 93b705a396c23f771ba203efb6f2f4934ae027b7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6da5fb8379dd1ced9a39c51c534e0252da111950 commit 6da5fb8379dd1ced9a39c51c534e0252da111950 Author: Kitware Robot AuthorDate: Sat Aug 6 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Sat Aug 6 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 6383bf6..3fbd76c 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160805) +set(CMake_VERSION_PATCH 20160806) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From kwrobot at kitware.com Sun Aug 7 00:01:07 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Sun, 7 Aug 2016 00:01:07 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-566-g5a8b67b Message-ID: <20160807040107.D6DF7F4D15@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 5a8b67b3de0e09abf5104bbf68e5eb4e74d34786 (commit) from 6da5fb8379dd1ced9a39c51c534e0252da111950 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5a8b67b3de0e09abf5104bbf68e5eb4e74d34786 commit 5a8b67b3de0e09abf5104bbf68e5eb4e74d34786 Author: Kitware Robot AuthorDate: Sun Aug 7 00:01:03 2016 -0400 Commit: Kitware Robot CommitDate: Sun Aug 7 00:01:03 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 3fbd76c..faf0a12 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160806) +set(CMake_VERSION_PATCH 20160807) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From cmake at anteru.net Sun Aug 7 13:43:40 2016 From: cmake at anteru.net (Matthaus G. Chajdas) Date: Sun, 7 Aug 2016 13:43:40 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1134-g8c38d8e Message-ID: <20160807174340.57609F2D0A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 8c38d8ed5f41f8b57e94b1e9dff923462f992d87 (commit) via 48dc6343bba3b3f296d35ab060681c50f0eb8cde (commit) via 5a8b67b3de0e09abf5104bbf68e5eb4e74d34786 (commit) via 6da5fb8379dd1ced9a39c51c534e0252da111950 (commit) from 435e2ab79c7f293254eab39a5a4150883e9066ca (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8c38d8ed5f41f8b57e94b1e9dff923462f992d87 commit 8c38d8ed5f41f8b57e94b1e9dff923462f992d87 Merge: 435e2ab 48dc634 Author: Matthaus G. Chajdas AuthorDate: Sun Aug 7 13:43:39 2016 -0400 Commit: CMake Topic Stage CommitDate: Sun Aug 7 13:43:39 2016 -0400 Merge topic 'fix-findopencl-on-mac-os' into next 48dc6343 Fix search for OpenCL on macOS. 5a8b67b3 CMake Nightly Date Stamp 6da5fb83 CMake Nightly Date Stamp https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=48dc6343bba3b3f296d35ab060681c50f0eb8cde commit 48dc6343bba3b3f296d35ab060681c50f0eb8cde Author: Matth?us G. Chajdas AuthorDate: Sun Aug 7 19:38:35 2016 +0200 Commit: Matth?us G. Chajdas CommitDate: Sun Aug 7 19:42:46 2016 +0200 Fix search for OpenCL on macOS. The original patch was provided by jerry . diff --git a/Modules/FindOpenCL.cmake b/Modules/FindOpenCL.cmake index feda315..6acda55 100644 --- a/Modules/FindOpenCL.cmake +++ b/Modules/FindOpenCL.cmake @@ -53,7 +53,7 @@ function(_FIND_OPENCL_VERSION) if(APPLE) CHECK_SYMBOL_EXISTS( CL_VERSION_${VERSION} - "${OpenCL_INCLUDE_DIR}/OpenCL/cl.h" + "${OpenCL_INCLUDE_DIR}/Headers/cl.h" OPENCL_VERSION_${VERSION}) else() CHECK_SYMBOL_EXISTS( @@ -145,8 +145,15 @@ mark_as_advanced( OpenCL_LIBRARY) if(OpenCL_FOUND AND NOT TARGET OpenCL::OpenCL) - add_library(OpenCL::OpenCL UNKNOWN IMPORTED) + if(OpenCL_LIBRARY MATCHES "/([^/]+)\\.framework$") + add_library(OpenCL::OpenCL INTERFACE IMPORTED) + set_target_properties(OpenCL::OpenCL PROPERTIES + INTERFACE_LINK_LIBRARIES "${OpenCL_LIBRARY}") + else() + add_library(OpenCL::OpenCL UNKNOWN IMPORTED) + set_target_properties(OpenCL::OpenCL PROPERTIES + IMPORTED_LOCATION "${OpenCL_LIBRARY}") + endif() set_target_properties(OpenCL::OpenCL PROPERTIES - IMPORTED_LOCATION "${OpenCL_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${OpenCL_INCLUDE_DIRS}") endif() ----------------------------------------------------------------------- Summary of changes: Modules/FindOpenCL.cmake | 13 ++++++++++--- Source/CMakeVersion.cmake | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) hooks/post-receive -- CMake From kwrobot at kitware.com Mon Aug 8 00:01:12 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Mon, 8 Aug 2016 00:01:12 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-567-g5a62e0c Message-ID: <20160808040116.19CBCF4CEC@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 5a62e0c1721281503c8b4cd9d4d3d0de8abebf0f (commit) from 5a8b67b3de0e09abf5104bbf68e5eb4e74d34786 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5a62e0c1721281503c8b4cd9d4d3d0de8abebf0f commit 5a62e0c1721281503c8b4cd9d4d3d0de8abebf0f Author: Kitware Robot AuthorDate: Mon Aug 8 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Mon Aug 8 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index faf0a12..8af6031 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160807) +set(CMake_VERSION_PATCH 20160808) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From nilsgladitz at gmail.com Mon Aug 8 08:46:37 2016 From: nilsgladitz at gmail.com (Nils Gladitz) Date: Mon, 8 Aug 2016 08:46:37 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1137-g25bd0c3 Message-ID: <20160808124638.621D3F3CBE@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 25bd0c3824b55ba10c23bc837ca28879487686bc (commit) via 17bbf6af1ecca15194a693d31fdd8163aacfd994 (commit) via 5a62e0c1721281503c8b4cd9d4d3d0de8abebf0f (commit) from 8c38d8ed5f41f8b57e94b1e9dff923462f992d87 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=25bd0c3824b55ba10c23bc837ca28879487686bc commit 25bd0c3824b55ba10c23bc837ca28879487686bc Merge: 8c38d8e 17bbf6a Author: Nils Gladitz AuthorDate: Mon Aug 8 08:46:35 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 8 08:46:35 2016 -0400 Merge topic 'wix-custom-install-dir' into next 17bbf6af CPackWIX: Implement new CPACK_WIX_SKIP_PROGRAM_FOLDER feature 5a62e0c1 CMake Nightly Date Stamp https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=17bbf6af1ecca15194a693d31fdd8163aacfd994 commit 17bbf6af1ecca15194a693d31fdd8163aacfd994 Author: Michael St?rmer AuthorDate: Wed Jul 20 15:32:38 2016 +0200 Commit: Nils Gladitz CommitDate: Mon Aug 8 13:42:23 2016 +0200 CPackWIX: Implement new CPACK_WIX_SKIP_PROGRAM_FOLDER feature The new variable allows setting of a custom absolute installation prefix outside of the ProgramFiles folders. diff --git a/Help/release/dev/wix-custom-install-dir.rst b/Help/release/dev/wix-custom-install-dir.rst new file mode 100644 index 0000000..cd12a88 --- /dev/null +++ b/Help/release/dev/wix-custom-install-dir.rst @@ -0,0 +1,7 @@ +wix-custom-install-dir +---------------------- + +* The CPack WIX generator now supports + :variable:`CPACK_WIX_SKIP_PROGRAM_FOLDER` to allow specification + of a custom absolute installation prefix outside + of the ProgramFiles folders. diff --git a/Modules/CPackWIX.cmake b/Modules/CPackWIX.cmake index 10926c0..08ff0cb 100644 --- a/Modules/CPackWIX.cmake +++ b/Modules/CPackWIX.cmake @@ -248,6 +248,23 @@ # Sets the description of the root install feature in the WIX installer. Same as # CPACK_COMPONENT__DESCRIPTION for components. # +# .. variable:: CPACK_WIX_SKIP_PROGRAM_FOLDER +# +# If this variable is set to true, the default install location +# of the generated package will be CPACK_PACKAGE_INSTALL_DIRECTORY directly. +# The install location will not be located relatively below +# ProgramFiles or ProgramFiles64. +# +# .. note:: +# Installers created with this feature do not take differences +# between the system on which the installer is created +# and the system on which the installer might be used into account. +# +# It is therefor possible that the installer e.g. might try to install +# onto a drive that is unavailable or unintended or a path that does not +# follow the localization or convention of the system on which the +# installation is performed. +# #============================================================================= # Copyright 2014-2015 Kitware, Inc. diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index 3ecc14d..d7f69a1 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -18,6 +18,7 @@ #include #include #include +#include #include "cmWIXDirectoriesSourceWriter.h" #include "cmWIXFeaturesSourceWriter.h" @@ -441,6 +442,11 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() cmWIXFilesSourceWriter fileDefinitions(this->Logger, fileDefinitionsFilename); + // if install folder is supposed to be set absolutely, the default + // component guid "*" cannot be used + fileDefinitions.GenerateComponentGuids = + cmSystemTools::IsOn(GetOption("CPACK_WIX_SKIP_PROGRAM_FOLDER")); + fileDefinitions.BeginElement("Fragment"); std::string featureDefinitionsFilename = @@ -566,6 +572,9 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() std::string cmCPackWIXGenerator::GetProgramFilesFolderId() const { + if (cmSystemTools::IsOn(GetOption("CPACK_WIX_SKIP_PROGRAM_FOLDER"))) { + return ""; + } if (GetArchitecture() == "x86") { return "ProgramFilesFolder"; } else { diff --git a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx index de64059..97e3a51 100644 --- a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx +++ b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx @@ -52,8 +52,12 @@ size_t cmWIXDirectoriesSourceWriter::BeginInstallationPrefixDirectory( std::string const& programFilesFolderId, std::string const& installRootString) { - BeginElement("Directory"); - AddAttribute("Id", programFilesFolderId); + size_t offset = 1; + if (!programFilesFolderId.empty()) { + BeginElement("Directory"); + AddAttribute("Id", programFilesFolderId); + offset = 0; + } std::vector installRoot; @@ -77,7 +81,7 @@ size_t cmWIXDirectoriesSourceWriter::BeginInstallationPrefixDirectory( AddAttribute("Name", installRoot[i]); } - return installRoot.size(); + return installRoot.size() - offset; } void cmWIXDirectoriesSourceWriter::EndInstallationPrefixDirectory(size_t size) diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx index 9a143cc..dde9635 100644 --- a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx +++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx @@ -16,6 +16,9 @@ #include +#include +#include + #include // include sys/stat.h after sys/types.h #include @@ -23,6 +26,7 @@ cmWIXFilesSourceWriter::cmWIXFilesSourceWriter(cmCPackLog* logger, std::string const& filename) : cmWIXSourceWriter(logger, filename) + , GenerateComponentGuids(false) { } @@ -126,12 +130,20 @@ std::string cmWIXFilesSourceWriter::EmitComponentFile( std::string componentId = std::string("CM_C") + id; std::string fileId = std::string("CM_F") + id; + std::string guid = "*"; + if (this->GenerateComponentGuids) { + std::string md5 = cmSystemTools::ComputeStringMD5(componentId); + cmUuid uuid; + std::vector ns; + guid = uuid.FromMd5(ns, md5); + } + BeginElement("DirectoryRef"); AddAttribute("Id", directoryId); BeginElement("Component"); AddAttribute("Id", componentId); - AddAttribute("Guid", "*"); + AddAttribute("Guid", guid); if (installedFile) { if (installedFile->GetPropertyAsBool("CPACK_NEVER_OVERWRITE")) { diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.h b/Source/CPack/WiX/cmWIXFilesSourceWriter.h index c577e5b..eeb84cb 100644 --- a/Source/CPack/WiX/cmWIXFilesSourceWriter.h +++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.h @@ -47,6 +47,8 @@ public: std::string const& id, std::string const& filePath, cmWIXPatch& patch, cmInstalledFile const* installedFile); + + bool GenerateComponentGuids; }; #endif ----------------------------------------------------------------------- Summary of changes: Help/release/dev/wix-custom-install-dir.rst | 7 +++++++ Modules/CPackWIX.cmake | 17 +++++++++++++++++ Source/CMakeVersion.cmake | 2 +- Source/CPack/WiX/cmCPackWIXGenerator.cxx | 9 +++++++++ Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx | 10 +++++++--- Source/CPack/WiX/cmWIXFilesSourceWriter.cxx | 14 +++++++++++++- Source/CPack/WiX/cmWIXFilesSourceWriter.h | 2 ++ 7 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 Help/release/dev/wix-custom-install-dir.rst hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 8 10:01:04 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 8 Aug 2016 10:01:04 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1139-g4e757ba Message-ID: <20160808140104.491DDF5361@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 4e757ba79f569463d57ddbe327ab21882214db70 (commit) via 88f2455f04ace2b5b9bf4462344bcfb52fabc85e (commit) from 25bd0c3824b55ba10c23bc837ca28879487686bc (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4e757ba79f569463d57ddbe327ab21882214db70 commit 4e757ba79f569463d57ddbe327ab21882214db70 Merge: 25bd0c3 88f2455 Author: Brad King AuthorDate: Mon Aug 8 10:01:03 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 8 10:01:03 2016 -0400 Merge topic 'FindOpenCL-macOS' into next 88f2455f FindOpenCL: Fix search on macOS. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=88f2455f04ace2b5b9bf4462344bcfb52fabc85e commit 88f2455f04ace2b5b9bf4462344bcfb52fabc85e Author: Matth?us G. Chajdas AuthorDate: Sun Aug 7 19:38:35 2016 +0200 Commit: Brad King CommitDate: Mon Aug 8 09:57:30 2016 -0400 FindOpenCL: Fix search on macOS. The original patch was provided by jerry . diff --git a/Modules/FindOpenCL.cmake b/Modules/FindOpenCL.cmake index feda315..6acda55 100644 --- a/Modules/FindOpenCL.cmake +++ b/Modules/FindOpenCL.cmake @@ -53,7 +53,7 @@ function(_FIND_OPENCL_VERSION) if(APPLE) CHECK_SYMBOL_EXISTS( CL_VERSION_${VERSION} - "${OpenCL_INCLUDE_DIR}/OpenCL/cl.h" + "${OpenCL_INCLUDE_DIR}/Headers/cl.h" OPENCL_VERSION_${VERSION}) else() CHECK_SYMBOL_EXISTS( @@ -145,8 +145,15 @@ mark_as_advanced( OpenCL_LIBRARY) if(OpenCL_FOUND AND NOT TARGET OpenCL::OpenCL) - add_library(OpenCL::OpenCL UNKNOWN IMPORTED) + if(OpenCL_LIBRARY MATCHES "/([^/]+)\\.framework$") + add_library(OpenCL::OpenCL INTERFACE IMPORTED) + set_target_properties(OpenCL::OpenCL PROPERTIES + INTERFACE_LINK_LIBRARIES "${OpenCL_LIBRARY}") + else() + add_library(OpenCL::OpenCL UNKNOWN IMPORTED) + set_target_properties(OpenCL::OpenCL PROPERTIES + IMPORTED_LOCATION "${OpenCL_LIBRARY}") + endif() set_target_properties(OpenCL::OpenCL PROPERTIES - IMPORTED_LOCATION "${OpenCL_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${OpenCL_INCLUDE_DIRS}") endif() ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 8 10:02:05 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 8 Aug 2016 10:02:05 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-569-g702a548 Message-ID: <20160808140206.34A69F5377@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 702a5489929afd1e16adf5a2123b906e4f398e2b (commit) via 038e3a4f718bcf6936065beecf886f7c1fc178cc (commit) from 5a62e0c1721281503c8b4cd9d4d3d0de8abebf0f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=702a5489929afd1e16adf5a2123b906e4f398e2b commit 702a5489929afd1e16adf5a2123b906e4f398e2b Merge: 5a62e0c 038e3a4 Author: Brad King AuthorDate: Mon Aug 8 10:02:03 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 8 10:02:03 2016 -0400 Merge topic 'vs14-debug-enum-older-toolsets' 038e3a4f cmVisualStudio10TargetGenerator: Run clang-format ----------------------------------------------------------------------- Summary of changes: Source/cmVisualStudio10TargetGenerator.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 8 10:02:09 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 8 Aug 2016 10:02:09 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-571-gacf6fc6 Message-ID: <20160808140210.335FCF5377@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via acf6fc6a7e95175796bb25c9be05ba26bf372b53 (commit) via 88f2455f04ace2b5b9bf4462344bcfb52fabc85e (commit) from 702a5489929afd1e16adf5a2123b906e4f398e2b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=acf6fc6a7e95175796bb25c9be05ba26bf372b53 commit acf6fc6a7e95175796bb25c9be05ba26bf372b53 Merge: 702a548 88f2455 Author: Brad King AuthorDate: Mon Aug 8 10:02:07 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 8 10:02:07 2016 -0400 Merge topic 'FindOpenCL-macOS' 88f2455f FindOpenCL: Fix search on macOS. ----------------------------------------------------------------------- Summary of changes: Modules/FindOpenCL.cmake | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 8 10:02:13 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 8 Aug 2016 10:02:13 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-573-g314a953 Message-ID: <20160808140213.961A0F53A0@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 314a953982f50f355bf552d07a9d404cc8c5ec87 (commit) via e52302d6cbee72c9d680affcf1f253bfa61f1891 (commit) from acf6fc6a7e95175796bb25c9be05ba26bf372b53 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=314a953982f50f355bf552d07a9d404cc8c5ec87 commit 314a953982f50f355bf552d07a9d404cc8c5ec87 Merge: acf6fc6 e52302d Author: Brad King AuthorDate: Mon Aug 8 10:02:11 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 8 10:02:11 2016 -0400 Merge topic 'update-cle-version-info' e52302d6 CrayLinuxEnvironment: Add alternative methods to get version info ----------------------------------------------------------------------- Summary of changes: Modules/Compiler/CrayPrgEnv.cmake | 2 ++ Modules/Platform/CrayLinuxEnvironment.cmake | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 8 10:02:17 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 8 Aug 2016 10:02:17 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-575-g9bb2faf Message-ID: <20160808140221.0E051F5386@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 9bb2faf62a495539a81da7968921b8f95870e03f (commit) via fe7f117ad22c1f2884c47cb961ea33f1c88206a4 (commit) from 314a953982f50f355bf552d07a9d404cc8c5ec87 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9bb2faf62a495539a81da7968921b8f95870e03f commit 9bb2faf62a495539a81da7968921b8f95870e03f Merge: 314a953 fe7f117 Author: Brad King AuthorDate: Mon Aug 8 10:02:15 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 8 10:02:15 2016 -0400 Merge topic 'bash-completion-fix-E-lookup' fe7f117a bash-completion: Fix cmake -E lookup ----------------------------------------------------------------------- Summary of changes: Auxiliary/bash-completion/cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 8 10:02:45 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 8 Aug 2016 10:02:45 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1144-g00d115a Message-ID: <20160808140246.C80B0F5385@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 00d115a1dc184ae5921040d493200090a9dddaeb (commit) via 9bb2faf62a495539a81da7968921b8f95870e03f (commit) via 314a953982f50f355bf552d07a9d404cc8c5ec87 (commit) via acf6fc6a7e95175796bb25c9be05ba26bf372b53 (commit) via 702a5489929afd1e16adf5a2123b906e4f398e2b (commit) from 4e757ba79f569463d57ddbe327ab21882214db70 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=00d115a1dc184ae5921040d493200090a9dddaeb commit 00d115a1dc184ae5921040d493200090a9dddaeb Merge: 4e757ba 9bb2faf Author: Brad King AuthorDate: Mon Aug 8 10:02:37 2016 -0400 Commit: Brad King CommitDate: Mon Aug 8 10:02:37 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 8 10:05:35 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 8 Aug 2016 10:05:35 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-583-gee9d4fe Message-ID: <20160808140535.4FD90F5418@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via ee9d4feb67f01686c270d3db584dfccaefd14b47 (commit) via 7da3df3fb617f4fc87d7fbc672e4968120a2ca7b (commit) via 054275c6d6caceb1b8c0d221aab65bc8f74e2c4e (commit) via 926886a41c5d0784ec432703585b2b81aef165a6 (commit) via 5bcbc3857fd9976389d8eee3bb54e352ea950aec (commit) via 236050153cea703e120e8b616ba785772a01819d (commit) via 88f4b4c9e03fae6cda2160b5f96b23ce42ce0b78 (commit) via 3c57905dcf9a458d403f25b451bab5f525c3ac61 (commit) from 9bb2faf62a495539a81da7968921b8f95870e03f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 8 10:05:35 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 8 Aug 2016 10:05:35 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1153-g4a5e3be Message-ID: <20160808140535.86B8DF540F@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 4a5e3beb82eca0e2a1358c3eddfe41939ebdcdb8 (commit) via ee9d4feb67f01686c270d3db584dfccaefd14b47 (commit) via 7da3df3fb617f4fc87d7fbc672e4968120a2ca7b (commit) via 054275c6d6caceb1b8c0d221aab65bc8f74e2c4e (commit) via 926886a41c5d0784ec432703585b2b81aef165a6 (commit) via 5bcbc3857fd9976389d8eee3bb54e352ea950aec (commit) via 236050153cea703e120e8b616ba785772a01819d (commit) via 88f4b4c9e03fae6cda2160b5f96b23ce42ce0b78 (commit) via 3c57905dcf9a458d403f25b451bab5f525c3ac61 (commit) from 00d115a1dc184ae5921040d493200090a9dddaeb (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4a5e3beb82eca0e2a1358c3eddfe41939ebdcdb8 commit 4a5e3beb82eca0e2a1358c3eddfe41939ebdcdb8 Merge: 00d115a ee9d4fe Author: Brad King AuthorDate: Mon Aug 8 10:04:17 2016 -0400 Commit: Brad King CommitDate: Mon Aug 8 10:04:17 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 8 10:05:36 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 8 Aug 2016 10:05:36 -0400 (EDT) Subject: [Cmake-commits] CMake branch, release, updated. v3.6.1-20-g7da3df3 Message-ID: <20160808140537.A7499F5421@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, release has been updated via 7da3df3fb617f4fc87d7fbc672e4968120a2ca7b (commit) via 054275c6d6caceb1b8c0d221aab65bc8f74e2c4e (commit) via 926886a41c5d0784ec432703585b2b81aef165a6 (commit) via e52302d6cbee72c9d680affcf1f253bfa61f1891 (commit) via 5bcbc3857fd9976389d8eee3bb54e352ea950aec (commit) via f59ab43370dc9bff7e6480032c95505cdd00e3cd (commit) via f53f4a8a2d215dac634effea575a27e000dfcb29 (commit) via 202adcfe056681109fe61569ecdb3bd69f0b4f97 (commit) via e1c11352f231ae310339cd539ed59cb302bd4dbe (commit) via a51c6c5394169f34480e7261ef666eb4bf898c67 (commit) via 7ec709d3d7cc988d4cf6dc2c49713d4c55f09542 (commit) via 3e9b03439f6fa16abf555f37016e0f45f2073b78 (commit) via 236050153cea703e120e8b616ba785772a01819d (commit) via 088f14eb725650158d256c28e86e44da3989ad9c (commit) via 27a3ca15e5e92abbdf9228a5ac83c190a5caf0a8 (commit) via cc223e1eed69775a323a59628ad93fc79390c2f2 (commit) via 88f4b4c9e03fae6cda2160b5f96b23ce42ce0b78 (commit) via 3c57905dcf9a458d403f25b451bab5f525c3ac61 (commit) via 5790d9b6f5ae0b5bb8b0f2e4ec630a690b4b0301 (commit) via 8eb0b56c2ace0f005cba436268337f509e06033f (commit) from f59513140bf086eda2029c5b4e950fc58216c06e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- ----------------------------------------------------------------------- Summary of changes: Modules/Compiler/CrayPrgEnv.cmake | 2 + Modules/Compiler/Intel-C.cmake | 8 +- Modules/FindHDF5.cmake | 2 +- Modules/FindProtobuf.cmake | 8 + Modules/Platform/CrayLinuxEnvironment.cmake | 16 +- Source/cmVisualStudio10TargetGenerator.cxx | 11 +- Utilities/Scripts/update-curl.bash | 38 + Utilities/cmcurl/CMake/CurlTests.c | 2 +- Utilities/cmcurl/CMake/OtherTests.cmake | 2 +- Utilities/cmcurl/CMakeLists.txt | 182 +-- Utilities/cmcurl/COPYING | 3 +- Utilities/cmcurl/README-CMake.txt | 66 - Utilities/cmcurl/include/curl/curl.h | 243 ++-- Utilities/cmcurl/include/curl/curlbuild.h.cmake | 4 +- Utilities/cmcurl/include/curl/curlrules.h | 4 +- Utilities/cmcurl/include/curl/curlver.h | 14 +- Utilities/cmcurl/include/curl/easy.h | 2 +- Utilities/cmcurl/include/curl/mprintf.h | 30 +- Utilities/cmcurl/include/curl/multi.h | 8 +- Utilities/cmcurl/include/curl/stdcheaders.h | 2 +- Utilities/cmcurl/include/curl/typecheck-gcc.h | 124 +- Utilities/cmcurl/lib/Makefile.inc | 41 +- Utilities/cmcurl/lib/amigaos.c | 6 +- Utilities/cmcurl/lib/amigaos.h | 2 +- Utilities/cmcurl/lib/arpa_telnet.h | 2 +- Utilities/cmcurl/lib/asyn-ares.c | 24 +- Utilities/cmcurl/lib/asyn-thread.c | 31 +- Utilities/cmcurl/lib/asyn.h | 4 +- Utilities/cmcurl/lib/base64.c | 44 +- Utilities/cmcurl/lib/conncache.c | 24 +- Utilities/cmcurl/lib/conncache.h | 2 +- Utilities/cmcurl/lib/connect.c | 133 +- Utilities/cmcurl/lib/connect.h | 14 +- Utilities/cmcurl/lib/content_encoding.c | 6 +- Utilities/cmcurl/lib/content_encoding.h | 2 +- Utilities/cmcurl/lib/cookie.c | 122 +- Utilities/cmcurl/lib/cookie.h | 14 +- Utilities/cmcurl/lib/curl_addrinfo.c | 44 +- Utilities/cmcurl/lib/curl_addrinfo.h | 15 +- Utilities/cmcurl/lib/curl_base64.h | 6 +- Utilities/cmcurl/lib/curl_config.h.cmake | 27 + Utilities/cmcurl/lib/curl_des.c | 6 +- Utilities/cmcurl/lib/curl_des.h | 6 +- Utilities/cmcurl/lib/curl_endian.c | 2 +- Utilities/cmcurl/lib/curl_endian.h | 2 +- Utilities/cmcurl/lib/curl_fnmatch.c | 6 +- Utilities/cmcurl/lib/curl_fnmatch.h | 2 +- Utilities/cmcurl/lib/curl_gethostname.c | 2 +- Utilities/cmcurl/lib/curl_gethostname.h | 2 +- Utilities/cmcurl/lib/curl_gssapi.c | 65 +- Utilities/cmcurl/lib/curl_gssapi.h | 8 +- Utilities/cmcurl/lib/curl_hmac.h | 2 +- Utilities/cmcurl/lib/curl_ldap.h | 2 +- Utilities/cmcurl/lib/curl_md4.h | 2 +- Utilities/cmcurl/lib/curl_md5.h | 2 +- Utilities/cmcurl/lib/curl_memory.h | 19 +- Utilities/cmcurl/lib/curl_memrchr.c | 7 +- Utilities/cmcurl/lib/curl_memrchr.h | 2 +- Utilities/cmcurl/lib/curl_multibyte.c | 4 +- Utilities/cmcurl/lib/curl_multibyte.h | 2 +- Utilities/cmcurl/lib/curl_ntlm_core.c | 34 +- Utilities/cmcurl/lib/curl_ntlm_core.h | 6 +- Utilities/cmcurl/lib/curl_ntlm_wb.c | 15 +- Utilities/cmcurl/lib/curl_ntlm_wb.h | 2 +- Utilities/cmcurl/lib/curl_printf.h | 2 +- Utilities/cmcurl/lib/curl_rtmp.c | 4 +- Utilities/cmcurl/lib/curl_rtmp.h | 2 +- Utilities/cmcurl/lib/curl_sasl.c | 1332 ++---------------- Utilities/cmcurl/lib/curl_sasl.h | 143 +- Utilities/cmcurl/lib/curl_sasl_sspi.c | 1281 ----------------- Utilities/cmcurl/lib/curl_sec.h | 2 +- Utilities/cmcurl/lib/curl_setup.h | 49 +- Utilities/cmcurl/lib/curl_setup_once.h | 2 +- Utilities/cmcurl/lib/curl_sspi.c | 52 +- Utilities/cmcurl/lib/curl_sspi.h | 6 +- Utilities/cmcurl/lib/curl_threads.c | 6 +- Utilities/cmcurl/lib/curl_threads.h | 2 +- Utilities/cmcurl/lib/curlx.h | 2 +- Utilities/cmcurl/lib/dict.c | 6 +- Utilities/cmcurl/lib/dict.h | 2 +- Utilities/cmcurl/lib/dotdot.c | 17 +- Utilities/cmcurl/lib/dotdot.h | 2 +- Utilities/cmcurl/lib/easy.c | 181 +-- Utilities/cmcurl/lib/easyif.h | 6 +- Utilities/cmcurl/lib/escape.c | 24 +- Utilities/cmcurl/lib/escape.h | 4 +- Utilities/cmcurl/lib/file.c | 93 +- Utilities/cmcurl/lib/file.h | 2 +- Utilities/cmcurl/lib/fileinfo.c | 2 +- Utilities/cmcurl/lib/fileinfo.h | 2 +- Utilities/cmcurl/lib/formdata.c | 121 +- Utilities/cmcurl/lib/formdata.h | 12 +- Utilities/cmcurl/lib/ftp.c | 181 +-- Utilities/cmcurl/lib/ftp.h | 6 +- Utilities/cmcurl/lib/ftplistparser.c | 36 +- Utilities/cmcurl/lib/ftplistparser.h | 2 +- Utilities/cmcurl/lib/getenv.c | 2 +- Utilities/cmcurl/lib/getinfo.c | 128 +- Utilities/cmcurl/lib/getinfo.h | 6 +- Utilities/cmcurl/lib/gopher.c | 12 +- Utilities/cmcurl/lib/gopher.h | 2 +- Utilities/cmcurl/lib/hash.c | 30 +- Utilities/cmcurl/lib/hash.h | 2 +- Utilities/cmcurl/lib/hmac.c | 7 +- Utilities/cmcurl/lib/hostasyn.c | 4 +- Utilities/cmcurl/lib/hostcheck.c | 4 +- Utilities/cmcurl/lib/hostcheck.h | 2 +- Utilities/cmcurl/lib/hostip.c | 29 +- Utilities/cmcurl/lib/hostip.h | 24 +- Utilities/cmcurl/lib/hostip4.c | 6 +- Utilities/cmcurl/lib/hostip6.c | 31 +- Utilities/cmcurl/lib/hostsyn.c | 10 +- Utilities/cmcurl/lib/http.c | 361 ++--- Utilities/cmcurl/lib/http.h | 12 +- Utilities/cmcurl/lib/http2.c | 800 ++++++++--- Utilities/cmcurl/lib/http2.h | 10 +- Utilities/cmcurl/lib/http_chunks.c | 8 +- Utilities/cmcurl/lib/http_chunks.h | 2 +- Utilities/cmcurl/lib/http_digest.c | 25 +- Utilities/cmcurl/lib/http_digest.h | 4 +- Utilities/cmcurl/lib/http_negotiate.c | 193 +-- Utilities/cmcurl/lib/http_negotiate.h | 8 +- Utilities/cmcurl/lib/http_negotiate_sspi.c | 300 ---- Utilities/cmcurl/lib/{curl_ntlm.c => http_ntlm.c} | 27 +- Utilities/cmcurl/lib/{curl_ntlm.h => http_ntlm.h} | 2 +- Utilities/cmcurl/lib/http_proxy.c | 45 +- Utilities/cmcurl/lib/http_proxy.h | 2 +- Utilities/cmcurl/lib/idn_win32.c | 63 +- Utilities/cmcurl/lib/if2ip.c | 19 +- Utilities/cmcurl/lib/if2ip.h | 2 +- Utilities/cmcurl/lib/imap.c | 148 +- Utilities/cmcurl/lib/imap.h | 6 +- Utilities/cmcurl/lib/inet_ntop.c | 11 +- Utilities/cmcurl/lib/inet_ntop.h | 2 +- Utilities/cmcurl/lib/inet_pton.c | 8 +- Utilities/cmcurl/lib/inet_pton.h | 2 +- Utilities/cmcurl/lib/krb5.c | 28 +- Utilities/cmcurl/lib/ldap.c | 13 +- Utilities/cmcurl/lib/libcurl.rc | 6 +- Utilities/cmcurl/lib/llist.c | 6 +- Utilities/cmcurl/lib/llist.h | 2 +- Utilities/cmcurl/lib/md5.c | 6 +- Utilities/cmcurl/lib/memdebug.c | 15 +- Utilities/cmcurl/lib/memdebug.h | 17 +- Utilities/cmcurl/lib/mprintf.c | 184 +-- Utilities/cmcurl/lib/multi.c | 709 +++++++--- Utilities/cmcurl/lib/multihandle.h | 10 +- Utilities/cmcurl/lib/multiif.h | 14 +- Utilities/cmcurl/lib/netrc.c | 8 +- Utilities/cmcurl/lib/netrc.h | 2 +- Utilities/cmcurl/lib/non-ascii.c | 24 +- Utilities/cmcurl/lib/non-ascii.h | 18 +- Utilities/cmcurl/lib/nonblock.c | 6 +- Utilities/cmcurl/lib/nonblock.h | 2 +- Utilities/cmcurl/lib/nwlib.c | 50 +- Utilities/cmcurl/lib/nwos.c | 12 +- Utilities/cmcurl/lib/openldap.c | 109 +- Utilities/cmcurl/lib/parsedate.c | 2 +- Utilities/cmcurl/lib/parsedate.h | 2 +- Utilities/cmcurl/lib/pingpong.c | 18 +- Utilities/cmcurl/lib/pingpong.h | 2 +- Utilities/cmcurl/lib/pipeline.c | 46 +- Utilities/cmcurl/lib/pipeline.h | 20 +- Utilities/cmcurl/lib/pop3.c | 74 +- Utilities/cmcurl/lib/pop3.h | 6 +- Utilities/cmcurl/lib/progress.c | 20 +- Utilities/cmcurl/lib/progress.h | 16 +- Utilities/cmcurl/lib/rawstr.c | 12 +- Utilities/cmcurl/lib/rawstr.h | 2 +- Utilities/cmcurl/lib/rtsp.c | 48 +- Utilities/cmcurl/lib/rtsp.h | 2 +- Utilities/cmcurl/lib/security.c | 2 +- Utilities/cmcurl/lib/select.c | 22 +- Utilities/cmcurl/lib/select.h | 2 +- Utilities/cmcurl/lib/sendf.c | 154 ++- Utilities/cmcurl/lib/sendf.h | 8 +- Utilities/cmcurl/lib/setup-os400.h | 2 +- Utilities/cmcurl/lib/setup-vms.h | 2 +- Utilities/cmcurl/lib/share.c | 23 +- Utilities/cmcurl/lib/share.h | 6 +- Utilities/cmcurl/lib/sigpipe.h | 6 +- Utilities/cmcurl/lib/slist.c | 6 +- Utilities/cmcurl/lib/slist.h | 2 +- Utilities/cmcurl/lib/smb.c | 13 +- Utilities/cmcurl/lib/smb.h | 2 +- Utilities/cmcurl/lib/smtp.c | 85 +- Utilities/cmcurl/lib/smtp.h | 6 +- Utilities/cmcurl/lib/sockaddr.h | 2 +- Utilities/cmcurl/lib/socks.c | 44 +- Utilities/cmcurl/lib/socks.h | 2 +- Utilities/cmcurl/lib/socks_gssapi.c | 14 +- Utilities/cmcurl/lib/socks_sspi.c | 17 +- Utilities/cmcurl/lib/speedcheck.c | 6 +- Utilities/cmcurl/lib/speedcheck.h | 6 +- Utilities/cmcurl/lib/splay.c | 2 +- Utilities/cmcurl/lib/splay.h | 6 +- Utilities/cmcurl/lib/ssh.c | 173 ++- Utilities/cmcurl/lib/ssh.h | 7 +- Utilities/cmcurl/lib/strdup.c | 8 +- Utilities/cmcurl/lib/strdup.h | 2 +- Utilities/cmcurl/lib/strequal.c | 2 +- Utilities/cmcurl/lib/strequal.h | 2 +- Utilities/cmcurl/lib/strerror.c | 20 +- Utilities/cmcurl/lib/strerror.h | 2 +- Utilities/cmcurl/lib/strtok.c | 2 +- Utilities/cmcurl/lib/strtok.h | 2 +- Utilities/cmcurl/lib/strtoofft.c | 2 +- Utilities/cmcurl/lib/strtoofft.h | 2 +- Utilities/cmcurl/lib/system_win32.c | 294 ++++ Utilities/cmcurl/lib/system_win32.h | 61 + Utilities/cmcurl/lib/telnet.c | 46 +- Utilities/cmcurl/lib/telnet.h | 2 +- Utilities/cmcurl/lib/tftp.c | 99 +- Utilities/cmcurl/lib/tftp.h | 2 +- Utilities/cmcurl/lib/timeval.c | 14 +- Utilities/cmcurl/lib/timeval.h | 2 +- Utilities/cmcurl/lib/transfer.c | 219 ++- Utilities/cmcurl/lib/transfer.h | 17 +- Utilities/cmcurl/lib/url.c | 1449 ++++++++++++-------- Utilities/cmcurl/lib/url.h | 40 +- Utilities/cmcurl/lib/urldata.h | 187 ++- Utilities/cmcurl/lib/vauth/cleartext.c | 157 +++ Utilities/cmcurl/lib/vauth/cram.c | 138 ++ Utilities/cmcurl/lib/vauth/digest.c | 883 ++++++++++++ .../cmcurl/lib/{hostcheck.h => vauth/digest.h} | 27 +- Utilities/cmcurl/lib/vauth/digest_sspi.c | 533 +++++++ .../{curl_sasl_gssapi.c => vauth/krb5_gssapi.c} | 175 ++- Utilities/cmcurl/lib/vauth/krb5_sspi.c | 496 +++++++ .../cmcurl/lib/{curl_ntlm_msgs.c => vauth/ntlm.c} | 65 +- .../cmcurl/lib/{curl_ntlm_msgs.h => vauth/ntlm.h} | 10 +- Utilities/cmcurl/lib/vauth/ntlm_sspi.c | 314 +++++ Utilities/cmcurl/lib/vauth/oauth2.c | 86 ++ Utilities/cmcurl/lib/vauth/spnego_gssapi.c | 260 ++++ Utilities/cmcurl/lib/vauth/spnego_sspi.c | 297 ++++ Utilities/cmcurl/lib/vauth/vauth.c | 106 ++ Utilities/cmcurl/lib/vauth/vauth.h | 189 +++ Utilities/cmcurl/lib/version.c | 40 +- Utilities/cmcurl/lib/vtls/axtls.c | 58 +- Utilities/cmcurl/lib/vtls/axtls.h | 4 +- Utilities/cmcurl/lib/vtls/cyassl.c | 203 ++- Utilities/cmcurl/lib/vtls/cyassl.h | 23 +- Utilities/cmcurl/lib/vtls/darwinssl.c | 111 +- Utilities/cmcurl/lib/vtls/darwinssl.h | 2 +- Utilities/cmcurl/lib/vtls/gskit.c | 36 +- Utilities/cmcurl/lib/vtls/gskit.h | 2 +- Utilities/cmcurl/lib/vtls/gtls.c | 116 +- Utilities/cmcurl/lib/vtls/gtls.h | 9 +- Utilities/cmcurl/lib/vtls/mbedtls.c | 871 ++++++++++++ Utilities/cmcurl/lib/vtls/mbedtls.h | 80 ++ Utilities/cmcurl/lib/vtls/nss.c | 113 +- Utilities/cmcurl/lib/vtls/nssg.h | 13 +- Utilities/cmcurl/lib/vtls/openssl.c | 998 +++++++------- Utilities/cmcurl/lib/vtls/openssl.h | 21 +- Utilities/cmcurl/lib/vtls/polarssl.c | 191 ++- Utilities/cmcurl/lib/vtls/polarssl.h | 18 +- Utilities/cmcurl/lib/vtls/polarssl_threadlock.c | 16 +- Utilities/cmcurl/lib/vtls/polarssl_threadlock.h | 22 +- Utilities/cmcurl/lib/vtls/schannel.c | 297 ++-- Utilities/cmcurl/lib/vtls/schannel.h | 5 +- Utilities/cmcurl/lib/vtls/vtls.c | 168 ++- Utilities/cmcurl/lib/vtls/vtls.h | 73 +- Utilities/cmcurl/lib/warnless.c | 61 +- Utilities/cmcurl/lib/warnless.h | 10 +- Utilities/cmcurl/lib/wildcard.c | 6 +- Utilities/cmcurl/lib/wildcard.h | 4 +- Utilities/cmcurl/lib/x509asn1.c | 31 +- Utilities/cmcurl/lib/x509asn1.h | 6 +- 267 files changed, 11926 insertions(+), 7502 deletions(-) create mode 100755 Utilities/Scripts/update-curl.bash delete mode 100644 Utilities/cmcurl/README-CMake.txt delete mode 100644 Utilities/cmcurl/lib/curl_sasl_sspi.c delete mode 100644 Utilities/cmcurl/lib/http_negotiate_sspi.c rename Utilities/cmcurl/lib/{curl_ntlm.c => http_ntlm.c} (91%) rename Utilities/cmcurl/lib/{curl_ntlm.h => http_ntlm.h} (95%) create mode 100644 Utilities/cmcurl/lib/system_win32.c create mode 100644 Utilities/cmcurl/lib/system_win32.h create mode 100644 Utilities/cmcurl/lib/vauth/cleartext.c create mode 100644 Utilities/cmcurl/lib/vauth/cram.c create mode 100644 Utilities/cmcurl/lib/vauth/digest.c copy Utilities/cmcurl/lib/{hostcheck.h => vauth/digest.h} (59%) create mode 100644 Utilities/cmcurl/lib/vauth/digest_sspi.c rename Utilities/cmcurl/lib/{curl_sasl_gssapi.c => vauth/krb5_gssapi.c} (66%) create mode 100644 Utilities/cmcurl/lib/vauth/krb5_sspi.c rename Utilities/cmcurl/lib/{curl_ntlm_msgs.c => vauth/ntlm.c} (94%) rename Utilities/cmcurl/lib/{curl_ntlm_msgs.h => vauth/ntlm.h} (95%) create mode 100644 Utilities/cmcurl/lib/vauth/ntlm_sspi.c create mode 100644 Utilities/cmcurl/lib/vauth/oauth2.c create mode 100644 Utilities/cmcurl/lib/vauth/spnego_gssapi.c create mode 100644 Utilities/cmcurl/lib/vauth/spnego_sspi.c create mode 100644 Utilities/cmcurl/lib/vauth/vauth.c create mode 100644 Utilities/cmcurl/lib/vauth/vauth.h create mode 100644 Utilities/cmcurl/lib/vtls/mbedtls.c create mode 100644 Utilities/cmcurl/lib/vtls/mbedtls.h hooks/post-receive -- CMake From chuck.atkins at kitware.com Mon Aug 8 10:48:01 2016 From: chuck.atkins at kitware.com (Chuck Atkins) Date: Mon, 8 Aug 2016 10:48:01 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1155-g717ece1 Message-ID: <20160808144801.E17EFF3BDD@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 717ece197f2931fe9d633b0fe1074aa3416eed0c (commit) via 8872cd142ba7ad8e3eb36f06e92bda35475a9e90 (commit) from 4a5e3beb82eca0e2a1358c3eddfe41939ebdcdb8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=717ece197f2931fe9d633b0fe1074aa3416eed0c commit 717ece197f2931fe9d633b0fe1074aa3416eed0c Merge: 4a5e3be 8872cd1 Author: Chuck Atkins AuthorDate: Mon Aug 8 10:48:00 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 8 10:48:00 2016 -0400 Merge topic 'add-extra-boolean-comparisons' into next 8872cd14 Add additional <= and >= comparison operators https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8872cd142ba7ad8e3eb36f06e92bda35475a9e90 commit 8872cd142ba7ad8e3eb36f06e92bda35475a9e90 Author: Chuck Atkins AuthorDate: Fri Aug 5 14:11:46 2016 -0400 Commit: Chuck Atkins CommitDate: Fri Aug 5 16:05:20 2016 -0400 Add additional <= and >= comparison operators This adds the LESS_EQUAL, GREATER_EQUAL, and associated STR and VERSION_ equivalents to use the combined <= and >= functionality. diff --git a/Help/command/if.rst b/Help/command/if.rst index 56e618c..0941029 100644 --- a/Help/command/if.rst +++ b/Help/command/if.rst @@ -30,10 +30,12 @@ else and endif clause is optional. Long expressions can be used and there is a traditional order of precedence. Parenthetical expressions are evaluated first followed by unary tests such as ``EXISTS``, ``COMMAND``, and ``DEFINED``. Then any binary tests such as -``EQUAL``, ``LESS``, ``GREATER``, ``STRLESS``, ``STRGREATER``, -``STREQUAL``, and ``MATCHES`` will be evaluated. Then boolean ``NOT`` -operators and finally boolean ``AND`` and then ``OR`` operators will -be evaluated. +``EQUAL``, ``LESS``, ``LESS_EQUAL, ``GREATER``, ``GREATER_EQUAL``, +``STREQUAL``, ``STRLESS``, ``STRLESS_EQUAL``, ``STRGREATER``, +``STRGREATER_EQUAL``, ``VERSION_EQUAL``, ``VERSION_LESS``, +``VERSION_LESS_EQUAL``, ``VERSION_GREATER``, ``VERSION_GREATER_EQUAL``, +and ``MATCHES`` will be evaluated. Then boolean ``NOT`` operators and +finally boolean ``AND`` and then ``OR`` operators will be evaluated. Possible expressions are: @@ -115,6 +117,14 @@ Possible expressions are: True if the given string or variable's value is a valid number and equal to that on the right. +``if( LESS_EQUAL )`` + True if the given string or variable's value is a valid number and less + than or equal to that on the right. + +``if( GREATER_EQUAL )`` + True if the given string or variable's value is a valid number and greater + than or equal to that on the right. + ``if( STRLESS )`` True if the given string or variable's value is lexicographically less than the string or variable on the right. @@ -127,15 +137,31 @@ Possible expressions are: True if the given string or variable's value is lexicographically equal to the string or variable on the right. +``if( STRLESS_EQUAL )`` + True if the given string or variable's value is lexicographically less + than or equal to the string or variable on the right. + +``if( STRGREATER_EQUAL )`` + True if the given string or variable's value is lexicographically greater + than or equal to the string or variable on the right. + ``if( VERSION_LESS )`` Component-wise integer version number comparison (version format is ``major[.minor[.patch[.tweak]]]``). +``if( VERSION_GREATER )`` + Component-wise integer version number comparison (version format is + ``major[.minor[.patch[.tweak]]]``). + ``if( VERSION_EQUAL )`` Component-wise integer version number comparison (version format is ``major[.minor[.patch[.tweak]]]``). -``if( VERSION_GREATER )`` +``if( VERSION_LESS_EQUAL )`` + Component-wise integer version number comparison (version format is + ``major[.minor[.patch[.tweak]]]``). + +``if( VERSION_GREATER_EQUAL )`` Component-wise integer version number comparison (version format is ``major[.minor[.patch[.tweak]]]``). @@ -186,20 +212,21 @@ above-documented signature accepts ````: * If the left hand argument to ``MATCHES`` is missing it returns false without error -* Both left and right hand arguments to ``LESS``, ``GREATER``, and - ``EQUAL`` are independently tested to see if they are defined - variables, if so their defined values are used otherwise the original - value is used. +* Both left and right hand arguments to ``LESS``, ``GREATER``, ``EQUAL``, + ``LESS_EQUAL``, and ``GREATER_EQUAL``, are independently tested to see if + they are defined variables, if so their defined values are used otherwise + the original value is used. -* Both left and right hand arguments to ``STRLESS``, ``STREQUAL``, and - ``STRGREATER`` are independently tested to see if they are defined - variables, if so their defined values are used otherwise the original - value is used. +* Both left and right hand arguments to ``STRLESS``, ``STRGREATER``, + ``STREQUAL``, ``STRLESS_EQUAL``, and ``STRGREATER_EQUAL`` are independently + tested to see if they are defined variables, if so their defined values are + used otherwise the original value is used. * Both left and right hand arguments to ``VERSION_LESS``, - ``VERSION_EQUAL``, and ``VERSION_GREATER`` are independently tested - to see if they are defined variables, if so their defined values are - used otherwise the original value is used. + ``VERSION_GREATER``, ``VERSION_EQUAL``, ``VERSION_LESS_EQUAL``, and + ``VERSION_GREATER_EQUAL`` are independently tested to see if they are defined + variables, if so their defined values are used otherwise the original value + is used. * The right hand argument to ``NOT`` is tested to see if it is a boolean constant, if so the value is used, otherwise it is assumed to be a diff --git a/Help/command/string.rst b/Help/command/string.rst index 3f4050e..19a095a 100644 --- a/Help/command/string.rst +++ b/Help/command/string.rst @@ -197,10 +197,12 @@ Comparison :: - string(COMPARE EQUAL ) - string(COMPARE NOTEQUAL ) string(COMPARE LESS ) string(COMPARE GREATER ) + string(COMPARE EQUAL ) + string(COMPARE NOTEQUAL ) + string(COMPARE LESS_EQUAL ) + string(COMPARE GREATER_EQUAL ) Compare the strings and store true or false in the output variable. diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index d4f47dd..64d15a9 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -66,12 +66,16 @@ Available logical expressions are: ``1`` if the CMake-id of the C compiler matches ``comp``, otherwise ``0``. ``$`` ``1`` if the CMake-id of the CXX compiler matches ``comp``, otherwise ``0``. -``$`` - ``1`` if ``v1`` is a version greater than ``v2``, else ``0``. ``$`` ``1`` if ``v1`` is a version less than ``v2``, else ``0``. +``$`` + ``1`` if ``v1`` is a version greater than ``v2``, else ``0``. ``$`` ``1`` if ``v1`` is the same version as ``v2``, else ``0``. +``$`` + ``1`` if ``v1`` is a version less than or equal to ``v2``, else ``0``. +``$`` + ``1`` if ``v1`` is a version greater than or equal to ``v2``, else ``0``. ``$`` ``1`` if the version of the C compiler matches ``ver``, otherwise ``0``. ``$`` diff --git a/Help/release/dev/add-extra-boolean-comparisons.rst b/Help/release/dev/add-extra-boolean-comparisons.rst new file mode 100644 index 0000000..d47f0af --- /dev/null +++ b/Help/release/dev/add-extra-boolean-comparisons.rst @@ -0,0 +1,5 @@ +add-extra-boolean-comparisons +-------------- + +* Add LESS_EQUAL, GREATER_EQUAL, and thier associated STR and VERSION_ + equivalents to use the combined <= and >= functionality. diff --git a/Help/variable/CMAKE_VERSION.rst b/Help/variable/CMAKE_VERSION.rst index bbb1d91..872e2fa 100644 --- a/Help/variable/CMAKE_VERSION.rst +++ b/Help/variable/CMAKE_VERSION.rst @@ -26,11 +26,11 @@ Individual component values are also available in variables: * :variable:`CMAKE_PATCH_VERSION` * :variable:`CMAKE_TWEAK_VERSION` -Use the :command:`if` command ``VERSION_LESS``, ``VERSION_EQUAL``, or -``VERSION_GREATER`` operators to compare version string values against -``CMAKE_VERSION`` using a component-wise test. Version component -values may be 10 or larger so do not attempt to compare version -strings as floating-point numbers. +Use the :command:`if` command ``VERSION_LESS``, ``VERSION_GREATER``, +``VERSION_EQUAL``, ``VERSION_LESS_EQUAL``, or ``VERSION_GREATER_EQUAL`` +operators to compare version string values against ``CMAKE_VERSION`` using a +component-wise test. Version component values may be 10 or larger so do not +attempt to compare version strings as floating-point numbers. .. note:: diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 0101049..141a00e 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -367,10 +367,8 @@ bool cmCTest::ShouldCompressTestOutput() std::string cdashVersion = this->GetCDashVersion(); // version >= 1.6? bool cdashSupportsGzip = - cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, - cdashVersion.c_str(), "1.6") || - cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, - cdashVersion.c_str(), "1.6"); + cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, + cdashVersion.c_str(), "1.6"); this->CompressTestOutput &= cdashSupportsGzip; this->ComputedCompressTestOutput = true; } diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index e02221c..d7532b3 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -21,12 +21,14 @@ static std::string const keyDEFINED = "DEFINED"; static std::string const keyEQUAL = "EQUAL"; static std::string const keyEXISTS = "EXISTS"; static std::string const keyGREATER = "GREATER"; +static std::string const keyGREATER_EQUAL = "GREATER_EQUAL"; static std::string const keyIN_LIST = "IN_LIST"; static std::string const keyIS_ABSOLUTE = "IS_ABSOLUTE"; static std::string const keyIS_DIRECTORY = "IS_DIRECTORY"; static std::string const keyIS_NEWER_THAN = "IS_NEWER_THAN"; static std::string const keyIS_SYMLINK = "IS_SYMLINK"; static std::string const keyLESS = "LESS"; +static std::string const keyLESS_EQUAL = "LESS_EQUAL"; static std::string const keyMATCHES = "MATCHES"; static std::string const keyNOT = "NOT"; static std::string const keyOR = "OR"; @@ -35,12 +37,16 @@ static std::string const keyParenR = ")"; static std::string const keyPOLICY = "POLICY"; static std::string const keySTREQUAL = "STREQUAL"; static std::string const keySTRGREATER = "STRGREATER"; +static std::string const keySTRGREATER_EQUAL = "STRGREATER_EQUAL"; static std::string const keySTRLESS = "STRLESS"; +static std::string const keySTRLESS_EQUAL = "STRLESS_EQUAL"; static std::string const keyTARGET = "TARGET"; static std::string const keyTEST = "TEST"; static std::string const keyVERSION_EQUAL = "VERSION_EQUAL"; static std::string const keyVERSION_GREATER = "VERSION_GREATER"; +static std::string const keyVERSION_GREATER_EQUAL = "VERSION_GREATER_EQUAL"; static std::string const keyVERSION_LESS = "VERSION_LESS"; +static std::string const keyVERSION_LESS_EQUAL = "VERSION_LESS_EQUAL"; cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile, const cmListFileContext& context, @@ -559,7 +565,9 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, if (argP1 != newArgs.end() && argP2 != newArgs.end() && (this->IsKeyword(keyLESS, *argP1) || + this->IsKeyword(keyLESS_EQUAL, *argP1) || this->IsKeyword(keyGREATER, *argP1) || + this->IsKeyword(keyGREATER_EQUAL, *argP1) || this->IsKeyword(keyEQUAL, *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); @@ -570,8 +578,12 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, result = false; } else if (*(argP1) == keyLESS) { result = (lhs < rhs); + } else if (*(argP1) == keyLESS_EQUAL) { + result = (lhs <= rhs); } else if (*(argP1) == keyGREATER) { result = (lhs > rhs); + } else if (*(argP1) == keyGREATER_EQUAL) { + result = (lhs >= rhs); } else { result = (lhs == rhs); } @@ -580,16 +592,22 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, if (argP1 != newArgs.end() && argP2 != newArgs.end() && (this->IsKeyword(keySTRLESS, *argP1) || - this->IsKeyword(keySTREQUAL, *argP1) || - this->IsKeyword(keySTRGREATER, *argP1))) { + this->IsKeyword(keySTRLESS_EQUAL, *argP1) || + this->IsKeyword(keySTRGREATER, *argP1) || + this->IsKeyword(keySTRGREATER_EQUAL, *argP1) || + this->IsKeyword(keySTREQUAL, *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); int val = strcmp(def, def2); bool result; if (*(argP1) == keySTRLESS) { result = (val < 0); + } else if (*(argP1) == keySTRLESS_EQUAL) { + result = (val <= 0); } else if (*(argP1) == keySTRGREATER) { result = (val > 0); + } else if (*(argP1) == keySTRGREATER_EQUAL) { + result = (val >= 0); } else // strequal { result = (val == 0); @@ -599,15 +617,23 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, if (argP1 != newArgs.end() && argP2 != newArgs.end() && (this->IsKeyword(keyVERSION_LESS, *argP1) || + this->IsKeyword(keyVERSION_LESS_EQUAL, *argP1) || this->IsKeyword(keyVERSION_GREATER, *argP1) || + this->IsKeyword(keyVERSION_GREATER_EQUAL, *argP1) || this->IsKeyword(keyVERSION_EQUAL, *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); - cmSystemTools::CompareOp op = cmSystemTools::OP_EQUAL; + cmSystemTools::CompareOp op; if (*argP1 == keyVERSION_LESS) { op = cmSystemTools::OP_LESS; + } else if (*argP1 == keyVERSION_LESS_EQUAL) { + op = cmSystemTools::OP_LESS_EQUAL; } else if (*argP1 == keyVERSION_GREATER) { op = cmSystemTools::OP_GREATER; + } else if (*argP1 == keyVERSION_GREATER_EQUAL) { + op = cmSystemTools::OP_GREATER_EQUAL; + } else { // version_equal + op = cmSystemTools::OP_EQUAL; } bool result = cmSystemTools::VersionCompare(op, def, def2); this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2); diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index ca7250b..6e2b16a 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -545,6 +545,25 @@ static const struct VersionGreaterNode : public cmGeneratorExpressionNode } } versionGreaterNode; +static const struct VersionGreaterEqNode : public cmGeneratorExpressionNode +{ + VersionGreaterEqNode() {} + + int NumExpectedParameters() const CM_OVERRIDE { return 2; } + + std::string Evaluate(const std::vector& parameters, + cmGeneratorExpressionContext*, + const GeneratorExpressionContent*, + cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + { + return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, + parameters.front().c_str(), + parameters[1].c_str()) + ? "1" + : "0"; + } +} versionGreaterEqNode; + static const struct VersionLessNode : public cmGeneratorExpressionNode { VersionLessNode() {} @@ -564,6 +583,25 @@ static const struct VersionLessNode : public cmGeneratorExpressionNode } } versionLessNode; +static const struct VersionLessEqNode : public cmGeneratorExpressionNode +{ + VersionLessEqNode() {} + + int NumExpectedParameters() const CM_OVERRIDE { return 2; } + + std::string Evaluate(const std::vector& parameters, + cmGeneratorExpressionContext*, + const GeneratorExpressionContent*, + cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + { + return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS_EQUAL, + parameters.front().c_str(), + parameters[1].c_str()) + ? "1" + : "0"; + } +} versionLessEqNode; + static const struct VersionEqualNode : public cmGeneratorExpressionNode { VersionEqualNode() {} @@ -1641,7 +1679,9 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( nodeMap["C_COMPILER_ID"] = &cCompilerIdNode; nodeMap["CXX_COMPILER_ID"] = &cxxCompilerIdNode; nodeMap["VERSION_GREATER"] = &versionGreaterNode; + nodeMap["VERSION_GREATER_EQUAL"] = &versionGreaterEqNode; nodeMap["VERSION_LESS"] = &versionLessNode; + nodeMap["VERSION_LESS_EQUAL"] = &versionLessEqNode; nodeMap["VERSION_EQUAL"] = &versionEqualNode; nodeMap["C_COMPILER_VERSION"] = &cCompilerVersionNode; nodeMap["CXX_COMPILER_VERSION"] = &cxxCompilerVersionNode; diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index dce4687..705fc7d 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -484,8 +484,9 @@ bool cmStringCommand::HandleCompareCommand( return false; } std::string mode = args[1]; - if ((mode == "EQUAL") || (mode == "NOTEQUAL") || (mode == "LESS") || - (mode == "GREATER")) { + if ((mode == "EQUAL") || (mode == "NOTEQUAL") || + (mode == "LESS") || (mode == "LESS_EQUAL") || + (mode == "GREATER") || (mode == "GREATER_EQUAL")) { if (args.size() < 5) { std::string e = "sub-command COMPARE, mode "; e += mode; @@ -500,8 +501,12 @@ bool cmStringCommand::HandleCompareCommand( bool result; if (mode == "LESS") { result = (left < right); + } else if (mode == "LESS_EQUAL") { + result = (left <= right); } else if (mode == "GREATER") { result = (left > right); + } else if (mode == "GREATER_EQUAL") { + result = (left >= right); } else if (mode == "EQUAL") { result = (left == right); } else // if(mode == "NOTEQUAL") diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 9740ef7..5745a01 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -2380,10 +2380,10 @@ bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op, if (lhs < rhs) { // lhs < rhs, so true if operation is LESS - return op == cmSystemTools::OP_LESS; + return (op & cmSystemTools::OP_LESS) != 0; } else if (lhs > rhs) { // lhs > rhs, so true if operation is GREATER - return op == cmSystemTools::OP_GREATER; + return (op & cmSystemTools::OP_GREATER) != 0; } if (*endr == '.') { @@ -2395,7 +2395,7 @@ bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op, } } // lhs == rhs, so true if operation is EQUAL - return op == cmSystemTools::OP_EQUAL; + return (op & cmSystemTools::OP_EQUAL) != 0; } bool cmSystemTools::VersionCompareEqual(std::string const& lhs, @@ -2412,6 +2412,13 @@ bool cmSystemTools::VersionCompareGreater(std::string const& lhs, rhs.c_str()); } +bool cmSystemTools::VersionCompareGreaterEq(std::string const& lhs, + std::string const& rhs) +{ + return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, + lhs.c_str(), rhs.c_str()); +} + bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, bool* removed) { diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 39e7994..f031273 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -284,9 +284,11 @@ public: enum CompareOp { - OP_LESS, - OP_GREATER, - OP_EQUAL + OP_EQUAL = 1, + OP_LESS = 2, + OP_GREATER = 4, + OP_LESS_EQUAL = OP_LESS | OP_EQUAL, + OP_GREATER_EQUAL = OP_GREATER | OP_EQUAL }; /** @@ -297,6 +299,8 @@ public: std::string const& rhs); static bool VersionCompareGreater(std::string const& lhs, std::string const& rhs); + static bool VersionCompareGreaterEq(std::string const& lhs, + std::string const& rhs); /** * Determine the file type based on the extension diff --git a/Tests/CMakeTests/VersionTest.cmake.in b/Tests/CMakeTests/VersionTest.cmake.in index 4e946ab..f045605 100644 --- a/Tests/CMakeTests/VersionTest.cmake.in +++ b/Tests/CMakeTests/VersionTest.cmake.in @@ -83,10 +83,24 @@ foreach(v IN LISTS LESSV) message(FATAL_ERROR "${CMAKE_MATCH_2} is less than ${CMAKE_MATCH_1}?") endif() + # check greater or equal (same as less negative) + if(CMAKE_MATCH_2 VERSION_GREATER_EQUAL CMAKE_MATCH_1) + message(STATUS "${CMAKE_MATCH_2} is not less than ${CMAKE_MATCH_1}") + else() + message(FATAL_ERROR "${CMAKE_MATCH_2} is less than ${CMAKE_MATCH_1}?") + endif() + # check greater negative case if(NOT CMAKE_MATCH_1 VERSION_GREATER CMAKE_MATCH_2) message(STATUS "${CMAKE_MATCH_1} is not greater than ${CMAKE_MATCH_2}") else() message(FATAL_ERROR "${CMAKE_MATCH_1} is greater than ${CMAKE_MATCH_2}?") endif() + + # check less or equal (same as greater negative) case + if(CMAKE_MATCH_1 VERSION_LESS_EQUAL CMAKE_MATCH_2) + message(STATUS "${CMAKE_MATCH_1} is not greater than ${CMAKE_MATCH_2}") + else() + message(FATAL_ERROR "${CMAKE_MATCH_1} is greater than ${CMAKE_MATCH_2}?") + endif() endforeach() diff --git a/Tests/CTestTestStopTime/GetDate.cmake b/Tests/CTestTestStopTime/GetDate.cmake index edc6519..1f4cb24 100644 --- a/Tests/CTestTestStopTime/GetDate.cmake +++ b/Tests/CTestTestStopTime/GetDate.cmake @@ -106,11 +106,11 @@ macro(ADD_SECONDS sec) set(new_min ${${GD_PREFIX}MINUTE}) set(new_hr ${${GD_PREFIX}HOUR}) math(EXPR new_sec "${sec} + ${${GD_PREFIX}SECOND}") - while(${new_sec} GREATER 60 OR ${new_sec} EQUAL 60) + while(${new_sec} GREATER_EQUAL 60) math(EXPR new_sec "${new_sec} - 60") math(EXPR new_min "${${GD_PREFIX}MINUTE} + 1") endwhile() - while(${new_min} GREATER 60 OR ${new_min} EQUAL 60) + while(${new_min} GREATER_EQUAL 60) math(EXPR new_min "${new_min} - 60") math(EXPR new_hr "${${GD_PREFIX}HOUR} + 1") endwhile() diff --git a/Tests/Complex/CMakeLists.txt b/Tests/Complex/CMakeLists.txt index 80cc2e3..075faa7 100644 --- a/Tests/Complex/CMakeLists.txt +++ b/Tests/Complex/CMakeLists.txt @@ -92,6 +92,12 @@ endif() if(NOT 2.4 EQUAL 2.4) message(FATAL_ERROR "Failed: NOT 2.4 EQUAL 2.4") endif() +if(NOT 2.4 LESS_EQUAL 2.4) + message(FATAL_ERROR "Failed: NOT 2.4 LESS_EQUAL 2.4") +endif() +if(NOT 2.4 GREATER_EQUAL 2.4) + message(FATAL_ERROR "Failed: NOT 2.4 GREATER_EQUAL 2.4") +endif() if(CMAKE_SYSTEM MATCHES "OSF1-V") if(NOT CMAKE_COMPILER_IS_GNUCXX) diff --git a/Tests/Complex/Executable/complex.cxx b/Tests/Complex/Executable/complex.cxx index 5f79ac0..f335d67 100644 --- a/Tests/Complex/Executable/complex.cxx +++ b/Tests/Complex/Executable/complex.cxx @@ -455,7 +455,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_LESS - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS is not defined."); #else cmPassed("SHOULD_BE_DEFINED_LESS is defined."); #endif @@ -467,7 +467,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_LESS2 - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS2 is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_LESS2 is defined."); #endif @@ -478,6 +478,24 @@ int main() cmPassed("SHOULD_NOT_BE_DEFINED_GREATER is not defined."); #endif +#ifndef SHOULD_BE_DEFINED_GREATER + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); +#endif + #ifdef SHOULD_NOT_BE_DEFINED_EQUAL cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_EQUAL is defined."); #else @@ -485,28 +503,92 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_EQUAL - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_EQUAL is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_EQUAL is not defined."); #else cmPassed("SHOULD_BE_DEFINED_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined.\n"); +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL is not defined."); #endif -#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 - cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL is not defined."); #else - cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER2 +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL3 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRLESS @@ -516,7 +598,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS is defined."); #endif @@ -528,22 +610,19 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS2 - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS2 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRGREATER - cmFailed( - "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); #else cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER is not defined."); #endif #ifndef SHOULD_BE_DEFINED_STRGREATER - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER is defined."); #endif @@ -557,11 +636,95 @@ int main() #ifndef SHOULD_BE_DEFINED_STRGREATER2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER2 is defined."); #endif +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is defined."); +#endif + // ---------------------------------------------------------------------- // Test FOREACH diff --git a/Tests/Complex/VarTests.cmake b/Tests/Complex/VarTests.cmake index 9d35949..8be59be 100644 --- a/Tests/Complex/VarTests.cmake +++ b/Tests/Complex/VarTests.cmake @@ -126,6 +126,12 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER) endif () +if (SNUM1_VAR GREATER SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER2) +endif () + if (SNUM2_VAR EQUAL SNUM1_VAR) add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) else () @@ -138,10 +144,40 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) endif () -if (SNUM1_VAR GREATER SNUM2_VAR) - add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +if (SNUM1_VAR LESS_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL) else () - add_definitions(-DSHOULD_BE_DEFINED_GREATER2) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL) +endif () + +if (SNUM2_VAR LESS_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL2) +endif () + +if (SNUM1_VAR LESS_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL3) +else () + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL3) +endif () + +if (SNUM2_VAR GREATER_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL2) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL3) endif () set (SSTR1_VAR "abc") @@ -171,6 +207,42 @@ else () add_definitions(-DSHOULD_BE_DEFINED_STRGREATER2) endif () +if (SSTR1_VAR STRLESS_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL) +endif () + +if (SSTR2_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL2) +endif () + +if (SSTR1_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3) +endif () + +if (SSTR2_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL2) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3) +endif () + # # Test FOREACH # diff --git a/Tests/ComplexOneConfig/Executable/complex.cxx b/Tests/ComplexOneConfig/Executable/complex.cxx index 5f79ac0..eeff948 100644 --- a/Tests/ComplexOneConfig/Executable/complex.cxx +++ b/Tests/ComplexOneConfig/Executable/complex.cxx @@ -478,6 +478,24 @@ int main() cmPassed("SHOULD_NOT_BE_DEFINED_GREATER is not defined."); #endif +#ifndef SHOULD_BE_DEFINED_GREATER + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined.\n"); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); +#endif + #ifdef SHOULD_NOT_BE_DEFINED_EQUAL cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_EQUAL is defined."); #else @@ -490,23 +508,86 @@ int main() cmPassed("SHOULD_BE_DEFINED_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined.\n"); +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL is not defined."); #endif -#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 - cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL is not defined."); #else - cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER2 +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL3 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRLESS @@ -516,7 +597,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS is defined."); #endif @@ -528,22 +609,19 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS2 - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS2 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRGREATER - cmFailed( - "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); #else cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER is not defined."); #endif #ifndef SHOULD_BE_DEFINED_STRGREATER - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER is defined."); #endif @@ -557,11 +635,95 @@ int main() #ifndef SHOULD_BE_DEFINED_STRGREATER2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER2 is defined."); #endif +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is defined."); +#endif + // ---------------------------------------------------------------------- // Test FOREACH diff --git a/Tests/ComplexOneConfig/VarTests.cmake b/Tests/ComplexOneConfig/VarTests.cmake index 9d35949..7dd8519 100644 --- a/Tests/ComplexOneConfig/VarTests.cmake +++ b/Tests/ComplexOneConfig/VarTests.cmake @@ -126,6 +126,12 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER) endif () +if (SNUM1_VAR GREATER SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER2) +endif () + if (SNUM2_VAR EQUAL SNUM1_VAR) add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) else () @@ -138,10 +144,40 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) endif () -if (SNUM1_VAR GREATER SNUM2_VAR) - add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +if (SNUM1_VAR LESS_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL) else () - add_definitions(-DSHOULD_BE_DEFINED_GREATER2) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL) +endif () + +if (SNUM2_VAR LESS_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL2) +endif () + +if (SNUM1_VAR LESS_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL3) +endif () + +if (SNUM2_VAR GREATER_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL2) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL3) endif () set (SSTR1_VAR "abc") @@ -171,6 +207,42 @@ else () add_definitions(-DSHOULD_BE_DEFINED_STRGREATER2) endif () +if (SSTR1_VAR STRLESS_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL) +endif () + +if (SSTR2_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL2) +endif () + +if (SSTR1_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3) +endif () + +if (SSTR2_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL2) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3) +endif () + # # Test FOREACH # ----------------------------------------------------------------------- Summary of changes: Help/command/if.rst | 59 ++++-- Help/command/string.rst | 6 +- Help/manual/cmake-generator-expressions.7.rst | 8 +- Help/release/dev/add-extra-boolean-comparisons.rst | 5 + Help/variable/CMAKE_VERSION.rst | 10 +- Source/cmCTest.cxx | 6 +- Source/cmConditionEvaluator.cxx | 32 ++- Source/cmGeneratorExpressionNode.cxx | 40 ++++ Source/cmStringCommand.cxx | 9 +- Source/cmSystemTools.cxx | 13 +- Source/cmSystemTools.h | 10 +- Tests/CMakeTests/VersionTest.cmake.in | 14 ++ Tests/CTestTestStopTime/GetDate.cmake | 4 +- Tests/Complex/CMakeLists.txt | 6 + Tests/Complex/Executable/complex.cxx | 203 ++++++++++++++++++-- Tests/Complex/VarTests.cmake | 78 +++++++- Tests/ComplexOneConfig/Executable/complex.cxx | 196 +++++++++++++++++-- Tests/ComplexOneConfig/VarTests.cmake | 78 +++++++- 18 files changed, 692 insertions(+), 85 deletions(-) create mode 100644 Help/release/dev/add-extra-boolean-comparisons.rst hooks/post-receive -- CMake From chuck.atkins at kitware.com Mon Aug 8 11:02:15 2016 From: chuck.atkins at kitware.com (Chuck Atkins) Date: Mon, 8 Aug 2016 11:02:15 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1157-g20b89cd Message-ID: <20160808150215.709F2F5364@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 20b89cd9be9f35c547e4cebc1fbbda251cad954b (commit) via dd46b956f2feabbf8041dd8cedf086dca5b54622 (commit) from 717ece197f2931fe9d633b0fe1074aa3416eed0c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=20b89cd9be9f35c547e4cebc1fbbda251cad954b commit 20b89cd9be9f35c547e4cebc1fbbda251cad954b Merge: 717ece1 dd46b95 Author: Chuck Atkins AuthorDate: Mon Aug 8 11:02:14 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 8 11:02:14 2016 -0400 Merge topic 'add-extra-boolean-comparisons' into next dd46b956 Fix Sphinx warnings https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=dd46b956f2feabbf8041dd8cedf086dca5b54622 commit dd46b956f2feabbf8041dd8cedf086dca5b54622 Author: Chuck Atkins AuthorDate: Mon Aug 8 11:01:20 2016 -0400 Commit: Chuck Atkins CommitDate: Mon Aug 8 11:01:20 2016 -0400 Fix Sphinx warnings diff --git a/Help/release/dev/add-extra-boolean-comparisons.rst b/Help/release/dev/add-extra-boolean-comparisons.rst index d47f0af..6a1db01 100644 --- a/Help/release/dev/add-extra-boolean-comparisons.rst +++ b/Help/release/dev/add-extra-boolean-comparisons.rst @@ -1,5 +1,5 @@ add-extra-boolean-comparisons --------------- +----------------------------- * Add LESS_EQUAL, GREATER_EQUAL, and thier associated STR and VERSION_ equivalents to use the combined <= and >= functionality. ----------------------------------------------------------------------- Summary of changes: Help/release/dev/add-extra-boolean-comparisons.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From chuck.atkins at kitware.com Mon Aug 8 11:03:12 2016 From: chuck.atkins at kitware.com (Chuck Atkins) Date: Mon, 8 Aug 2016 11:03:12 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1159-ge52f140 Message-ID: <20160808150312.9F128F5376@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via e52f1401237c7aa646ca6ecbe7f1eb78b018607f (commit) via 37507ffb11c441380ce6d6635b3992e09937f090 (commit) from 20b89cd9be9f35c547e4cebc1fbbda251cad954b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e52f1401237c7aa646ca6ecbe7f1eb78b018607f commit e52f1401237c7aa646ca6ecbe7f1eb78b018607f Merge: 20b89cd 37507ff Author: Chuck Atkins AuthorDate: Mon Aug 8 11:03:11 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 8 11:03:11 2016 -0400 Merge topic 'add-extra-boolean-comparisons' into next 37507ffb Add additional <= and >= comparison operators https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=37507ffb11c441380ce6d6635b3992e09937f090 commit 37507ffb11c441380ce6d6635b3992e09937f090 Author: Chuck Atkins AuthorDate: Fri Aug 5 14:11:46 2016 -0400 Commit: Chuck Atkins CommitDate: Mon Aug 8 11:02:27 2016 -0400 Add additional <= and >= comparison operators This adds the LESS_EQUAL, GREATER_EQUAL, and associated STR and VERSION_ equivalents to use the combined <= and >= functionality. diff --git a/Help/command/if.rst b/Help/command/if.rst index 56e618c..0941029 100644 --- a/Help/command/if.rst +++ b/Help/command/if.rst @@ -30,10 +30,12 @@ else and endif clause is optional. Long expressions can be used and there is a traditional order of precedence. Parenthetical expressions are evaluated first followed by unary tests such as ``EXISTS``, ``COMMAND``, and ``DEFINED``. Then any binary tests such as -``EQUAL``, ``LESS``, ``GREATER``, ``STRLESS``, ``STRGREATER``, -``STREQUAL``, and ``MATCHES`` will be evaluated. Then boolean ``NOT`` -operators and finally boolean ``AND`` and then ``OR`` operators will -be evaluated. +``EQUAL``, ``LESS``, ``LESS_EQUAL, ``GREATER``, ``GREATER_EQUAL``, +``STREQUAL``, ``STRLESS``, ``STRLESS_EQUAL``, ``STRGREATER``, +``STRGREATER_EQUAL``, ``VERSION_EQUAL``, ``VERSION_LESS``, +``VERSION_LESS_EQUAL``, ``VERSION_GREATER``, ``VERSION_GREATER_EQUAL``, +and ``MATCHES`` will be evaluated. Then boolean ``NOT`` operators and +finally boolean ``AND`` and then ``OR`` operators will be evaluated. Possible expressions are: @@ -115,6 +117,14 @@ Possible expressions are: True if the given string or variable's value is a valid number and equal to that on the right. +``if( LESS_EQUAL )`` + True if the given string or variable's value is a valid number and less + than or equal to that on the right. + +``if( GREATER_EQUAL )`` + True if the given string or variable's value is a valid number and greater + than or equal to that on the right. + ``if( STRLESS )`` True if the given string or variable's value is lexicographically less than the string or variable on the right. @@ -127,15 +137,31 @@ Possible expressions are: True if the given string or variable's value is lexicographically equal to the string or variable on the right. +``if( STRLESS_EQUAL )`` + True if the given string or variable's value is lexicographically less + than or equal to the string or variable on the right. + +``if( STRGREATER_EQUAL )`` + True if the given string or variable's value is lexicographically greater + than or equal to the string or variable on the right. + ``if( VERSION_LESS )`` Component-wise integer version number comparison (version format is ``major[.minor[.patch[.tweak]]]``). +``if( VERSION_GREATER )`` + Component-wise integer version number comparison (version format is + ``major[.minor[.patch[.tweak]]]``). + ``if( VERSION_EQUAL )`` Component-wise integer version number comparison (version format is ``major[.minor[.patch[.tweak]]]``). -``if( VERSION_GREATER )`` +``if( VERSION_LESS_EQUAL )`` + Component-wise integer version number comparison (version format is + ``major[.minor[.patch[.tweak]]]``). + +``if( VERSION_GREATER_EQUAL )`` Component-wise integer version number comparison (version format is ``major[.minor[.patch[.tweak]]]``). @@ -186,20 +212,21 @@ above-documented signature accepts ````: * If the left hand argument to ``MATCHES`` is missing it returns false without error -* Both left and right hand arguments to ``LESS``, ``GREATER``, and - ``EQUAL`` are independently tested to see if they are defined - variables, if so their defined values are used otherwise the original - value is used. +* Both left and right hand arguments to ``LESS``, ``GREATER``, ``EQUAL``, + ``LESS_EQUAL``, and ``GREATER_EQUAL``, are independently tested to see if + they are defined variables, if so their defined values are used otherwise + the original value is used. -* Both left and right hand arguments to ``STRLESS``, ``STREQUAL``, and - ``STRGREATER`` are independently tested to see if they are defined - variables, if so their defined values are used otherwise the original - value is used. +* Both left and right hand arguments to ``STRLESS``, ``STRGREATER``, + ``STREQUAL``, ``STRLESS_EQUAL``, and ``STRGREATER_EQUAL`` are independently + tested to see if they are defined variables, if so their defined values are + used otherwise the original value is used. * Both left and right hand arguments to ``VERSION_LESS``, - ``VERSION_EQUAL``, and ``VERSION_GREATER`` are independently tested - to see if they are defined variables, if so their defined values are - used otherwise the original value is used. + ``VERSION_GREATER``, ``VERSION_EQUAL``, ``VERSION_LESS_EQUAL``, and + ``VERSION_GREATER_EQUAL`` are independently tested to see if they are defined + variables, if so their defined values are used otherwise the original value + is used. * The right hand argument to ``NOT`` is tested to see if it is a boolean constant, if so the value is used, otherwise it is assumed to be a diff --git a/Help/command/string.rst b/Help/command/string.rst index 3f4050e..19a095a 100644 --- a/Help/command/string.rst +++ b/Help/command/string.rst @@ -197,10 +197,12 @@ Comparison :: - string(COMPARE EQUAL ) - string(COMPARE NOTEQUAL ) string(COMPARE LESS ) string(COMPARE GREATER ) + string(COMPARE EQUAL ) + string(COMPARE NOTEQUAL ) + string(COMPARE LESS_EQUAL ) + string(COMPARE GREATER_EQUAL ) Compare the strings and store true or false in the output variable. diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index d4f47dd..64d15a9 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -66,12 +66,16 @@ Available logical expressions are: ``1`` if the CMake-id of the C compiler matches ``comp``, otherwise ``0``. ``$`` ``1`` if the CMake-id of the CXX compiler matches ``comp``, otherwise ``0``. -``$`` - ``1`` if ``v1`` is a version greater than ``v2``, else ``0``. ``$`` ``1`` if ``v1`` is a version less than ``v2``, else ``0``. +``$`` + ``1`` if ``v1`` is a version greater than ``v2``, else ``0``. ``$`` ``1`` if ``v1`` is the same version as ``v2``, else ``0``. +``$`` + ``1`` if ``v1`` is a version less than or equal to ``v2``, else ``0``. +``$`` + ``1`` if ``v1`` is a version greater than or equal to ``v2``, else ``0``. ``$`` ``1`` if the version of the C compiler matches ``ver``, otherwise ``0``. ``$`` diff --git a/Help/release/dev/add-extra-boolean-comparisons.rst b/Help/release/dev/add-extra-boolean-comparisons.rst new file mode 100644 index 0000000..6a1db01 --- /dev/null +++ b/Help/release/dev/add-extra-boolean-comparisons.rst @@ -0,0 +1,5 @@ +add-extra-boolean-comparisons +----------------------------- + +* Add LESS_EQUAL, GREATER_EQUAL, and thier associated STR and VERSION_ + equivalents to use the combined <= and >= functionality. diff --git a/Help/variable/CMAKE_VERSION.rst b/Help/variable/CMAKE_VERSION.rst index bbb1d91..872e2fa 100644 --- a/Help/variable/CMAKE_VERSION.rst +++ b/Help/variable/CMAKE_VERSION.rst @@ -26,11 +26,11 @@ Individual component values are also available in variables: * :variable:`CMAKE_PATCH_VERSION` * :variable:`CMAKE_TWEAK_VERSION` -Use the :command:`if` command ``VERSION_LESS``, ``VERSION_EQUAL``, or -``VERSION_GREATER`` operators to compare version string values against -``CMAKE_VERSION`` using a component-wise test. Version component -values may be 10 or larger so do not attempt to compare version -strings as floating-point numbers. +Use the :command:`if` command ``VERSION_LESS``, ``VERSION_GREATER``, +``VERSION_EQUAL``, ``VERSION_LESS_EQUAL``, or ``VERSION_GREATER_EQUAL`` +operators to compare version string values against ``CMAKE_VERSION`` using a +component-wise test. Version component values may be 10 or larger so do not +attempt to compare version strings as floating-point numbers. .. note:: diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 0101049..141a00e 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -367,10 +367,8 @@ bool cmCTest::ShouldCompressTestOutput() std::string cdashVersion = this->GetCDashVersion(); // version >= 1.6? bool cdashSupportsGzip = - cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, - cdashVersion.c_str(), "1.6") || - cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, - cdashVersion.c_str(), "1.6"); + cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, + cdashVersion.c_str(), "1.6"); this->CompressTestOutput &= cdashSupportsGzip; this->ComputedCompressTestOutput = true; } diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index e02221c..d7532b3 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -21,12 +21,14 @@ static std::string const keyDEFINED = "DEFINED"; static std::string const keyEQUAL = "EQUAL"; static std::string const keyEXISTS = "EXISTS"; static std::string const keyGREATER = "GREATER"; +static std::string const keyGREATER_EQUAL = "GREATER_EQUAL"; static std::string const keyIN_LIST = "IN_LIST"; static std::string const keyIS_ABSOLUTE = "IS_ABSOLUTE"; static std::string const keyIS_DIRECTORY = "IS_DIRECTORY"; static std::string const keyIS_NEWER_THAN = "IS_NEWER_THAN"; static std::string const keyIS_SYMLINK = "IS_SYMLINK"; static std::string const keyLESS = "LESS"; +static std::string const keyLESS_EQUAL = "LESS_EQUAL"; static std::string const keyMATCHES = "MATCHES"; static std::string const keyNOT = "NOT"; static std::string const keyOR = "OR"; @@ -35,12 +37,16 @@ static std::string const keyParenR = ")"; static std::string const keyPOLICY = "POLICY"; static std::string const keySTREQUAL = "STREQUAL"; static std::string const keySTRGREATER = "STRGREATER"; +static std::string const keySTRGREATER_EQUAL = "STRGREATER_EQUAL"; static std::string const keySTRLESS = "STRLESS"; +static std::string const keySTRLESS_EQUAL = "STRLESS_EQUAL"; static std::string const keyTARGET = "TARGET"; static std::string const keyTEST = "TEST"; static std::string const keyVERSION_EQUAL = "VERSION_EQUAL"; static std::string const keyVERSION_GREATER = "VERSION_GREATER"; +static std::string const keyVERSION_GREATER_EQUAL = "VERSION_GREATER_EQUAL"; static std::string const keyVERSION_LESS = "VERSION_LESS"; +static std::string const keyVERSION_LESS_EQUAL = "VERSION_LESS_EQUAL"; cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile, const cmListFileContext& context, @@ -559,7 +565,9 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, if (argP1 != newArgs.end() && argP2 != newArgs.end() && (this->IsKeyword(keyLESS, *argP1) || + this->IsKeyword(keyLESS_EQUAL, *argP1) || this->IsKeyword(keyGREATER, *argP1) || + this->IsKeyword(keyGREATER_EQUAL, *argP1) || this->IsKeyword(keyEQUAL, *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); @@ -570,8 +578,12 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, result = false; } else if (*(argP1) == keyLESS) { result = (lhs < rhs); + } else if (*(argP1) == keyLESS_EQUAL) { + result = (lhs <= rhs); } else if (*(argP1) == keyGREATER) { result = (lhs > rhs); + } else if (*(argP1) == keyGREATER_EQUAL) { + result = (lhs >= rhs); } else { result = (lhs == rhs); } @@ -580,16 +592,22 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, if (argP1 != newArgs.end() && argP2 != newArgs.end() && (this->IsKeyword(keySTRLESS, *argP1) || - this->IsKeyword(keySTREQUAL, *argP1) || - this->IsKeyword(keySTRGREATER, *argP1))) { + this->IsKeyword(keySTRLESS_EQUAL, *argP1) || + this->IsKeyword(keySTRGREATER, *argP1) || + this->IsKeyword(keySTRGREATER_EQUAL, *argP1) || + this->IsKeyword(keySTREQUAL, *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); int val = strcmp(def, def2); bool result; if (*(argP1) == keySTRLESS) { result = (val < 0); + } else if (*(argP1) == keySTRLESS_EQUAL) { + result = (val <= 0); } else if (*(argP1) == keySTRGREATER) { result = (val > 0); + } else if (*(argP1) == keySTRGREATER_EQUAL) { + result = (val >= 0); } else // strequal { result = (val == 0); @@ -599,15 +617,23 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, if (argP1 != newArgs.end() && argP2 != newArgs.end() && (this->IsKeyword(keyVERSION_LESS, *argP1) || + this->IsKeyword(keyVERSION_LESS_EQUAL, *argP1) || this->IsKeyword(keyVERSION_GREATER, *argP1) || + this->IsKeyword(keyVERSION_GREATER_EQUAL, *argP1) || this->IsKeyword(keyVERSION_EQUAL, *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); - cmSystemTools::CompareOp op = cmSystemTools::OP_EQUAL; + cmSystemTools::CompareOp op; if (*argP1 == keyVERSION_LESS) { op = cmSystemTools::OP_LESS; + } else if (*argP1 == keyVERSION_LESS_EQUAL) { + op = cmSystemTools::OP_LESS_EQUAL; } else if (*argP1 == keyVERSION_GREATER) { op = cmSystemTools::OP_GREATER; + } else if (*argP1 == keyVERSION_GREATER_EQUAL) { + op = cmSystemTools::OP_GREATER_EQUAL; + } else { // version_equal + op = cmSystemTools::OP_EQUAL; } bool result = cmSystemTools::VersionCompare(op, def, def2); this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2); diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index ca7250b..6e2b16a 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -545,6 +545,25 @@ static const struct VersionGreaterNode : public cmGeneratorExpressionNode } } versionGreaterNode; +static const struct VersionGreaterEqNode : public cmGeneratorExpressionNode +{ + VersionGreaterEqNode() {} + + int NumExpectedParameters() const CM_OVERRIDE { return 2; } + + std::string Evaluate(const std::vector& parameters, + cmGeneratorExpressionContext*, + const GeneratorExpressionContent*, + cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + { + return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, + parameters.front().c_str(), + parameters[1].c_str()) + ? "1" + : "0"; + } +} versionGreaterEqNode; + static const struct VersionLessNode : public cmGeneratorExpressionNode { VersionLessNode() {} @@ -564,6 +583,25 @@ static const struct VersionLessNode : public cmGeneratorExpressionNode } } versionLessNode; +static const struct VersionLessEqNode : public cmGeneratorExpressionNode +{ + VersionLessEqNode() {} + + int NumExpectedParameters() const CM_OVERRIDE { return 2; } + + std::string Evaluate(const std::vector& parameters, + cmGeneratorExpressionContext*, + const GeneratorExpressionContent*, + cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + { + return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS_EQUAL, + parameters.front().c_str(), + parameters[1].c_str()) + ? "1" + : "0"; + } +} versionLessEqNode; + static const struct VersionEqualNode : public cmGeneratorExpressionNode { VersionEqualNode() {} @@ -1641,7 +1679,9 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( nodeMap["C_COMPILER_ID"] = &cCompilerIdNode; nodeMap["CXX_COMPILER_ID"] = &cxxCompilerIdNode; nodeMap["VERSION_GREATER"] = &versionGreaterNode; + nodeMap["VERSION_GREATER_EQUAL"] = &versionGreaterEqNode; nodeMap["VERSION_LESS"] = &versionLessNode; + nodeMap["VERSION_LESS_EQUAL"] = &versionLessEqNode; nodeMap["VERSION_EQUAL"] = &versionEqualNode; nodeMap["C_COMPILER_VERSION"] = &cCompilerVersionNode; nodeMap["CXX_COMPILER_VERSION"] = &cxxCompilerVersionNode; diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index dce4687..705fc7d 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -484,8 +484,9 @@ bool cmStringCommand::HandleCompareCommand( return false; } std::string mode = args[1]; - if ((mode == "EQUAL") || (mode == "NOTEQUAL") || (mode == "LESS") || - (mode == "GREATER")) { + if ((mode == "EQUAL") || (mode == "NOTEQUAL") || + (mode == "LESS") || (mode == "LESS_EQUAL") || + (mode == "GREATER") || (mode == "GREATER_EQUAL")) { if (args.size() < 5) { std::string e = "sub-command COMPARE, mode "; e += mode; @@ -500,8 +501,12 @@ bool cmStringCommand::HandleCompareCommand( bool result; if (mode == "LESS") { result = (left < right); + } else if (mode == "LESS_EQUAL") { + result = (left <= right); } else if (mode == "GREATER") { result = (left > right); + } else if (mode == "GREATER_EQUAL") { + result = (left >= right); } else if (mode == "EQUAL") { result = (left == right); } else // if(mode == "NOTEQUAL") diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 9740ef7..5745a01 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -2380,10 +2380,10 @@ bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op, if (lhs < rhs) { // lhs < rhs, so true if operation is LESS - return op == cmSystemTools::OP_LESS; + return (op & cmSystemTools::OP_LESS) != 0; } else if (lhs > rhs) { // lhs > rhs, so true if operation is GREATER - return op == cmSystemTools::OP_GREATER; + return (op & cmSystemTools::OP_GREATER) != 0; } if (*endr == '.') { @@ -2395,7 +2395,7 @@ bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op, } } // lhs == rhs, so true if operation is EQUAL - return op == cmSystemTools::OP_EQUAL; + return (op & cmSystemTools::OP_EQUAL) != 0; } bool cmSystemTools::VersionCompareEqual(std::string const& lhs, @@ -2412,6 +2412,13 @@ bool cmSystemTools::VersionCompareGreater(std::string const& lhs, rhs.c_str()); } +bool cmSystemTools::VersionCompareGreaterEq(std::string const& lhs, + std::string const& rhs) +{ + return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, + lhs.c_str(), rhs.c_str()); +} + bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, bool* removed) { diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 39e7994..f031273 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -284,9 +284,11 @@ public: enum CompareOp { - OP_LESS, - OP_GREATER, - OP_EQUAL + OP_EQUAL = 1, + OP_LESS = 2, + OP_GREATER = 4, + OP_LESS_EQUAL = OP_LESS | OP_EQUAL, + OP_GREATER_EQUAL = OP_GREATER | OP_EQUAL }; /** @@ -297,6 +299,8 @@ public: std::string const& rhs); static bool VersionCompareGreater(std::string const& lhs, std::string const& rhs); + static bool VersionCompareGreaterEq(std::string const& lhs, + std::string const& rhs); /** * Determine the file type based on the extension diff --git a/Tests/CMakeTests/VersionTest.cmake.in b/Tests/CMakeTests/VersionTest.cmake.in index 4e946ab..f045605 100644 --- a/Tests/CMakeTests/VersionTest.cmake.in +++ b/Tests/CMakeTests/VersionTest.cmake.in @@ -83,10 +83,24 @@ foreach(v IN LISTS LESSV) message(FATAL_ERROR "${CMAKE_MATCH_2} is less than ${CMAKE_MATCH_1}?") endif() + # check greater or equal (same as less negative) + if(CMAKE_MATCH_2 VERSION_GREATER_EQUAL CMAKE_MATCH_1) + message(STATUS "${CMAKE_MATCH_2} is not less than ${CMAKE_MATCH_1}") + else() + message(FATAL_ERROR "${CMAKE_MATCH_2} is less than ${CMAKE_MATCH_1}?") + endif() + # check greater negative case if(NOT CMAKE_MATCH_1 VERSION_GREATER CMAKE_MATCH_2) message(STATUS "${CMAKE_MATCH_1} is not greater than ${CMAKE_MATCH_2}") else() message(FATAL_ERROR "${CMAKE_MATCH_1} is greater than ${CMAKE_MATCH_2}?") endif() + + # check less or equal (same as greater negative) case + if(CMAKE_MATCH_1 VERSION_LESS_EQUAL CMAKE_MATCH_2) + message(STATUS "${CMAKE_MATCH_1} is not greater than ${CMAKE_MATCH_2}") + else() + message(FATAL_ERROR "${CMAKE_MATCH_1} is greater than ${CMAKE_MATCH_2}?") + endif() endforeach() diff --git a/Tests/CTestTestStopTime/GetDate.cmake b/Tests/CTestTestStopTime/GetDate.cmake index edc6519..1f4cb24 100644 --- a/Tests/CTestTestStopTime/GetDate.cmake +++ b/Tests/CTestTestStopTime/GetDate.cmake @@ -106,11 +106,11 @@ macro(ADD_SECONDS sec) set(new_min ${${GD_PREFIX}MINUTE}) set(new_hr ${${GD_PREFIX}HOUR}) math(EXPR new_sec "${sec} + ${${GD_PREFIX}SECOND}") - while(${new_sec} GREATER 60 OR ${new_sec} EQUAL 60) + while(${new_sec} GREATER_EQUAL 60) math(EXPR new_sec "${new_sec} - 60") math(EXPR new_min "${${GD_PREFIX}MINUTE} + 1") endwhile() - while(${new_min} GREATER 60 OR ${new_min} EQUAL 60) + while(${new_min} GREATER_EQUAL 60) math(EXPR new_min "${new_min} - 60") math(EXPR new_hr "${${GD_PREFIX}HOUR} + 1") endwhile() diff --git a/Tests/Complex/CMakeLists.txt b/Tests/Complex/CMakeLists.txt index 80cc2e3..075faa7 100644 --- a/Tests/Complex/CMakeLists.txt +++ b/Tests/Complex/CMakeLists.txt @@ -92,6 +92,12 @@ endif() if(NOT 2.4 EQUAL 2.4) message(FATAL_ERROR "Failed: NOT 2.4 EQUAL 2.4") endif() +if(NOT 2.4 LESS_EQUAL 2.4) + message(FATAL_ERROR "Failed: NOT 2.4 LESS_EQUAL 2.4") +endif() +if(NOT 2.4 GREATER_EQUAL 2.4) + message(FATAL_ERROR "Failed: NOT 2.4 GREATER_EQUAL 2.4") +endif() if(CMAKE_SYSTEM MATCHES "OSF1-V") if(NOT CMAKE_COMPILER_IS_GNUCXX) diff --git a/Tests/Complex/Executable/complex.cxx b/Tests/Complex/Executable/complex.cxx index 5f79ac0..f335d67 100644 --- a/Tests/Complex/Executable/complex.cxx +++ b/Tests/Complex/Executable/complex.cxx @@ -455,7 +455,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_LESS - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS is not defined."); #else cmPassed("SHOULD_BE_DEFINED_LESS is defined."); #endif @@ -467,7 +467,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_LESS2 - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS2 is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_LESS2 is defined."); #endif @@ -478,6 +478,24 @@ int main() cmPassed("SHOULD_NOT_BE_DEFINED_GREATER is not defined."); #endif +#ifndef SHOULD_BE_DEFINED_GREATER + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); +#endif + #ifdef SHOULD_NOT_BE_DEFINED_EQUAL cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_EQUAL is defined."); #else @@ -485,28 +503,92 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_EQUAL - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_EQUAL is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_EQUAL is not defined."); #else cmPassed("SHOULD_BE_DEFINED_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined.\n"); +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL is not defined."); #endif -#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 - cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL is not defined."); #else - cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER2 +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL3 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRLESS @@ -516,7 +598,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS is defined."); #endif @@ -528,22 +610,19 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS2 - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS2 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRGREATER - cmFailed( - "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); #else cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER is not defined."); #endif #ifndef SHOULD_BE_DEFINED_STRGREATER - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER is defined."); #endif @@ -557,11 +636,95 @@ int main() #ifndef SHOULD_BE_DEFINED_STRGREATER2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER2 is defined."); #endif +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is defined."); +#endif + // ---------------------------------------------------------------------- // Test FOREACH diff --git a/Tests/Complex/VarTests.cmake b/Tests/Complex/VarTests.cmake index 9d35949..8be59be 100644 --- a/Tests/Complex/VarTests.cmake +++ b/Tests/Complex/VarTests.cmake @@ -126,6 +126,12 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER) endif () +if (SNUM1_VAR GREATER SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER2) +endif () + if (SNUM2_VAR EQUAL SNUM1_VAR) add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) else () @@ -138,10 +144,40 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) endif () -if (SNUM1_VAR GREATER SNUM2_VAR) - add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +if (SNUM1_VAR LESS_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL) else () - add_definitions(-DSHOULD_BE_DEFINED_GREATER2) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL) +endif () + +if (SNUM2_VAR LESS_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL2) +endif () + +if (SNUM1_VAR LESS_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL3) +else () + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL3) +endif () + +if (SNUM2_VAR GREATER_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL2) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL3) endif () set (SSTR1_VAR "abc") @@ -171,6 +207,42 @@ else () add_definitions(-DSHOULD_BE_DEFINED_STRGREATER2) endif () +if (SSTR1_VAR STRLESS_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL) +endif () + +if (SSTR2_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL2) +endif () + +if (SSTR1_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3) +endif () + +if (SSTR2_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL2) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3) +endif () + # # Test FOREACH # diff --git a/Tests/ComplexOneConfig/Executable/complex.cxx b/Tests/ComplexOneConfig/Executable/complex.cxx index 5f79ac0..eeff948 100644 --- a/Tests/ComplexOneConfig/Executable/complex.cxx +++ b/Tests/ComplexOneConfig/Executable/complex.cxx @@ -478,6 +478,24 @@ int main() cmPassed("SHOULD_NOT_BE_DEFINED_GREATER is not defined."); #endif +#ifndef SHOULD_BE_DEFINED_GREATER + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined.\n"); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); +#endif + #ifdef SHOULD_NOT_BE_DEFINED_EQUAL cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_EQUAL is defined."); #else @@ -490,23 +508,86 @@ int main() cmPassed("SHOULD_BE_DEFINED_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined.\n"); +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL is not defined."); #endif -#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 - cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL is not defined."); #else - cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER2 +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL3 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRLESS @@ -516,7 +597,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS is defined."); #endif @@ -528,22 +609,19 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS2 - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS2 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRGREATER - cmFailed( - "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); #else cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER is not defined."); #endif #ifndef SHOULD_BE_DEFINED_STRGREATER - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER is defined."); #endif @@ -557,11 +635,95 @@ int main() #ifndef SHOULD_BE_DEFINED_STRGREATER2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER2 is defined."); #endif +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is defined."); +#endif + // ---------------------------------------------------------------------- // Test FOREACH diff --git a/Tests/ComplexOneConfig/VarTests.cmake b/Tests/ComplexOneConfig/VarTests.cmake index 9d35949..7dd8519 100644 --- a/Tests/ComplexOneConfig/VarTests.cmake +++ b/Tests/ComplexOneConfig/VarTests.cmake @@ -126,6 +126,12 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER) endif () +if (SNUM1_VAR GREATER SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER2) +endif () + if (SNUM2_VAR EQUAL SNUM1_VAR) add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) else () @@ -138,10 +144,40 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) endif () -if (SNUM1_VAR GREATER SNUM2_VAR) - add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +if (SNUM1_VAR LESS_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL) else () - add_definitions(-DSHOULD_BE_DEFINED_GREATER2) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL) +endif () + +if (SNUM2_VAR LESS_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL2) +endif () + +if (SNUM1_VAR LESS_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL3) +endif () + +if (SNUM2_VAR GREATER_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL2) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL3) endif () set (SSTR1_VAR "abc") @@ -171,6 +207,42 @@ else () add_definitions(-DSHOULD_BE_DEFINED_STRGREATER2) endif () +if (SSTR1_VAR STRLESS_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL) +endif () + +if (SSTR2_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL2) +endif () + +if (SSTR1_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3) +endif () + +if (SSTR2_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL2) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3) +endif () + # # Test FOREACH # ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 8 13:22:08 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 8 Aug 2016 13:22:08 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1165-ge10f5fc Message-ID: <20160808172208.7ACB9F46B1@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via e10f5fc665ea07d533a9fcd3ee6f519a650491f0 (commit) via 20f0028cc656e0065db09058888e2a4905c0cdc7 (commit) via 71d0308a6f400bd9d2cd993f71461c55a1c3d57d (commit) via 3e2cd04ba67acbd3962e98374a357bc2c45810ff (commit) via 06217388de8014f32173cea9244fd5a43b40fd3a (commit) via ecb6df52a1137c6e176e54263ea1b6f9a0848a31 (commit) from e52f1401237c7aa646ca6ecbe7f1eb78b018607f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e10f5fc665ea07d533a9fcd3ee6f519a650491f0 commit e10f5fc665ea07d533a9fcd3ee6f519a650491f0 Merge: e52f140 20f0028 Author: Brad King AuthorDate: Mon Aug 8 13:22:06 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 8 13:22:06 2016 -0400 Merge topic 'autogen-same-name' into next 20f0028c Tests/QtAutogen: Test same moc/qrc source names in different directories 71d0308a QtAutogen: Allow multiple qrc files with the same name 3e2cd04b QtAutogen: Allow multiple moc files with the same name 06217388 QtAutogen: Use std:: instead of ::std:: ecb6df52 cmFilePathUuid: Add class to generate deterministic unique file names https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=20f0028cc656e0065db09058888e2a4905c0cdc7 commit 20f0028cc656e0065db09058888e2a4905c0cdc7 Author: Sebastian Holtermann AuthorDate: Sat Aug 6 15:22:54 2016 +0200 Commit: Brad King CommitDate: Mon Aug 8 13:21:39 2016 -0400 Tests/QtAutogen: Test same moc/qrc source names in different directories diff --git a/Tests/QtAutogen/CMakeLists.txt b/Tests/QtAutogen/CMakeLists.txt index d5aca55..e35e1d1 100644 --- a/Tests/QtAutogen/CMakeLists.txt +++ b/Tests/QtAutogen/CMakeLists.txt @@ -110,6 +110,10 @@ set_target_properties( AUTOMOC TRUE ) +# Test AUTOMOC and AUTORCC on source files with the same name +# but in different subdirectories +add_subdirectory(sameName) + include(GenerateExportHeader) # The order is relevant here. B depends on A, and B headers depend on A # headers both subdirectories use CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE and we diff --git a/Tests/QtAutogen/sameName/CMakeLists.txt b/Tests/QtAutogen/sameName/CMakeLists.txt new file mode 100644 index 0000000..ed045fb --- /dev/null +++ b/Tests/QtAutogen/sameName/CMakeLists.txt @@ -0,0 +1,21 @@ +# Test AUTOMOC and AUTORCC on source files with the same name +# but in different subdirectories + +add_executable(sameName + aaa/bbb/item.cpp + aaa/bbb/data.qrc + aaa/item.cpp + aaa/data.qrc + bbb/aaa/item.cpp + bbb/aaa/data.qrc + bbb/item.cpp + bbb/data.qrc + ccc/item.cpp + ccc/data.qrc + item.cpp + data.qrc + main.cpp +) +target_include_directories(sameName PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_link_libraries(sameName ${QT_LIBRARIES}) +set_target_properties( sameName PROPERTIES AUTOMOC TRUE AUTORCC TRUE ) diff --git a/Tests/QtAutogen/sameName/aaa/bbb/data.qrc b/Tests/QtAutogen/sameName/aaa/bbb/data.qrc new file mode 100644 index 0000000..0ea3537 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/bbb/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/aaa/bbb/item.cpp b/Tests/QtAutogen/sameName/aaa/bbb/item.cpp new file mode 100644 index 0000000..20d0044 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/bbb/item.cpp @@ -0,0 +1,10 @@ +#include "item.hpp" + +namespace aaa { +namespace bbb { + +void Item::go() +{ +} +} +} diff --git a/Tests/QtAutogen/sameName/aaa/bbb/item.hpp b/Tests/QtAutogen/sameName/aaa/bbb/item.hpp new file mode 100644 index 0000000..0855043 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/bbb/item.hpp @@ -0,0 +1,18 @@ +#ifndef AAA_BBB_ITEM_HPP +#define AAA_BBB_ITEM_HPP + +#include + +namespace aaa { +namespace bbb { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} +} + +#endif diff --git a/Tests/QtAutogen/sameName/aaa/data.qrc b/Tests/QtAutogen/sameName/aaa/data.qrc new file mode 100644 index 0000000..379af60 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/aaa/item.cpp b/Tests/QtAutogen/sameName/aaa/item.cpp new file mode 100644 index 0000000..95dd3b6 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/item.cpp @@ -0,0 +1,8 @@ +#include "item.hpp" + +namespace aaa { + +void Item::go() +{ +} +} diff --git a/Tests/QtAutogen/sameName/aaa/item.hpp b/Tests/QtAutogen/sameName/aaa/item.hpp new file mode 100644 index 0000000..b63466f --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/item.hpp @@ -0,0 +1,16 @@ +#ifndef AAA_ITEM_HPP +#define AAA_ITEM_HPP + +#include + +namespace aaa { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} + +#endif diff --git a/Tests/QtAutogen/sameName/bbb/aaa/data.qrc b/Tests/QtAutogen/sameName/bbb/aaa/data.qrc new file mode 100644 index 0000000..da98009 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/aaa/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/bbb/aaa/item.cpp b/Tests/QtAutogen/sameName/bbb/aaa/item.cpp new file mode 100644 index 0000000..ac4b2c2 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/aaa/item.cpp @@ -0,0 +1,10 @@ +#include "item.hpp" + +namespace bbb { +namespace aaa { + +void Item::go() +{ +} +} +} diff --git a/Tests/QtAutogen/sameName/bbb/aaa/item.hpp b/Tests/QtAutogen/sameName/bbb/aaa/item.hpp new file mode 100644 index 0000000..be07ca8 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/aaa/item.hpp @@ -0,0 +1,18 @@ +#ifndef BBB_AAA_ITEM_HPP +#define BBB_AAA_ITEM_HPP + +#include + +namespace bbb { +namespace aaa { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} +} + +#endif diff --git a/Tests/QtAutogen/sameName/bbb/data.qrc b/Tests/QtAutogen/sameName/bbb/data.qrc new file mode 100644 index 0000000..5b080f5 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/bbb/item.cpp b/Tests/QtAutogen/sameName/bbb/item.cpp new file mode 100644 index 0000000..f97a143 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/item.cpp @@ -0,0 +1,8 @@ +#include "item.hpp" + +namespace bbb { + +void Item::go() +{ +} +} diff --git a/Tests/QtAutogen/sameName/bbb/item.hpp b/Tests/QtAutogen/sameName/bbb/item.hpp new file mode 100644 index 0000000..5b7f985 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/item.hpp @@ -0,0 +1,16 @@ +#ifndef BBB_ITEM_HPP +#define BBB_ITEM_HPP + +#include + +namespace bbb { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} + +#endif diff --git a/Tests/QtAutogen/sameName/ccc/data.qrc b/Tests/QtAutogen/sameName/ccc/data.qrc new file mode 100644 index 0000000..f934c39 --- /dev/null +++ b/Tests/QtAutogen/sameName/ccc/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/ccc/item.cpp b/Tests/QtAutogen/sameName/ccc/item.cpp new file mode 100644 index 0000000..d90b2b8 --- /dev/null +++ b/Tests/QtAutogen/sameName/ccc/item.cpp @@ -0,0 +1,23 @@ +#include "item.hpp" + +namespace ccc { + +void Item::go() +{ +} + +class MocTest : public QObject +{ + Q_OBJECT; + Q_SLOT + void go(); +}; + +void MocTest::go() +{ +} +} + +// Include own moc files +#include "item.moc" +#include "moc_item.cpp" diff --git a/Tests/QtAutogen/sameName/ccc/item.hpp b/Tests/QtAutogen/sameName/ccc/item.hpp new file mode 100644 index 0000000..96fcc24 --- /dev/null +++ b/Tests/QtAutogen/sameName/ccc/item.hpp @@ -0,0 +1,16 @@ +#ifndef CCC_ITEM_HPP +#define CCC_ITEM_HPP + +#include + +namespace ccc { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} + +#endif diff --git a/Tests/QtAutogen/sameName/data.qrc b/Tests/QtAutogen/sameName/data.qrc new file mode 100644 index 0000000..4ce0b4e --- /dev/null +++ b/Tests/QtAutogen/sameName/data.qrc @@ -0,0 +1,5 @@ + + + main.cpp + + diff --git a/Tests/QtAutogen/sameName/item.cpp b/Tests/QtAutogen/sameName/item.cpp new file mode 100644 index 0000000..e013cf3 --- /dev/null +++ b/Tests/QtAutogen/sameName/item.cpp @@ -0,0 +1,5 @@ +#include "item.hpp" + +void Item::go() +{ +} diff --git a/Tests/QtAutogen/sameName/item.hpp b/Tests/QtAutogen/sameName/item.hpp new file mode 100644 index 0000000..91bba3b --- /dev/null +++ b/Tests/QtAutogen/sameName/item.hpp @@ -0,0 +1,13 @@ +#ifndef ITEM_HPP +#define ITEM_HPP + +#include + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; + +#endif diff --git a/Tests/QtAutogen/sameName/main.cpp b/Tests/QtAutogen/sameName/main.cpp new file mode 100644 index 0000000..a4ffcb3 --- /dev/null +++ b/Tests/QtAutogen/sameName/main.cpp @@ -0,0 +1,16 @@ +#include "aaa/bbb/item.hpp" +#include "aaa/item.hpp" +#include "bbb/aaa/item.hpp" +#include "bbb/item.hpp" +#include "ccc/item.hpp" + +int main(int argv, char** args) +{ + // Object instances + ::aaa::Item aaa_item; + ::aaa::bbb::Item aaa_bbb_item; + ::bbb::Item bbb_item; + ::bbb::aaa::Item bbb_aaa_item; + ::ccc::Item ccc_item; + return 0; +} https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=71d0308a6f400bd9d2cd993f71461c55a1c3d57d commit 71d0308a6f400bd9d2cd993f71461c55a1c3d57d Author: Sebastian Holtermann AuthorDate: Sat Aug 6 14:57:52 2016 +0200 Commit: Brad King CommitDate: Mon Aug 8 13:21:39 2016 -0400 QtAutogen: Allow multiple qrc files with the same name Use cmFilePathUuid for qrc files. diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index d5634e8..7efb333 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -13,6 +13,7 @@ #include "cmQtAutoGeneratorInitializer.h" +#include "cmFilePathUuid.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmSourceFile.h" @@ -25,6 +26,34 @@ #include "cmGlobalVisualStudioGenerator.h" #endif +static std::string GetAutogenTargetName(cmGeneratorTarget const* target) +{ + std::string autogenTargetName = target->GetName(); + autogenTargetName += "_automoc"; + return autogenTargetName; +} + +static std::string GetAutogenTargetDir(cmGeneratorTarget const* target) +{ + cmMakefile* makefile = target->Target->GetMakefile(); + std::string targetDir = makefile->GetCurrentBinaryDirectory(); + targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory(); + targetDir += "/"; + targetDir += GetAutogenTargetName(target); + targetDir += ".dir/"; + return targetDir; +} + +static std::string GetAutogenTargetBuildDir(cmGeneratorTarget const* target) +{ + cmMakefile* makefile = target->Target->GetMakefile(); + std::string targetDir = makefile->GetCurrentBinaryDirectory(); + targetDir += "/"; + targetDir += GetAutogenTargetName(target); + targetDir += ".dir/"; + return targetDir; +} + static void SetupSourceFiles(cmGeneratorTarget const* target, std::vector& skipMoc, std::vector& mocSources, @@ -38,6 +67,7 @@ static void SetupSourceFiles(cmGeneratorTarget const* target, std::vector newRccFiles; + cmFilePathUuid fpathUuid(makefile); for (std::vector::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; @@ -55,13 +85,12 @@ static void SetupSourceFiles(cmGeneratorTarget const* target, if (target->GetPropertyAsBool("AUTORCC")) { if (ext == "qrc" && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { - std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); - std::string rcc_output_dir = target->GetSupportDirectory(); - cmSystemTools::MakeDirectory(rcc_output_dir.c_str()); - std::string rcc_output_file = rcc_output_dir; - rcc_output_file += "/qrc_" + basename + ".cpp"; + std::string rcc_output_file = GetAutogenTargetBuildDir(target); + // Create output directory + cmSystemTools::MakeDirectory(rcc_output_file.c_str()); + rcc_output_file += fpathUuid.get(absFile, "qrc_", ".cpp"); + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", rcc_output_file.c_str(), false); makefile->GetOrCreateSource(rcc_output_file, true); @@ -365,24 +394,6 @@ static void MergeRccOptions(std::vector& opts, opts.insert(opts.end(), extraOpts.begin(), extraOpts.end()); } -std::string GetAutogenTargetName(cmGeneratorTarget const* target) -{ - std::string autogenTargetName = target->GetName(); - autogenTargetName += "_automoc"; - return autogenTargetName; -} - -std::string GetAutogenTargetDir(cmGeneratorTarget const* target) -{ - cmMakefile* makefile = target->Target->GetMakefile(); - std::string targetDir = makefile->GetCurrentBinaryDirectory(); - targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory(); - targetDir += "/"; - targetDir += GetAutogenTargetName(target); - targetDir += ".dir/"; - return targetDir; -} - static void copyTargetProperty(cmTarget* destinationTarget, cmTarget* sourceTarget, const std::string& propertyName) @@ -737,6 +748,7 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( ) { std::vector srcFiles; target->GetConfigCommonSourceFiles(srcFiles); + cmFilePathUuid fpathUuid(makefile); for (std::vector::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; @@ -747,15 +759,13 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( if (target->GetPropertyAsBool("AUTORCC")) { if (ext == "qrc" && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { - std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); - - std::string rcc_output_dir = target->GetSupportDirectory(); - cmSystemTools::MakeDirectory(rcc_output_dir.c_str()); - std::string rcc_output_file = rcc_output_dir; - rcc_output_file += "/qrc_" + basename + ".cpp"; - rcc_output.push_back(rcc_output_file); - + { + std::string rcc_output_file = GetAutogenTargetBuildDir(target); + // Create output directory + cmSystemTools::MakeDirectory(rcc_output_file.c_str()); + rcc_output_file += fpathUuid.get(absFile, "qrc_", ".cpp"); + rcc_output.push_back(rcc_output_file); + } if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { if (qtMajorVersion == "5") { ListQt5RccInputs(sf, target, depends); diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 33f7a54..6a95615 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -88,6 +88,23 @@ static std::string extractSubDir(const std::string& absPath, return subDir; } +static bool FileNameIsUnique(const std::string& filePath, + const std::map& fileMap) +{ + size_t count(0); + const std::string fileName = cmsys::SystemTools::GetFilenameName(filePath); + for (std::map::const_iterator si = fileMap.begin(); + si != fileMap.end(); ++si) { + if (cmsys::SystemTools::GetFilenameName(si->first) == fileName) { + ++count; + if (count > 1) { + return false; + } + } + } + return true; +} + cmQtAutoGenerators::cmQtAutoGenerators() : Verbose(cmsys::SystemTools::HasEnv("VERBOSE")) , ColorOutput(true) @@ -1257,15 +1274,18 @@ bool cmQtAutoGenerators::GenerateQrcFiles() { // generate single map with input / output names std::map qrcGenMap; - for (std::vector::const_iterator si = this->RccSources.begin(); - si != this->RccSources.end(); ++si) { - const std::string ext = cmsys::SystemTools::GetFilenameLastExtension(*si); - if (ext == ".qrc") { - std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(*si); - std::string qrcOutputFile = "CMakeFiles/" + this->OriginTargetName + - ".dir/qrc_" + basename + ".cpp"; - qrcGenMap[*si] = qrcOutputFile; + { + cmFilePathUuid fpathUuid(this->Srcdir, this->Builddir, + this->ProjectSourceDir, this->ProjectBinaryDir); + for (std::vector::const_iterator si = + this->RccSources.begin(); + si != this->RccSources.end(); ++si) { + const std::string ext = + cmsys::SystemTools::GetFilenameLastExtension(*si); + if (ext == ".qrc") { + qrcGenMap[*si] = + (this->TargetBuildSubDir + fpathUuid.get(*si, "qrc_", ".cpp")); + } } } @@ -1287,7 +1307,8 @@ bool cmQtAutoGenerators::GenerateQrcFiles() for (std::map::const_iterator si = qrcGenMap.begin(); si != qrcGenMap.end(); ++si) { - if (!this->GenerateQrc(si->first, si->second)) { + bool unique = FileNameIsUnique(si->first, qrcGenMap); + if (!this->GenerateQrc(si->first, si->second, unique)) { if (this->RunRccFailed) { return false; } @@ -1297,10 +1318,19 @@ bool cmQtAutoGenerators::GenerateQrcFiles() } bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, - const std::string& qrcOutputFile) + const std::string& qrcOutputFile, + bool unique_n) { - const std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); + std::string symbolName; + if (unique_n) { + symbolName = + cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); + } else { + symbolName = + cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcOutputFile); + // Remove "qrc_" at string begin + symbolName.erase(0, 4); + } const std::string qrcBuildFile = this->Builddir + qrcOutputFile; int sourceNewerThanQrc = 0; @@ -1327,7 +1357,7 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, } command.push_back("-name"); - command.push_back(basename); + command.push_back(symbolName); command.push_back("-o"); command.push_back(qrcBuildFile); command.push_back(qrcInputFile); diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 216b0b0..fab2d19 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -51,7 +51,8 @@ private: const std::string& uiOutputFile); bool GenerateQrcFiles(); bool GenerateQrc(const std::string& qrcInputFile, - const std::string& qrcOutputFile); + const std::string& qrcOutputFile, bool unique_n); + void ParseCppFile( const std::string& absFilename, const std::vector& headerExtensions, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3e2cd04ba67acbd3962e98374a357bc2c45810ff commit 3e2cd04ba67acbd3962e98374a357bc2c45810ff Author: Sebastian Holtermann AuthorDate: Sat Aug 6 13:33:46 2016 +0200 Commit: Brad King CommitDate: Mon Aug 8 13:21:27 2016 -0400 QtAutogen: Allow multiple moc files with the same name Use cmFilePathUuid for moc files. Closes: #12873 diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index ea8db71..33f7a54 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -14,6 +14,7 @@ #include "cmQtAutoGenerators.h" #include "cmAlgorithms.h" +#include "cmFilePathUuid.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmOutputConverter.h" @@ -358,11 +359,13 @@ void cmQtAutoGenerators::WriteOldMocDefinitionsFile( void cmQtAutoGenerators::Init() { + this->TargetBuildSubDir = this->TargetName; + this->TargetBuildSubDir += ".dir/"; + this->OutMocCppFilenameRel = this->TargetName; this->OutMocCppFilenameRel += ".cpp"; - this->OutMocCppFilename = this->Builddir; - this->OutMocCppFilename += this->OutMocCppFilenameRel; + this->OutMocCppFilenameAbs = this->Builddir + this->OutMocCppFilenameRel; std::vector cdefList; cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList); @@ -439,7 +442,7 @@ static std::string ReadAll(const std::string& filename) bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile) { - if (!cmsys::SystemTools::FileExists(this->OutMocCppFilename.c_str()) || + if (!cmsys::SystemTools::FileExists(this->OutMocCppFilenameAbs.c_str()) || (this->OldCompileSettingsStr != this->CurrentCompileSettingsStr)) { this->GenerateAll = true; } @@ -933,6 +936,8 @@ void cmQtAutoGenerators::ParseHeaders( std::map& notIncludedMocs, std::map >& includedUis) { + cmFilePathUuid fpathUuid(this->Srcdir, this->Builddir, + this->ProjectSourceDir, this->ProjectBinaryDir); for (std::set::const_iterator hIt = absHeaders.begin(); hIt != absHeaders.end(); ++hIt) { const std::string& headerName = *hIt; @@ -946,13 +951,10 @@ void cmQtAutoGenerators::ParseHeaders( this->LogInfo(err.str()); } - const std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(headerName); - - const std::string currentMoc = "moc_" + basename + ".cpp"; std::string macroName; if (requiresMocing(contents, macroName)) { - notIncludedMocs[headerName] = currentMoc; + notIncludedMocs[headerName] = + this->TargetBuildSubDir + fpathUuid.get(headerName, "moc_", ".cpp"); } } this->ParseForUic(headerName, contents, includedUis); @@ -1029,7 +1031,7 @@ bool cmQtAutoGenerators::GenerateMocFiles( // check if we even need to update _automoc.cpp if (!automocCppChanged) { // compare contents of the _automoc.cpp file - const std::string oldContents = ReadAll(this->OutMocCppFilename); + const std::string oldContents = ReadAll(this->OutMocCppFilenameAbs); if (oldContents == automocSource) { // nothing changed: don't touch the _automoc.cpp file if (this->Verbose) { @@ -1052,7 +1054,7 @@ bool cmQtAutoGenerators::GenerateMocFiles( } { cmsys::ofstream outfile; - outfile.open(this->OutMocCppFilename.c_str(), std::ios::trunc); + outfile.open(this->OutMocCppFilenameAbs.c_str(), std::ios::trunc); outfile << automocSource; outfile.close(); } diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 86913f0..216b0b0 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -123,8 +123,9 @@ private: std::string CurrentCompileSettingsStr; std::string OldCompileSettingsStr; + std::string TargetBuildSubDir; std::string OutMocCppFilenameRel; - std::string OutMocCppFilename; + std::string OutMocCppFilenameAbs; std::list MocIncludes; std::list MocDefinitions; std::vector MocOptions; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=06217388de8014f32173cea9244fd5a43b40fd3a commit 06217388de8014f32173cea9244fd5a43b40fd3a Author: Sebastian Holtermann AuthorDate: Sat Aug 6 14:05:23 2016 +0200 Commit: Brad King CommitDate: Mon Aug 8 11:49:16 2016 -0400 QtAutogen: Use std:: instead of ::std:: diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 174760f..ea8db71 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -1183,7 +1183,7 @@ bool cmQtAutoGenerators::GenerateUi(const std::string& realName, cmsys::SystemTools::MakeDirectory(this->Builddir.c_str()); } - const ::std::string uiBuildFile = this->Builddir + uiOutputFile; + const std::string uiBuildFile = this->Builddir + uiOutputFile; int sourceNewerThanUi = 0; bool success = cmsys::SystemTools::FileTimeCompare(uiInputFile, uiBuildFile, @@ -1299,7 +1299,7 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, { const std::string basename = cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); - const ::std::string qrcBuildFile = this->Builddir + qrcOutputFile; + const std::string qrcBuildFile = this->Builddir + qrcOutputFile; int sourceNewerThanQrc = 0; bool generateQrc = !cmsys::SystemTools::FileTimeCompare( https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ecb6df52a1137c6e176e54263ea1b6f9a0848a31 commit ecb6df52a1137c6e176e54263ea1b6f9a0848a31 Author: Sebastian Holtermann AuthorDate: Sat Aug 6 13:09:59 2016 +0200 Commit: Brad King CommitDate: Mon Aug 8 11:48:52 2016 -0400 cmFilePathUuid: Add class to generate deterministic unique file names The class generates a semi-unique (checksum based) pathless file name from a full source file path. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index a790994..cdc8fb1 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -238,6 +238,8 @@ set(SRCS cmFileLockPool.h cmFileLockResult.cxx cmFileLockResult.h + cmFilePathUuid.cxx + cmFilePathUuid.h cmFileTimeComparison.cxx cmFileTimeComparison.h cmFortranLexer.cxx diff --git a/Source/cmFilePathUuid.cxx b/Source/cmFilePathUuid.cxx new file mode 100644 index 0000000..e226cdc --- /dev/null +++ b/Source/cmFilePathUuid.cxx @@ -0,0 +1,156 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2016 Sebastian Holtermann (sebholt at xwmw.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmFilePathUuid.h" + +#include "cmCryptoHash.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" +#include "cmsys/Base64.h" + +cmFilePathUuid::cmFilePathUuid(cmMakefile* makefile) +{ + initParentDirs(makefile->GetCurrentSourceDirectory(), + makefile->GetCurrentBinaryDirectory(), + makefile->GetHomeDirectory(), + makefile->GetHomeOutputDirectory()); +} + +cmFilePathUuid::cmFilePathUuid(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir) +{ + initParentDirs(currentSrcDir, currentBinDir, projectSrcDir, projectBinDir); +} + +void cmFilePathUuid::initParentDirs(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir) +{ + parentDirs[0].first = cmsys::SystemTools::GetRealPath(currentSrcDir); + parentDirs[1].first = cmsys::SystemTools::GetRealPath(currentBinDir); + parentDirs[2].first = cmsys::SystemTools::GetRealPath(projectSrcDir); + parentDirs[3].first = cmsys::SystemTools::GetRealPath(projectBinDir); + + parentDirs[0].second = "CurrentSource"; + parentDirs[1].second = "CurrentBinary"; + parentDirs[2].second = "ProjectSource"; + parentDirs[3].second = "ProjectBinary"; +} + +std::string cmFilePathUuid::get(const std::string& filePath, + const char* outputPrefix, + const char* outputSuffix) +{ + std::string sourceFilename = cmsys::SystemTools::GetFilenameName(filePath); + std::string sourceBasename = + cmsys::SystemTools::GetFilenameWithoutLastExtension(sourceFilename); + + // Acquire checksum string + std::string checksum; + { + std::string sourceRelPath; + std::string sourceRelSeed; + GetRelPathSeed(filePath, sourceRelPath, sourceRelSeed); + checksum = GetChecksumString(sourceFilename, sourceRelPath, sourceRelSeed); + } + + // Compose the file name + std::string uuid; + if (outputPrefix) { + uuid += outputPrefix; + } + uuid += sourceBasename.substr(0, partLengthName); + uuid += "_"; + uuid += checksum.substr(0, partLengthCheckSum); + if (outputSuffix) { + uuid += outputSuffix; + } + return uuid; +} + +void cmFilePathUuid::GetRelPathSeed(const std::string& filePath, + std::string& sourceRelPath, + std::string& sourceRelSeed) +{ + const std::string sourceNameReal = cmsys::SystemTools::GetRealPath(filePath); + std::string parentDirectory; + // Find closest project parent directory + for (size_t ii = 0; ii != numParentDirs; ++ii) { + const std::string& pDir = parentDirs[ii].first; + if (!pDir.empty() && + cmsys::SystemTools::IsSubDirectory(sourceNameReal, pDir)) { + sourceRelSeed = parentDirs[ii].second; + parentDirectory = pDir; + break; + } + } + // Check if the file path is below a known project directory + if (parentDirectory.empty()) { + // Use file syste root as fallback parent directory + sourceRelSeed = "FileSystemRoot"; + cmsys::SystemTools::SplitPathRootComponent(sourceNameReal, + &parentDirectory); + } + sourceRelPath = cmsys::SystemTools::RelativePath( + parentDirectory, cmsys::SystemTools::GetParentDirectory(sourceNameReal)); +} + +std::string cmFilePathUuid::GetChecksumString( + const std::string& sourceFilename, const std::string& sourceRelPath, + const std::string& sourceRelSeed) +{ + // Calculate the file ( seed + relative path + name ) checksum + std::string checksumBase64; + + std::vector hashBytes; + { + // Acquire hash in a hex value string + std::string hexHash = cmCryptoHash::New("SHA256")->HashString( + (sourceRelSeed + sourceRelPath + sourceFilename).c_str()); + // Convert hex value string to bytes + hashBytes.resize(hexHash.size() / 2); + for (unsigned int ii = 0; ii != hashBytes.size(); ++ii) { + unsigned char hbyte[2] = { 0, 0 }; + for (unsigned int jj = 0; jj != 2; ++jj) { + const unsigned char nibble = hexHash[ii * 2 + jj]; + if ('0' <= nibble && nibble <= '9') { + hbyte[jj] = nibble - '0'; + } else if ('a' <= nibble && nibble <= 'f') { + hbyte[jj] = nibble - 'a' + 10; + } else if ('A' <= nibble && nibble <= 'f') { + hbyte[jj] = nibble - 'A' + 10; + } else { + // Unexpected non hex character + std::cerr << "Unexpected non hex character in checksum string"; + exit(-1); + } + } + hashBytes[ii] = hbyte[1] | (hbyte[0] << 4); + } + } + // Convert hash bytes to Base64 text string + { + std::vector base64Bytes(hashBytes.size() * 2, 0); + cmsysBase64_Encode(&hashBytes[0], hashBytes.size(), &base64Bytes[0], 0); + checksumBase64 = reinterpret_cast(&base64Bytes[0]); + // Base64 allows '+' and '/' characters. + // Both are problematic when used in file names. + // Replace them with safer alternatives. + std::replace(checksumBase64.begin(), checksumBase64.end(), '+', '_'); + std::replace(checksumBase64.begin(), checksumBase64.end(), '/', '-'); + } + + return checksumBase64; +} diff --git a/Source/cmFilePathUuid.h b/Source/cmFilePathUuid.h new file mode 100644 index 0000000..42e89b1 --- /dev/null +++ b/Source/cmFilePathUuid.h @@ -0,0 +1,77 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2016 Sebastian Holtermann (sebholt at xwmw.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmFilePathUuid_h +#define cmFilePathUuid_h + +#include "cmStandardIncludes.h" + +#include +#include + +class cmMakefile; + +/** \class cmFilePathUuid + * @brief Generates a unique pathless file name with a checksum component + * calculated from the file path. + * + * The checksum is calculated from the relative file path to the + * closest known project directory. This guarantees reproducibility + * when source and build directory differ e.g. for different project + * build directories. + */ +class cmFilePathUuid +{ +public: + /// Maximum number of characters to use from the file name + static const size_t partLengthName = 14; + /// Maximum number of characters to use from the path checksum + static const size_t partLengthCheckSum = 14; + + /// @brief Initilizes the parent directories from a makefile + cmFilePathUuid(cmMakefile* makefile); + + /// @brief Initilizes the parent directories manually + cmFilePathUuid(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir); + + /* @brief Calculates and returns the uuid for a file path + * + * @arg outputPrefix optional string to prepend to the result + * @arg outputSuffix optional string to append to the result + */ + std::string get(const std::string& filePath, const char* outputPrefix = NULL, + const char* outputSuffix = NULL); + +private: + void initParentDirs(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir); + + /// Returns the relative path and the parent directory key string (seed) + void GetRelPathSeed(const std::string& filePath, std::string& sourceRelPath, + std::string& sourceRelSeed); + + std::string GetChecksumString(const std::string& sourceFilename, + const std::string& sourceRelPath, + const std::string& sourceRelSeed); + + /// Size of the parent directory list + static const size_t numParentDirs = 4; + /// List of (directory name, seed name) pairs + std::pair parentDirs[numParentDirs]; +}; + +#endif ----------------------------------------------------------------------- Summary of changes: Source/CMakeLists.txt | 2 + Source/cmFilePathUuid.cxx | 156 +++++++++++++++++++++++++++++ Source/cmFilePathUuid.h | 77 ++++++++++++++ Source/cmQtAutoGeneratorInitializer.cxx | 76 ++++++++------ Source/cmQtAutoGenerators.cxx | 84 +++++++++++----- Source/cmQtAutoGenerators.h | 6 +- Tests/QtAutogen/CMakeLists.txt | 4 + Tests/QtAutogen/sameName/CMakeLists.txt | 21 ++++ Tests/QtAutogen/sameName/aaa/bbb/data.qrc | 6 ++ Tests/QtAutogen/sameName/aaa/bbb/item.cpp | 10 ++ Tests/QtAutogen/sameName/aaa/bbb/item.hpp | 18 ++++ Tests/QtAutogen/sameName/aaa/data.qrc | 6 ++ Tests/QtAutogen/sameName/aaa/item.cpp | 8 ++ Tests/QtAutogen/sameName/aaa/item.hpp | 16 +++ Tests/QtAutogen/sameName/bbb/aaa/data.qrc | 6 ++ Tests/QtAutogen/sameName/bbb/aaa/item.cpp | 10 ++ Tests/QtAutogen/sameName/bbb/aaa/item.hpp | 18 ++++ Tests/QtAutogen/sameName/bbb/data.qrc | 6 ++ Tests/QtAutogen/sameName/bbb/item.cpp | 8 ++ Tests/QtAutogen/sameName/bbb/item.hpp | 16 +++ Tests/QtAutogen/sameName/ccc/data.qrc | 6 ++ Tests/QtAutogen/sameName/ccc/item.cpp | 23 +++++ Tests/QtAutogen/sameName/ccc/item.hpp | 16 +++ Tests/QtAutogen/sameName/data.qrc | 5 + Tests/QtAutogen/sameName/item.cpp | 5 + Tests/QtAutogen/sameName/item.hpp | 13 +++ Tests/QtAutogen/sameName/main.cpp | 16 +++ 27 files changed, 577 insertions(+), 61 deletions(-) create mode 100644 Source/cmFilePathUuid.cxx create mode 100644 Source/cmFilePathUuid.h create mode 100644 Tests/QtAutogen/sameName/CMakeLists.txt create mode 100644 Tests/QtAutogen/sameName/aaa/bbb/data.qrc create mode 100644 Tests/QtAutogen/sameName/aaa/bbb/item.cpp create mode 100644 Tests/QtAutogen/sameName/aaa/bbb/item.hpp create mode 100644 Tests/QtAutogen/sameName/aaa/data.qrc create mode 100644 Tests/QtAutogen/sameName/aaa/item.cpp create mode 100644 Tests/QtAutogen/sameName/aaa/item.hpp create mode 100644 Tests/QtAutogen/sameName/bbb/aaa/data.qrc create mode 100644 Tests/QtAutogen/sameName/bbb/aaa/item.cpp create mode 100644 Tests/QtAutogen/sameName/bbb/aaa/item.hpp create mode 100644 Tests/QtAutogen/sameName/bbb/data.qrc create mode 100644 Tests/QtAutogen/sameName/bbb/item.cpp create mode 100644 Tests/QtAutogen/sameName/bbb/item.hpp create mode 100644 Tests/QtAutogen/sameName/ccc/data.qrc create mode 100644 Tests/QtAutogen/sameName/ccc/item.cpp create mode 100644 Tests/QtAutogen/sameName/ccc/item.hpp create mode 100644 Tests/QtAutogen/sameName/data.qrc create mode 100644 Tests/QtAutogen/sameName/item.cpp create mode 100644 Tests/QtAutogen/sameName/item.hpp create mode 100644 Tests/QtAutogen/sameName/main.cpp hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 8 14:02:30 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 8 Aug 2016 14:02:30 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1167-g3e16d88 Message-ID: <20160808180230.63670F52C2@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 3e16d885e07a30f644ebc4cf2397bcc1ab0a635a (commit) via 955c2a630aae9b925b468e98e7c323384d943cb0 (commit) from e10f5fc665ea07d533a9fcd3ee6f519a650491f0 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3e16d885e07a30f644ebc4cf2397bcc1ab0a635a commit 3e16d885e07a30f644ebc4cf2397bcc1ab0a635a Merge: e10f5fc 955c2a6 Author: Brad King AuthorDate: Mon Aug 8 14:02:29 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 8 14:02:29 2016 -0400 Merge topic 'ninja-full-path' into next 955c2a63 Ninja: Use full path for all source files https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=955c2a630aae9b925b468e98e7c323384d943cb0 commit 955c2a630aae9b925b468e98e7c323384d943cb0 Author: Chaoren Lin AuthorDate: Fri Aug 5 16:51:56 2016 -0700 Commit: Brad King CommitDate: Mon Aug 8 13:55:29 2016 -0400 Ninja: Use full path for all source files This is consistent with the behavior of the Makefile generators. Relative paths are difficult for an IDE to parse the output of a build error. diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 855a243..1466f8a 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -305,7 +305,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) vars.RuleLauncher = "RULE_LAUNCH_COMPILE"; vars.CMTarget = this->GetGeneratorTarget(); vars.Language = lang.c_str(); - vars.Source = "$in"; + vars.Source = "$IN_ABS"; vars.Object = "$out"; vars.Defines = "$DEFINES"; vars.Includes = "$INCLUDES"; @@ -529,8 +529,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( cmSourceFile const* source, bool writeOrderDependsTargetForTarget) { std::string const language = source->GetLanguage(); - std::string const sourceFileName = - language == "RC" ? source->GetFullPath() : this->GetSourceFilePath(source); + std::string const sourceFileName = this->GetSourceFilePath(source); std::string const objectDir = this->ConvertToNinjaPath(this->GeneratorTarget->GetSupportDirectory()); std::string const objectFileName = @@ -539,6 +538,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( cmSystemTools::GetFilenamePath(objectFileName); cmNinjaVars vars; + vars["IN_ABS"] = this->GetLocalGenerator()->ConvertToOutputFormat( + source->GetFullPath(), cmOutputConverter::SHELL); vars["FLAGS"] = this->ComputeFlagsForObject(source, language); vars["DEFINES"] = this->ComputeDefines(source, language); vars["INCLUDES"] = this->GetIncludes(language); ----------------------------------------------------------------------- Summary of changes: Source/cmNinjaTargetGenerator.cxx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 8 14:08:57 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 8 Aug 2016 14:08:57 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1169-gc758d6a Message-ID: <20160808180857.CF7E5F539C@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via c758d6a57f6f8ee85be063b12123560fa4d174c3 (commit) via 5f3c8f6ab2c6633bdbfc083b9e96b477c1700c80 (commit) from 3e16d885e07a30f644ebc4cf2397bcc1ab0a635a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c758d6a57f6f8ee85be063b12123560fa4d174c3 commit c758d6a57f6f8ee85be063b12123560fa4d174c3 Merge: 3e16d88 5f3c8f6 Author: Brad King AuthorDate: Mon Aug 8 14:08:57 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 8 14:08:57 2016 -0400 Merge topic 'GetPrerequisites-grep-a' into next 5f3c8f6a GetPrerequisites: Always filter objdump output as text https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5f3c8f6ab2c6633bdbfc083b9e96b477c1700c80 commit 5f3c8f6ab2c6633bdbfc083b9e96b477c1700c80 Author: Alexander Shishenko AuthorDate: Sat Aug 6 17:32:44 2016 +0300 Commit: Brad King CommitDate: Mon Aug 8 14:05:21 2016 -0400 GetPrerequisites: Always filter objdump output as text When using `grep` to filter the output, add the `-a` flag to tell it never to treat the output as binary. Otherwise when LANG != C in the environment the non-ascii text may break the filter. diff --git a/Modules/GetPrerequisites.cmake b/Modules/GetPrerequisites.cmake index 322cbd3..2881e7f 100644 --- a/Modules/GetPrerequisites.cmake +++ b/Modules/GetPrerequisites.cmake @@ -753,7 +753,7 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa find_program(gp_grep_cmd grep) endif() if(gp_grep_cmd) - set(gp_cmd_maybe_filter COMMAND ${gp_grep_cmd} "^[[:blank:]]*DLL Name: ") + set(gp_cmd_maybe_filter COMMAND ${gp_grep_cmd} "-a" "^[[:blank:]]*DLL Name: ") endif() else() message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...") ----------------------------------------------------------------------- Summary of changes: Modules/GetPrerequisites.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From daniel at pfeifer-mail.de Mon Aug 8 15:51:28 2016 From: daniel at pfeifer-mail.de (Daniel Pfeifer) Date: Mon, 8 Aug 2016 15:51:28 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1172-gd20a973 Message-ID: <20160808195128.5A887F4B7C@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via d20a9735cddbdceda3ee3122711feaab7cb74818 (commit) via 551b4c90626357ee9b6048e89c7406f3b4063fbb (commit) via 3a7be4f3943e160b1c0c144d914d3dd2ba42819e (commit) from c758d6a57f6f8ee85be063b12123560fa4d174c3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d20a9735cddbdceda3ee3122711feaab7cb74818 commit d20a9735cddbdceda3ee3122711feaab7cb74818 Merge: c758d6a 551b4c9 Author: Daniel Pfeifer AuthorDate: Mon Aug 8 15:51:26 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 8 15:51:26 2016 -0400 Merge topic 'fix-string-append' into next 551b4c90 Revert the use of string(APPEND) in .cmake.in files 3a7be4f3 prefer list(APPEND) over string(APPEND) where appropriate https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=551b4c90626357ee9b6048e89c7406f3b4063fbb commit 551b4c90626357ee9b6048e89c7406f3b4063fbb Author: Daniel Pfeifer AuthorDate: Mon Aug 8 21:45:41 2016 +0200 Commit: Daniel Pfeifer CommitDate: Mon Aug 8 21:45:41 2016 +0200 Revert the use of string(APPEND) in .cmake.in files The generated files may be consumed by older cmake versions which do not support string(APPEND). diff --git a/Modules/BasicConfigVersion-AnyNewerVersion.cmake.in b/Modules/BasicConfigVersion-AnyNewerVersion.cmake.in index 3e8c511..bc78016 100644 --- a/Modules/BasicConfigVersion-AnyNewerVersion.cmake.in +++ b/Modules/BasicConfigVersion-AnyNewerVersion.cmake.in @@ -26,6 +26,6 @@ endif() # check that the installed version has the same 32/64bit-ness as the one which is currently searching: if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "@CMAKE_SIZEOF_VOID_P@") math(EXPR installedBits "@CMAKE_SIZEOF_VOID_P@ * 8") - string(APPEND PACKAGE_VERSION " (${installedBits}bit)") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") set(PACKAGE_VERSION_UNSUITABLE TRUE) endif() diff --git a/Modules/BasicConfigVersion-ExactVersion.cmake.in b/Modules/BasicConfigVersion-ExactVersion.cmake.in index 5741007..de4a23a 100644 --- a/Modules/BasicConfigVersion-ExactVersion.cmake.in +++ b/Modules/BasicConfigVersion-ExactVersion.cmake.in @@ -42,6 +42,6 @@ endif() # check that the installed version has the same 32/64bit-ness as the one which is currently searching: if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "@CMAKE_SIZEOF_VOID_P@") math(EXPR installedBits "@CMAKE_SIZEOF_VOID_P@ * 8") - string(APPEND PACKAGE_VERSION " (${installedBits}bit)") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") set(PACKAGE_VERSION_UNSUITABLE TRUE) endif() diff --git a/Modules/BasicConfigVersion-SameMajorVersion.cmake.in b/Modules/BasicConfigVersion-SameMajorVersion.cmake.in index 0fad8a3..a32245d 100644 --- a/Modules/BasicConfigVersion-SameMajorVersion.cmake.in +++ b/Modules/BasicConfigVersion-SameMajorVersion.cmake.in @@ -41,6 +41,6 @@ endif() # check that the installed version has the same 32/64bit-ness as the one which is currently searching: if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "@CMAKE_SIZEOF_VOID_P@") math(EXPR installedBits "@CMAKE_SIZEOF_VOID_P@ * 8") - string(APPEND PACKAGE_VERSION " (${installedBits}bit)") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") set(PACKAGE_VERSION_UNSUITABLE TRUE) endif() https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3a7be4f3943e160b1c0c144d914d3dd2ba42819e commit 3a7be4f3943e160b1c0c144d914d3dd2ba42819e Author: Daniel Pfeifer AuthorDate: Mon Aug 8 21:25:41 2016 +0200 Commit: Daniel Pfeifer CommitDate: Mon Aug 8 21:28:52 2016 +0200 prefer list(APPEND) over string(APPEND) where appropriate diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index 44bf957..fc01976 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -1133,7 +1133,7 @@ function(_ep_command_line_to_initial_cache var args force) endif() else() # Assume this is a list to append to the last var - string(APPEND accumulator ";${line}") + list(APPEND accumulator "${line}") endif() endforeach() # Catch the final line of the args diff --git a/Modules/FindQt4.cmake b/Modules/FindQt4.cmake index bf41ea1..7c41b99 100644 --- a/Modules/FindQt4.cmake +++ b/Modules/FindQt4.cmake @@ -764,7 +764,7 @@ if (QT_QMAKE_EXECUTABLE AND ############################################# cmake_push_check_state() # Add QT_INCLUDE_DIR to CMAKE_REQUIRED_INCLUDES - string(APPEND CMAKE_REQUIRED_INCLUDES ";${QT_INCLUDE_DIR}") + list(APPEND CMAKE_REQUIRED_INCLUDES "${QT_INCLUDE_DIR}") set(CMAKE_REQUIRED_QUIET ${Qt4_FIND_QUIETLY}) # Check for Window system symbols (note: only one should end up being set) CHECK_CXX_SYMBOL_EXISTS(Q_WS_X11 "QtCore/qglobal.h" Q_WS_X11) diff --git a/Tests/RunCMake/CPack/VerifyResult.cmake b/Tests/RunCMake/CPack/VerifyResult.cmake index 8047668..074890f 100644 --- a/Tests/RunCMake/CPack/VerifyResult.cmake +++ b/Tests/RunCMake/CPack/VerifyResult.cmake @@ -16,7 +16,7 @@ include("${src_dir}/${GENERATOR_TYPE}/${RunCMake_TEST}-ExpectedFiles.cmake") if(NOT EXPECTED_FILES_COUNT EQUAL 0) foreach(file_no_ RANGE 1 ${EXPECTED_FILES_COUNT}) file(GLOB FOUND_FILE_${file_no_} RELATIVE "${bin_dir}" "${EXPECTED_FILE_${file_no_}}") - string(APPEND foundFiles_ ";${FOUND_FILE_${file_no_}}") + list(APPEND foundFiles_ "${FOUND_FILE_${file_no_}}") list(LENGTH FOUND_FILE_${file_no_} foundFilesCount_) if(foundFilesCount_ EQUAL 1) @@ -45,7 +45,7 @@ if(NOT EXPECTED_FILES_COUNT EQUAL 0) # check that there were no extra files generated foreach(all_files_glob_ IN LISTS ALL_FILES_GLOB) file(GLOB foundAll_ RELATIVE "${bin_dir}" "${all_files_glob_}") - string(APPEND allFoundFiles_ ";${foundAll_}") + list(APPEND allFoundFiles_ "${foundAll_}") endforeach() list(LENGTH foundFiles_ foundFilesCount_) diff --git a/Tests/SimpleInstall/CMakeLists.txt b/Tests/SimpleInstall/CMakeLists.txt index 5a1392b..4cf7355 100644 --- a/Tests/SimpleInstall/CMakeLists.txt +++ b/Tests/SimpleInstall/CMakeLists.txt @@ -348,7 +348,7 @@ if(UNIX AND NOT APPLE) # if(NOT SKIP_TZ) # message("compress found and it was not a script") # message("output from file command: [${output}]") - # string(APPEND CPACK_GENERATOR ";TZ") + # list(APPEND CPACK_GENERATOR "TZ") # else() # message("compress found, but it was a script so dont use it") # message("output from file command: [${output}]") @@ -357,7 +357,7 @@ if(UNIX AND NOT APPLE) find_program(found_bz2 NAMES bzip2) if(found_bz2) - string(APPEND CPACK_GENERATOR ";TBZ2") + list(APPEND CPACK_GENERATOR "TBZ2") endif() endif() diff --git a/Tests/SimpleInstallS2/CMakeLists.txt b/Tests/SimpleInstallS2/CMakeLists.txt index 5a1392b..4cf7355 100644 --- a/Tests/SimpleInstallS2/CMakeLists.txt +++ b/Tests/SimpleInstallS2/CMakeLists.txt @@ -348,7 +348,7 @@ if(UNIX AND NOT APPLE) # if(NOT SKIP_TZ) # message("compress found and it was not a script") # message("output from file command: [${output}]") - # string(APPEND CPACK_GENERATOR ";TZ") + # list(APPEND CPACK_GENERATOR "TZ") # else() # message("compress found, but it was a script so dont use it") # message("output from file command: [${output}]") @@ -357,7 +357,7 @@ if(UNIX AND NOT APPLE) find_program(found_bz2 NAMES bzip2) if(found_bz2) - string(APPEND CPACK_GENERATOR ";TBZ2") + list(APPEND CPACK_GENERATOR "TBZ2") endif() endif() ----------------------------------------------------------------------- Summary of changes: Modules/BasicConfigVersion-AnyNewerVersion.cmake.in | 2 +- Modules/BasicConfigVersion-ExactVersion.cmake.in | 2 +- Modules/BasicConfigVersion-SameMajorVersion.cmake.in | 2 +- Modules/ExternalProject.cmake | 2 +- Modules/FindQt4.cmake | 2 +- Tests/RunCMake/CPack/VerifyResult.cmake | 4 ++-- Tests/SimpleInstall/CMakeLists.txt | 4 ++-- Tests/SimpleInstallS2/CMakeLists.txt | 4 ++-- 8 files changed, 11 insertions(+), 11 deletions(-) hooks/post-receive -- CMake From kwrobot at kitware.com Tue Aug 9 00:01:08 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Tue, 9 Aug 2016 00:01:08 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-584-g982b4cd Message-ID: <20160809040108.B5946F51E2@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 982b4cd602fc125c9d2165145100d5e574644bf9 (commit) from ee9d4feb67f01686c270d3db584dfccaefd14b47 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=982b4cd602fc125c9d2165145100d5e574644bf9 commit 982b4cd602fc125c9d2165145100d5e574644bf9 Author: Kitware Robot AuthorDate: Tue Aug 9 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Tue Aug 9 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 8af6031..55a9958 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160808) +set(CMake_VERSION_PATCH 20160809) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From chuck.atkins at kitware.com Tue Aug 9 08:00:12 2016 From: chuck.atkins at kitware.com (Chuck Atkins) Date: Tue, 9 Aug 2016 08:00:12 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1174-gd8a2506 Message-ID: <20160809120012.77CD9F581E@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via d8a2506da003e45b84c1f8e09960b60037be7434 (commit) via 970eaed46afef12f003b51bdb51f5abf62214b19 (commit) from d20a9735cddbdceda3ee3122711feaab7cb74818 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d8a2506da003e45b84c1f8e09960b60037be7434 commit d8a2506da003e45b84c1f8e09960b60037be7434 Merge: d20a973 970eaed Author: Chuck Atkins AuthorDate: Tue Aug 9 08:00:11 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 9 08:00:11 2016 -0400 Merge topic 'add-extra-boolean-comparisons' into next 970eaed4 Fix documentation warning https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=970eaed46afef12f003b51bdb51f5abf62214b19 commit 970eaed46afef12f003b51bdb51f5abf62214b19 Author: Chuck Atkins AuthorDate: Tue Aug 9 07:59:28 2016 -0400 Commit: Chuck Atkins CommitDate: Tue Aug 9 07:59:28 2016 -0400 Fix documentation warning diff --git a/Help/release/dev/add-extra-boolean-comparisons.rst b/Help/release/dev/add-extra-boolean-comparisons.rst index 6a1db01..a69b212 100644 --- a/Help/release/dev/add-extra-boolean-comparisons.rst +++ b/Help/release/dev/add-extra-boolean-comparisons.rst @@ -1,5 +1,5 @@ add-extra-boolean-comparisons ----------------------------- -* Add LESS_EQUAL, GREATER_EQUAL, and thier associated STR and VERSION_ +* Add LESS_EQUAL, GREATER_EQUAL, and thier associated STR and VERSION equivalents to use the combined <= and >= functionality. ----------------------------------------------------------------------- Summary of changes: Help/release/dev/add-extra-boolean-comparisons.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From chuck.atkins at kitware.com Tue Aug 9 08:01:15 2016 From: chuck.atkins at kitware.com (Chuck Atkins) Date: Tue, 9 Aug 2016 08:01:15 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1176-gc9477b6 Message-ID: <20160809120115.9367DF5844@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via c9477b66889974bf27c435ef951435a557bfd1b7 (commit) via 55e72872796d6649b17edf4dbca2d2641274c5c4 (commit) from d8a2506da003e45b84c1f8e09960b60037be7434 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c9477b66889974bf27c435ef951435a557bfd1b7 commit c9477b66889974bf27c435ef951435a557bfd1b7 Merge: d8a2506 55e7287 Author: Chuck Atkins AuthorDate: Tue Aug 9 08:01:14 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 9 08:01:14 2016 -0400 Merge topic 'add-extra-boolean-comparisons' into next 55e72872 Add additional <= and >= comparison operators https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=55e72872796d6649b17edf4dbca2d2641274c5c4 commit 55e72872796d6649b17edf4dbca2d2641274c5c4 Author: Chuck Atkins AuthorDate: Fri Aug 5 14:11:46 2016 -0400 Commit: Chuck Atkins CommitDate: Tue Aug 9 08:00:25 2016 -0400 Add additional <= and >= comparison operators This adds the LESS_EQUAL, GREATER_EQUAL, and associated STR and VERSION equivalents to use the combined <= and >= functionality. diff --git a/Help/command/if.rst b/Help/command/if.rst index 56e618c..0941029 100644 --- a/Help/command/if.rst +++ b/Help/command/if.rst @@ -30,10 +30,12 @@ else and endif clause is optional. Long expressions can be used and there is a traditional order of precedence. Parenthetical expressions are evaluated first followed by unary tests such as ``EXISTS``, ``COMMAND``, and ``DEFINED``. Then any binary tests such as -``EQUAL``, ``LESS``, ``GREATER``, ``STRLESS``, ``STRGREATER``, -``STREQUAL``, and ``MATCHES`` will be evaluated. Then boolean ``NOT`` -operators and finally boolean ``AND`` and then ``OR`` operators will -be evaluated. +``EQUAL``, ``LESS``, ``LESS_EQUAL, ``GREATER``, ``GREATER_EQUAL``, +``STREQUAL``, ``STRLESS``, ``STRLESS_EQUAL``, ``STRGREATER``, +``STRGREATER_EQUAL``, ``VERSION_EQUAL``, ``VERSION_LESS``, +``VERSION_LESS_EQUAL``, ``VERSION_GREATER``, ``VERSION_GREATER_EQUAL``, +and ``MATCHES`` will be evaluated. Then boolean ``NOT`` operators and +finally boolean ``AND`` and then ``OR`` operators will be evaluated. Possible expressions are: @@ -115,6 +117,14 @@ Possible expressions are: True if the given string or variable's value is a valid number and equal to that on the right. +``if( LESS_EQUAL )`` + True if the given string or variable's value is a valid number and less + than or equal to that on the right. + +``if( GREATER_EQUAL )`` + True if the given string or variable's value is a valid number and greater + than or equal to that on the right. + ``if( STRLESS )`` True if the given string or variable's value is lexicographically less than the string or variable on the right. @@ -127,15 +137,31 @@ Possible expressions are: True if the given string or variable's value is lexicographically equal to the string or variable on the right. +``if( STRLESS_EQUAL )`` + True if the given string or variable's value is lexicographically less + than or equal to the string or variable on the right. + +``if( STRGREATER_EQUAL )`` + True if the given string or variable's value is lexicographically greater + than or equal to the string or variable on the right. + ``if( VERSION_LESS )`` Component-wise integer version number comparison (version format is ``major[.minor[.patch[.tweak]]]``). +``if( VERSION_GREATER )`` + Component-wise integer version number comparison (version format is + ``major[.minor[.patch[.tweak]]]``). + ``if( VERSION_EQUAL )`` Component-wise integer version number comparison (version format is ``major[.minor[.patch[.tweak]]]``). -``if( VERSION_GREATER )`` +``if( VERSION_LESS_EQUAL )`` + Component-wise integer version number comparison (version format is + ``major[.minor[.patch[.tweak]]]``). + +``if( VERSION_GREATER_EQUAL )`` Component-wise integer version number comparison (version format is ``major[.minor[.patch[.tweak]]]``). @@ -186,20 +212,21 @@ above-documented signature accepts ````: * If the left hand argument to ``MATCHES`` is missing it returns false without error -* Both left and right hand arguments to ``LESS``, ``GREATER``, and - ``EQUAL`` are independently tested to see if they are defined - variables, if so their defined values are used otherwise the original - value is used. +* Both left and right hand arguments to ``LESS``, ``GREATER``, ``EQUAL``, + ``LESS_EQUAL``, and ``GREATER_EQUAL``, are independently tested to see if + they are defined variables, if so their defined values are used otherwise + the original value is used. -* Both left and right hand arguments to ``STRLESS``, ``STREQUAL``, and - ``STRGREATER`` are independently tested to see if they are defined - variables, if so their defined values are used otherwise the original - value is used. +* Both left and right hand arguments to ``STRLESS``, ``STRGREATER``, + ``STREQUAL``, ``STRLESS_EQUAL``, and ``STRGREATER_EQUAL`` are independently + tested to see if they are defined variables, if so their defined values are + used otherwise the original value is used. * Both left and right hand arguments to ``VERSION_LESS``, - ``VERSION_EQUAL``, and ``VERSION_GREATER`` are independently tested - to see if they are defined variables, if so their defined values are - used otherwise the original value is used. + ``VERSION_GREATER``, ``VERSION_EQUAL``, ``VERSION_LESS_EQUAL``, and + ``VERSION_GREATER_EQUAL`` are independently tested to see if they are defined + variables, if so their defined values are used otherwise the original value + is used. * The right hand argument to ``NOT`` is tested to see if it is a boolean constant, if so the value is used, otherwise it is assumed to be a diff --git a/Help/command/string.rst b/Help/command/string.rst index 3f4050e..19a095a 100644 --- a/Help/command/string.rst +++ b/Help/command/string.rst @@ -197,10 +197,12 @@ Comparison :: - string(COMPARE EQUAL ) - string(COMPARE NOTEQUAL ) string(COMPARE LESS ) string(COMPARE GREATER ) + string(COMPARE EQUAL ) + string(COMPARE NOTEQUAL ) + string(COMPARE LESS_EQUAL ) + string(COMPARE GREATER_EQUAL ) Compare the strings and store true or false in the output variable. diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index d4f47dd..64d15a9 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -66,12 +66,16 @@ Available logical expressions are: ``1`` if the CMake-id of the C compiler matches ``comp``, otherwise ``0``. ``$`` ``1`` if the CMake-id of the CXX compiler matches ``comp``, otherwise ``0``. -``$`` - ``1`` if ``v1`` is a version greater than ``v2``, else ``0``. ``$`` ``1`` if ``v1`` is a version less than ``v2``, else ``0``. +``$`` + ``1`` if ``v1`` is a version greater than ``v2``, else ``0``. ``$`` ``1`` if ``v1`` is the same version as ``v2``, else ``0``. +``$`` + ``1`` if ``v1`` is a version less than or equal to ``v2``, else ``0``. +``$`` + ``1`` if ``v1`` is a version greater than or equal to ``v2``, else ``0``. ``$`` ``1`` if the version of the C compiler matches ``ver``, otherwise ``0``. ``$`` diff --git a/Help/release/dev/add-extra-boolean-comparisons.rst b/Help/release/dev/add-extra-boolean-comparisons.rst new file mode 100644 index 0000000..a69b212 --- /dev/null +++ b/Help/release/dev/add-extra-boolean-comparisons.rst @@ -0,0 +1,5 @@ +add-extra-boolean-comparisons +----------------------------- + +* Add LESS_EQUAL, GREATER_EQUAL, and thier associated STR and VERSION + equivalents to use the combined <= and >= functionality. diff --git a/Help/variable/CMAKE_VERSION.rst b/Help/variable/CMAKE_VERSION.rst index bbb1d91..872e2fa 100644 --- a/Help/variable/CMAKE_VERSION.rst +++ b/Help/variable/CMAKE_VERSION.rst @@ -26,11 +26,11 @@ Individual component values are also available in variables: * :variable:`CMAKE_PATCH_VERSION` * :variable:`CMAKE_TWEAK_VERSION` -Use the :command:`if` command ``VERSION_LESS``, ``VERSION_EQUAL``, or -``VERSION_GREATER`` operators to compare version string values against -``CMAKE_VERSION`` using a component-wise test. Version component -values may be 10 or larger so do not attempt to compare version -strings as floating-point numbers. +Use the :command:`if` command ``VERSION_LESS``, ``VERSION_GREATER``, +``VERSION_EQUAL``, ``VERSION_LESS_EQUAL``, or ``VERSION_GREATER_EQUAL`` +operators to compare version string values against ``CMAKE_VERSION`` using a +component-wise test. Version component values may be 10 or larger so do not +attempt to compare version strings as floating-point numbers. .. note:: diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 0101049..141a00e 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -367,10 +367,8 @@ bool cmCTest::ShouldCompressTestOutput() std::string cdashVersion = this->GetCDashVersion(); // version >= 1.6? bool cdashSupportsGzip = - cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, - cdashVersion.c_str(), "1.6") || - cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, - cdashVersion.c_str(), "1.6"); + cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, + cdashVersion.c_str(), "1.6"); this->CompressTestOutput &= cdashSupportsGzip; this->ComputedCompressTestOutput = true; } diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index e02221c..d7532b3 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -21,12 +21,14 @@ static std::string const keyDEFINED = "DEFINED"; static std::string const keyEQUAL = "EQUAL"; static std::string const keyEXISTS = "EXISTS"; static std::string const keyGREATER = "GREATER"; +static std::string const keyGREATER_EQUAL = "GREATER_EQUAL"; static std::string const keyIN_LIST = "IN_LIST"; static std::string const keyIS_ABSOLUTE = "IS_ABSOLUTE"; static std::string const keyIS_DIRECTORY = "IS_DIRECTORY"; static std::string const keyIS_NEWER_THAN = "IS_NEWER_THAN"; static std::string const keyIS_SYMLINK = "IS_SYMLINK"; static std::string const keyLESS = "LESS"; +static std::string const keyLESS_EQUAL = "LESS_EQUAL"; static std::string const keyMATCHES = "MATCHES"; static std::string const keyNOT = "NOT"; static std::string const keyOR = "OR"; @@ -35,12 +37,16 @@ static std::string const keyParenR = ")"; static std::string const keyPOLICY = "POLICY"; static std::string const keySTREQUAL = "STREQUAL"; static std::string const keySTRGREATER = "STRGREATER"; +static std::string const keySTRGREATER_EQUAL = "STRGREATER_EQUAL"; static std::string const keySTRLESS = "STRLESS"; +static std::string const keySTRLESS_EQUAL = "STRLESS_EQUAL"; static std::string const keyTARGET = "TARGET"; static std::string const keyTEST = "TEST"; static std::string const keyVERSION_EQUAL = "VERSION_EQUAL"; static std::string const keyVERSION_GREATER = "VERSION_GREATER"; +static std::string const keyVERSION_GREATER_EQUAL = "VERSION_GREATER_EQUAL"; static std::string const keyVERSION_LESS = "VERSION_LESS"; +static std::string const keyVERSION_LESS_EQUAL = "VERSION_LESS_EQUAL"; cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile, const cmListFileContext& context, @@ -559,7 +565,9 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, if (argP1 != newArgs.end() && argP2 != newArgs.end() && (this->IsKeyword(keyLESS, *argP1) || + this->IsKeyword(keyLESS_EQUAL, *argP1) || this->IsKeyword(keyGREATER, *argP1) || + this->IsKeyword(keyGREATER_EQUAL, *argP1) || this->IsKeyword(keyEQUAL, *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); @@ -570,8 +578,12 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, result = false; } else if (*(argP1) == keyLESS) { result = (lhs < rhs); + } else if (*(argP1) == keyLESS_EQUAL) { + result = (lhs <= rhs); } else if (*(argP1) == keyGREATER) { result = (lhs > rhs); + } else if (*(argP1) == keyGREATER_EQUAL) { + result = (lhs >= rhs); } else { result = (lhs == rhs); } @@ -580,16 +592,22 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, if (argP1 != newArgs.end() && argP2 != newArgs.end() && (this->IsKeyword(keySTRLESS, *argP1) || - this->IsKeyword(keySTREQUAL, *argP1) || - this->IsKeyword(keySTRGREATER, *argP1))) { + this->IsKeyword(keySTRLESS_EQUAL, *argP1) || + this->IsKeyword(keySTRGREATER, *argP1) || + this->IsKeyword(keySTRGREATER_EQUAL, *argP1) || + this->IsKeyword(keySTREQUAL, *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); int val = strcmp(def, def2); bool result; if (*(argP1) == keySTRLESS) { result = (val < 0); + } else if (*(argP1) == keySTRLESS_EQUAL) { + result = (val <= 0); } else if (*(argP1) == keySTRGREATER) { result = (val > 0); + } else if (*(argP1) == keySTRGREATER_EQUAL) { + result = (val >= 0); } else // strequal { result = (val == 0); @@ -599,15 +617,23 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, if (argP1 != newArgs.end() && argP2 != newArgs.end() && (this->IsKeyword(keyVERSION_LESS, *argP1) || + this->IsKeyword(keyVERSION_LESS_EQUAL, *argP1) || this->IsKeyword(keyVERSION_GREATER, *argP1) || + this->IsKeyword(keyVERSION_GREATER_EQUAL, *argP1) || this->IsKeyword(keyVERSION_EQUAL, *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); - cmSystemTools::CompareOp op = cmSystemTools::OP_EQUAL; + cmSystemTools::CompareOp op; if (*argP1 == keyVERSION_LESS) { op = cmSystemTools::OP_LESS; + } else if (*argP1 == keyVERSION_LESS_EQUAL) { + op = cmSystemTools::OP_LESS_EQUAL; } else if (*argP1 == keyVERSION_GREATER) { op = cmSystemTools::OP_GREATER; + } else if (*argP1 == keyVERSION_GREATER_EQUAL) { + op = cmSystemTools::OP_GREATER_EQUAL; + } else { // version_equal + op = cmSystemTools::OP_EQUAL; } bool result = cmSystemTools::VersionCompare(op, def, def2); this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2); diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index ca7250b..6e2b16a 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -545,6 +545,25 @@ static const struct VersionGreaterNode : public cmGeneratorExpressionNode } } versionGreaterNode; +static const struct VersionGreaterEqNode : public cmGeneratorExpressionNode +{ + VersionGreaterEqNode() {} + + int NumExpectedParameters() const CM_OVERRIDE { return 2; } + + std::string Evaluate(const std::vector& parameters, + cmGeneratorExpressionContext*, + const GeneratorExpressionContent*, + cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + { + return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, + parameters.front().c_str(), + parameters[1].c_str()) + ? "1" + : "0"; + } +} versionGreaterEqNode; + static const struct VersionLessNode : public cmGeneratorExpressionNode { VersionLessNode() {} @@ -564,6 +583,25 @@ static const struct VersionLessNode : public cmGeneratorExpressionNode } } versionLessNode; +static const struct VersionLessEqNode : public cmGeneratorExpressionNode +{ + VersionLessEqNode() {} + + int NumExpectedParameters() const CM_OVERRIDE { return 2; } + + std::string Evaluate(const std::vector& parameters, + cmGeneratorExpressionContext*, + const GeneratorExpressionContent*, + cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + { + return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS_EQUAL, + parameters.front().c_str(), + parameters[1].c_str()) + ? "1" + : "0"; + } +} versionLessEqNode; + static const struct VersionEqualNode : public cmGeneratorExpressionNode { VersionEqualNode() {} @@ -1641,7 +1679,9 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( nodeMap["C_COMPILER_ID"] = &cCompilerIdNode; nodeMap["CXX_COMPILER_ID"] = &cxxCompilerIdNode; nodeMap["VERSION_GREATER"] = &versionGreaterNode; + nodeMap["VERSION_GREATER_EQUAL"] = &versionGreaterEqNode; nodeMap["VERSION_LESS"] = &versionLessNode; + nodeMap["VERSION_LESS_EQUAL"] = &versionLessEqNode; nodeMap["VERSION_EQUAL"] = &versionEqualNode; nodeMap["C_COMPILER_VERSION"] = &cCompilerVersionNode; nodeMap["CXX_COMPILER_VERSION"] = &cxxCompilerVersionNode; diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index dce4687..705fc7d 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -484,8 +484,9 @@ bool cmStringCommand::HandleCompareCommand( return false; } std::string mode = args[1]; - if ((mode == "EQUAL") || (mode == "NOTEQUAL") || (mode == "LESS") || - (mode == "GREATER")) { + if ((mode == "EQUAL") || (mode == "NOTEQUAL") || + (mode == "LESS") || (mode == "LESS_EQUAL") || + (mode == "GREATER") || (mode == "GREATER_EQUAL")) { if (args.size() < 5) { std::string e = "sub-command COMPARE, mode "; e += mode; @@ -500,8 +501,12 @@ bool cmStringCommand::HandleCompareCommand( bool result; if (mode == "LESS") { result = (left < right); + } else if (mode == "LESS_EQUAL") { + result = (left <= right); } else if (mode == "GREATER") { result = (left > right); + } else if (mode == "GREATER_EQUAL") { + result = (left >= right); } else if (mode == "EQUAL") { result = (left == right); } else // if(mode == "NOTEQUAL") diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 9740ef7..5745a01 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -2380,10 +2380,10 @@ bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op, if (lhs < rhs) { // lhs < rhs, so true if operation is LESS - return op == cmSystemTools::OP_LESS; + return (op & cmSystemTools::OP_LESS) != 0; } else if (lhs > rhs) { // lhs > rhs, so true if operation is GREATER - return op == cmSystemTools::OP_GREATER; + return (op & cmSystemTools::OP_GREATER) != 0; } if (*endr == '.') { @@ -2395,7 +2395,7 @@ bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op, } } // lhs == rhs, so true if operation is EQUAL - return op == cmSystemTools::OP_EQUAL; + return (op & cmSystemTools::OP_EQUAL) != 0; } bool cmSystemTools::VersionCompareEqual(std::string const& lhs, @@ -2412,6 +2412,13 @@ bool cmSystemTools::VersionCompareGreater(std::string const& lhs, rhs.c_str()); } +bool cmSystemTools::VersionCompareGreaterEq(std::string const& lhs, + std::string const& rhs) +{ + return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, + lhs.c_str(), rhs.c_str()); +} + bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, bool* removed) { diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 39e7994..f031273 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -284,9 +284,11 @@ public: enum CompareOp { - OP_LESS, - OP_GREATER, - OP_EQUAL + OP_EQUAL = 1, + OP_LESS = 2, + OP_GREATER = 4, + OP_LESS_EQUAL = OP_LESS | OP_EQUAL, + OP_GREATER_EQUAL = OP_GREATER | OP_EQUAL }; /** @@ -297,6 +299,8 @@ public: std::string const& rhs); static bool VersionCompareGreater(std::string const& lhs, std::string const& rhs); + static bool VersionCompareGreaterEq(std::string const& lhs, + std::string const& rhs); /** * Determine the file type based on the extension diff --git a/Tests/CMakeTests/VersionTest.cmake.in b/Tests/CMakeTests/VersionTest.cmake.in index 4e946ab..f045605 100644 --- a/Tests/CMakeTests/VersionTest.cmake.in +++ b/Tests/CMakeTests/VersionTest.cmake.in @@ -83,10 +83,24 @@ foreach(v IN LISTS LESSV) message(FATAL_ERROR "${CMAKE_MATCH_2} is less than ${CMAKE_MATCH_1}?") endif() + # check greater or equal (same as less negative) + if(CMAKE_MATCH_2 VERSION_GREATER_EQUAL CMAKE_MATCH_1) + message(STATUS "${CMAKE_MATCH_2} is not less than ${CMAKE_MATCH_1}") + else() + message(FATAL_ERROR "${CMAKE_MATCH_2} is less than ${CMAKE_MATCH_1}?") + endif() + # check greater negative case if(NOT CMAKE_MATCH_1 VERSION_GREATER CMAKE_MATCH_2) message(STATUS "${CMAKE_MATCH_1} is not greater than ${CMAKE_MATCH_2}") else() message(FATAL_ERROR "${CMAKE_MATCH_1} is greater than ${CMAKE_MATCH_2}?") endif() + + # check less or equal (same as greater negative) case + if(CMAKE_MATCH_1 VERSION_LESS_EQUAL CMAKE_MATCH_2) + message(STATUS "${CMAKE_MATCH_1} is not greater than ${CMAKE_MATCH_2}") + else() + message(FATAL_ERROR "${CMAKE_MATCH_1} is greater than ${CMAKE_MATCH_2}?") + endif() endforeach() diff --git a/Tests/CTestTestStopTime/GetDate.cmake b/Tests/CTestTestStopTime/GetDate.cmake index edc6519..1f4cb24 100644 --- a/Tests/CTestTestStopTime/GetDate.cmake +++ b/Tests/CTestTestStopTime/GetDate.cmake @@ -106,11 +106,11 @@ macro(ADD_SECONDS sec) set(new_min ${${GD_PREFIX}MINUTE}) set(new_hr ${${GD_PREFIX}HOUR}) math(EXPR new_sec "${sec} + ${${GD_PREFIX}SECOND}") - while(${new_sec} GREATER 60 OR ${new_sec} EQUAL 60) + while(${new_sec} GREATER_EQUAL 60) math(EXPR new_sec "${new_sec} - 60") math(EXPR new_min "${${GD_PREFIX}MINUTE} + 1") endwhile() - while(${new_min} GREATER 60 OR ${new_min} EQUAL 60) + while(${new_min} GREATER_EQUAL 60) math(EXPR new_min "${new_min} - 60") math(EXPR new_hr "${${GD_PREFIX}HOUR} + 1") endwhile() diff --git a/Tests/Complex/CMakeLists.txt b/Tests/Complex/CMakeLists.txt index 80cc2e3..075faa7 100644 --- a/Tests/Complex/CMakeLists.txt +++ b/Tests/Complex/CMakeLists.txt @@ -92,6 +92,12 @@ endif() if(NOT 2.4 EQUAL 2.4) message(FATAL_ERROR "Failed: NOT 2.4 EQUAL 2.4") endif() +if(NOT 2.4 LESS_EQUAL 2.4) + message(FATAL_ERROR "Failed: NOT 2.4 LESS_EQUAL 2.4") +endif() +if(NOT 2.4 GREATER_EQUAL 2.4) + message(FATAL_ERROR "Failed: NOT 2.4 GREATER_EQUAL 2.4") +endif() if(CMAKE_SYSTEM MATCHES "OSF1-V") if(NOT CMAKE_COMPILER_IS_GNUCXX) diff --git a/Tests/Complex/Executable/complex.cxx b/Tests/Complex/Executable/complex.cxx index 5f79ac0..f335d67 100644 --- a/Tests/Complex/Executable/complex.cxx +++ b/Tests/Complex/Executable/complex.cxx @@ -455,7 +455,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_LESS - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS is not defined."); #else cmPassed("SHOULD_BE_DEFINED_LESS is defined."); #endif @@ -467,7 +467,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_LESS2 - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS2 is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_LESS2 is defined."); #endif @@ -478,6 +478,24 @@ int main() cmPassed("SHOULD_NOT_BE_DEFINED_GREATER is not defined."); #endif +#ifndef SHOULD_BE_DEFINED_GREATER + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); +#endif + #ifdef SHOULD_NOT_BE_DEFINED_EQUAL cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_EQUAL is defined."); #else @@ -485,28 +503,92 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_EQUAL - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_EQUAL is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_EQUAL is not defined."); #else cmPassed("SHOULD_BE_DEFINED_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined.\n"); +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL is not defined."); #endif -#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 - cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL is not defined."); #else - cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER2 +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL3 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRLESS @@ -516,7 +598,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS is defined."); #endif @@ -528,22 +610,19 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS2 - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS2 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRGREATER - cmFailed( - "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); #else cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER is not defined."); #endif #ifndef SHOULD_BE_DEFINED_STRGREATER - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER is defined."); #endif @@ -557,11 +636,95 @@ int main() #ifndef SHOULD_BE_DEFINED_STRGREATER2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER2 is defined."); #endif +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is defined."); +#endif + // ---------------------------------------------------------------------- // Test FOREACH diff --git a/Tests/Complex/VarTests.cmake b/Tests/Complex/VarTests.cmake index 9d35949..8be59be 100644 --- a/Tests/Complex/VarTests.cmake +++ b/Tests/Complex/VarTests.cmake @@ -126,6 +126,12 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER) endif () +if (SNUM1_VAR GREATER SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER2) +endif () + if (SNUM2_VAR EQUAL SNUM1_VAR) add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) else () @@ -138,10 +144,40 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) endif () -if (SNUM1_VAR GREATER SNUM2_VAR) - add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +if (SNUM1_VAR LESS_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL) else () - add_definitions(-DSHOULD_BE_DEFINED_GREATER2) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL) +endif () + +if (SNUM2_VAR LESS_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL2) +endif () + +if (SNUM1_VAR LESS_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL3) +else () + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL3) +endif () + +if (SNUM2_VAR GREATER_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL2) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL3) endif () set (SSTR1_VAR "abc") @@ -171,6 +207,42 @@ else () add_definitions(-DSHOULD_BE_DEFINED_STRGREATER2) endif () +if (SSTR1_VAR STRLESS_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL) +endif () + +if (SSTR2_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL2) +endif () + +if (SSTR1_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3) +endif () + +if (SSTR2_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL2) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3) +endif () + # # Test FOREACH # diff --git a/Tests/ComplexOneConfig/Executable/complex.cxx b/Tests/ComplexOneConfig/Executable/complex.cxx index 5f79ac0..eeff948 100644 --- a/Tests/ComplexOneConfig/Executable/complex.cxx +++ b/Tests/ComplexOneConfig/Executable/complex.cxx @@ -478,6 +478,24 @@ int main() cmPassed("SHOULD_NOT_BE_DEFINED_GREATER is not defined."); #endif +#ifndef SHOULD_BE_DEFINED_GREATER + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined.\n"); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); +#endif + #ifdef SHOULD_NOT_BE_DEFINED_EQUAL cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_EQUAL is defined."); #else @@ -490,23 +508,86 @@ int main() cmPassed("SHOULD_BE_DEFINED_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined.\n"); +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL is not defined."); #endif -#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 - cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL is not defined."); #else - cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER2 +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL3 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRLESS @@ -516,7 +597,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS is defined."); #endif @@ -528,22 +609,19 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS2 - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS2 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRGREATER - cmFailed( - "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); #else cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER is not defined."); #endif #ifndef SHOULD_BE_DEFINED_STRGREATER - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER is defined."); #endif @@ -557,11 +635,95 @@ int main() #ifndef SHOULD_BE_DEFINED_STRGREATER2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER2 is defined."); #endif +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is defined."); +#endif + // ---------------------------------------------------------------------- // Test FOREACH diff --git a/Tests/ComplexOneConfig/VarTests.cmake b/Tests/ComplexOneConfig/VarTests.cmake index 9d35949..7dd8519 100644 --- a/Tests/ComplexOneConfig/VarTests.cmake +++ b/Tests/ComplexOneConfig/VarTests.cmake @@ -126,6 +126,12 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER) endif () +if (SNUM1_VAR GREATER SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER2) +endif () + if (SNUM2_VAR EQUAL SNUM1_VAR) add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) else () @@ -138,10 +144,40 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) endif () -if (SNUM1_VAR GREATER SNUM2_VAR) - add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +if (SNUM1_VAR LESS_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL) else () - add_definitions(-DSHOULD_BE_DEFINED_GREATER2) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL) +endif () + +if (SNUM2_VAR LESS_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL2) +endif () + +if (SNUM1_VAR LESS_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL3) +endif () + +if (SNUM2_VAR GREATER_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL2) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL3) endif () set (SSTR1_VAR "abc") @@ -171,6 +207,42 @@ else () add_definitions(-DSHOULD_BE_DEFINED_STRGREATER2) endif () +if (SSTR1_VAR STRLESS_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL) +endif () + +if (SSTR2_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL2) +endif () + +if (SSTR1_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3) +endif () + +if (SSTR2_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL2) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3) +endif () + # # Test FOREACH # ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 9 09:15:50 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 9 Aug 2016 09:15:50 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1179-g56bac0a Message-ID: <20160809131550.5C7E9F50BF@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 56bac0ae7c1e982e995546e8458a0f73b0f477b5 (commit) via c6da78dfa74d2dbab57535d864d2d1772763d008 (commit) via 83273ca5a1d36a6f05695d4c90a9e30c2874a087 (commit) from c9477b66889974bf27c435ef951435a557bfd1b7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=56bac0ae7c1e982e995546e8458a0f73b0f477b5 commit 56bac0ae7c1e982e995546e8458a0f73b0f477b5 Merge: c9477b6 c6da78d Author: Brad King AuthorDate: Tue Aug 9 09:15:49 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 9 09:15:49 2016 -0400 Merge topic 'autogen-same-name' into next c6da78df fixup! cmFilePathUuid: Add class to generate deterministic unique file names 83273ca5 QtAutogen: Replace invalid character for symbol names https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c6da78dfa74d2dbab57535d864d2d1772763d008 commit c6da78dfa74d2dbab57535d864d2d1772763d008 Author: Brad King AuthorDate: Tue Aug 9 09:14:18 2016 -0400 Commit: Brad King CommitDate: Tue Aug 9 09:14:18 2016 -0400 fixup! cmFilePathUuid: Add class to generate deterministic unique file names diff --git a/Source/cmFilePathUuid.cxx b/Source/cmFilePathUuid.cxx index e226cdc..592c3a6 100644 --- a/Source/cmFilePathUuid.cxx +++ b/Source/cmFilePathUuid.cxx @@ -126,18 +126,18 @@ std::string cmFilePathUuid::GetChecksumString( for (unsigned int jj = 0; jj != 2; ++jj) { const unsigned char nibble = hexHash[ii * 2 + jj]; if ('0' <= nibble && nibble <= '9') { - hbyte[jj] = nibble - '0'; + hbyte[jj] = static_cast(nibble - '0'); } else if ('a' <= nibble && nibble <= 'f') { - hbyte[jj] = nibble - 'a' + 10; + hbyte[jj] = static_cast(nibble - 'a' + 10); } else if ('A' <= nibble && nibble <= 'f') { - hbyte[jj] = nibble - 'A' + 10; + hbyte[jj] = static_cast(nibble - 'A' + 10); } else { // Unexpected non hex character std::cerr << "Unexpected non hex character in checksum string"; exit(-1); } } - hashBytes[ii] = hbyte[1] | (hbyte[0] << 4); + hashBytes[ii] = static_cast(hbyte[1] | (hbyte[0] << 4)); } } // Convert hash bytes to Base64 text string https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=83273ca5a1d36a6f05695d4c90a9e30c2874a087 commit 83273ca5a1d36a6f05695d4c90a9e30c2874a087 Author: Sebastian Holtermann AuthorDate: Mon Aug 8 20:58:21 2016 +0200 Commit: Brad King CommitDate: Tue Aug 9 09:04:40 2016 -0400 QtAutogen: Replace invalid character for symbol names diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 6a95615..a261962 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -1331,6 +1331,10 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, // Remove "qrc_" at string begin symbolName.erase(0, 4); } + // Replace '-' with '_'. The former is valid for + // file names but not for symbol names. + std::replace(symbolName.begin(), symbolName.end(), '-', '_'); + const std::string qrcBuildFile = this->Builddir + qrcOutputFile; int sourceNewerThanQrc = 0; ----------------------------------------------------------------------- Summary of changes: Source/cmFilePathUuid.cxx | 8 ++++---- Source/cmQtAutoGenerators.cxx | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 9 09:16:04 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 9 Aug 2016 09:16:04 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1185-g81666a6 Message-ID: <20160809131606.98A89F53D5@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 81666a6fb2567c8f71649db3c45ac00bdc7287ca (commit) via f692f66d492eca3a4f28a6fd496c9e3e859538d0 (commit) via 04b220a713c10791a2e576d620f7189421ca5749 (commit) via c84623b72dae79f9bf61d7e31b0d851e65a9ff1d (commit) via 4b4bafda73b0f7221498153e7bed69b9d44e7982 (commit) via 096d0ba6919cf78b127408cf5bb5b5404a77bb80 (commit) from 56bac0ae7c1e982e995546e8458a0f73b0f477b5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=81666a6fb2567c8f71649db3c45ac00bdc7287ca commit 81666a6fb2567c8f71649db3c45ac00bdc7287ca Merge: 56bac0a f692f66 Author: Brad King AuthorDate: Tue Aug 9 09:16:00 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 9 09:16:00 2016 -0400 Merge topic 'autogen-same-name' into next f692f66d Tests/QtAutogen: Test same moc/qrc source names in different directories 04b220a7 QtAutogen: Allow multiple qrc files with the same name c84623b7 QtAutogen: Allow multiple moc files with the same name 4b4bafda QtAutogen: Use std:: instead of ::std:: 096d0ba6 cmFilePathUuid: Add class to generate deterministic unique file names https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f692f66d492eca3a4f28a6fd496c9e3e859538d0 commit f692f66d492eca3a4f28a6fd496c9e3e859538d0 Author: Sebastian Holtermann AuthorDate: Sat Aug 6 15:22:54 2016 +0200 Commit: Brad King CommitDate: Tue Aug 9 09:14:38 2016 -0400 Tests/QtAutogen: Test same moc/qrc source names in different directories diff --git a/Tests/QtAutogen/CMakeLists.txt b/Tests/QtAutogen/CMakeLists.txt index d5aca55..e35e1d1 100644 --- a/Tests/QtAutogen/CMakeLists.txt +++ b/Tests/QtAutogen/CMakeLists.txt @@ -110,6 +110,10 @@ set_target_properties( AUTOMOC TRUE ) +# Test AUTOMOC and AUTORCC on source files with the same name +# but in different subdirectories +add_subdirectory(sameName) + include(GenerateExportHeader) # The order is relevant here. B depends on A, and B headers depend on A # headers both subdirectories use CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE and we diff --git a/Tests/QtAutogen/sameName/CMakeLists.txt b/Tests/QtAutogen/sameName/CMakeLists.txt new file mode 100644 index 0000000..ed045fb --- /dev/null +++ b/Tests/QtAutogen/sameName/CMakeLists.txt @@ -0,0 +1,21 @@ +# Test AUTOMOC and AUTORCC on source files with the same name +# but in different subdirectories + +add_executable(sameName + aaa/bbb/item.cpp + aaa/bbb/data.qrc + aaa/item.cpp + aaa/data.qrc + bbb/aaa/item.cpp + bbb/aaa/data.qrc + bbb/item.cpp + bbb/data.qrc + ccc/item.cpp + ccc/data.qrc + item.cpp + data.qrc + main.cpp +) +target_include_directories(sameName PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_link_libraries(sameName ${QT_LIBRARIES}) +set_target_properties( sameName PROPERTIES AUTOMOC TRUE AUTORCC TRUE ) diff --git a/Tests/QtAutogen/sameName/aaa/bbb/data.qrc b/Tests/QtAutogen/sameName/aaa/bbb/data.qrc new file mode 100644 index 0000000..0ea3537 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/bbb/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/aaa/bbb/item.cpp b/Tests/QtAutogen/sameName/aaa/bbb/item.cpp new file mode 100644 index 0000000..20d0044 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/bbb/item.cpp @@ -0,0 +1,10 @@ +#include "item.hpp" + +namespace aaa { +namespace bbb { + +void Item::go() +{ +} +} +} diff --git a/Tests/QtAutogen/sameName/aaa/bbb/item.hpp b/Tests/QtAutogen/sameName/aaa/bbb/item.hpp new file mode 100644 index 0000000..0855043 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/bbb/item.hpp @@ -0,0 +1,18 @@ +#ifndef AAA_BBB_ITEM_HPP +#define AAA_BBB_ITEM_HPP + +#include + +namespace aaa { +namespace bbb { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} +} + +#endif diff --git a/Tests/QtAutogen/sameName/aaa/data.qrc b/Tests/QtAutogen/sameName/aaa/data.qrc new file mode 100644 index 0000000..379af60 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/aaa/item.cpp b/Tests/QtAutogen/sameName/aaa/item.cpp new file mode 100644 index 0000000..95dd3b6 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/item.cpp @@ -0,0 +1,8 @@ +#include "item.hpp" + +namespace aaa { + +void Item::go() +{ +} +} diff --git a/Tests/QtAutogen/sameName/aaa/item.hpp b/Tests/QtAutogen/sameName/aaa/item.hpp new file mode 100644 index 0000000..b63466f --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/item.hpp @@ -0,0 +1,16 @@ +#ifndef AAA_ITEM_HPP +#define AAA_ITEM_HPP + +#include + +namespace aaa { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} + +#endif diff --git a/Tests/QtAutogen/sameName/bbb/aaa/data.qrc b/Tests/QtAutogen/sameName/bbb/aaa/data.qrc new file mode 100644 index 0000000..da98009 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/aaa/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/bbb/aaa/item.cpp b/Tests/QtAutogen/sameName/bbb/aaa/item.cpp new file mode 100644 index 0000000..ac4b2c2 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/aaa/item.cpp @@ -0,0 +1,10 @@ +#include "item.hpp" + +namespace bbb { +namespace aaa { + +void Item::go() +{ +} +} +} diff --git a/Tests/QtAutogen/sameName/bbb/aaa/item.hpp b/Tests/QtAutogen/sameName/bbb/aaa/item.hpp new file mode 100644 index 0000000..be07ca8 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/aaa/item.hpp @@ -0,0 +1,18 @@ +#ifndef BBB_AAA_ITEM_HPP +#define BBB_AAA_ITEM_HPP + +#include + +namespace bbb { +namespace aaa { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} +} + +#endif diff --git a/Tests/QtAutogen/sameName/bbb/data.qrc b/Tests/QtAutogen/sameName/bbb/data.qrc new file mode 100644 index 0000000..5b080f5 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/bbb/item.cpp b/Tests/QtAutogen/sameName/bbb/item.cpp new file mode 100644 index 0000000..f97a143 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/item.cpp @@ -0,0 +1,8 @@ +#include "item.hpp" + +namespace bbb { + +void Item::go() +{ +} +} diff --git a/Tests/QtAutogen/sameName/bbb/item.hpp b/Tests/QtAutogen/sameName/bbb/item.hpp new file mode 100644 index 0000000..5b7f985 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/item.hpp @@ -0,0 +1,16 @@ +#ifndef BBB_ITEM_HPP +#define BBB_ITEM_HPP + +#include + +namespace bbb { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} + +#endif diff --git a/Tests/QtAutogen/sameName/ccc/data.qrc b/Tests/QtAutogen/sameName/ccc/data.qrc new file mode 100644 index 0000000..f934c39 --- /dev/null +++ b/Tests/QtAutogen/sameName/ccc/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/ccc/item.cpp b/Tests/QtAutogen/sameName/ccc/item.cpp new file mode 100644 index 0000000..d90b2b8 --- /dev/null +++ b/Tests/QtAutogen/sameName/ccc/item.cpp @@ -0,0 +1,23 @@ +#include "item.hpp" + +namespace ccc { + +void Item::go() +{ +} + +class MocTest : public QObject +{ + Q_OBJECT; + Q_SLOT + void go(); +}; + +void MocTest::go() +{ +} +} + +// Include own moc files +#include "item.moc" +#include "moc_item.cpp" diff --git a/Tests/QtAutogen/sameName/ccc/item.hpp b/Tests/QtAutogen/sameName/ccc/item.hpp new file mode 100644 index 0000000..96fcc24 --- /dev/null +++ b/Tests/QtAutogen/sameName/ccc/item.hpp @@ -0,0 +1,16 @@ +#ifndef CCC_ITEM_HPP +#define CCC_ITEM_HPP + +#include + +namespace ccc { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} + +#endif diff --git a/Tests/QtAutogen/sameName/data.qrc b/Tests/QtAutogen/sameName/data.qrc new file mode 100644 index 0000000..4ce0b4e --- /dev/null +++ b/Tests/QtAutogen/sameName/data.qrc @@ -0,0 +1,5 @@ + + + main.cpp + + diff --git a/Tests/QtAutogen/sameName/item.cpp b/Tests/QtAutogen/sameName/item.cpp new file mode 100644 index 0000000..e013cf3 --- /dev/null +++ b/Tests/QtAutogen/sameName/item.cpp @@ -0,0 +1,5 @@ +#include "item.hpp" + +void Item::go() +{ +} diff --git a/Tests/QtAutogen/sameName/item.hpp b/Tests/QtAutogen/sameName/item.hpp new file mode 100644 index 0000000..91bba3b --- /dev/null +++ b/Tests/QtAutogen/sameName/item.hpp @@ -0,0 +1,13 @@ +#ifndef ITEM_HPP +#define ITEM_HPP + +#include + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; + +#endif diff --git a/Tests/QtAutogen/sameName/main.cpp b/Tests/QtAutogen/sameName/main.cpp new file mode 100644 index 0000000..a4ffcb3 --- /dev/null +++ b/Tests/QtAutogen/sameName/main.cpp @@ -0,0 +1,16 @@ +#include "aaa/bbb/item.hpp" +#include "aaa/item.hpp" +#include "bbb/aaa/item.hpp" +#include "bbb/item.hpp" +#include "ccc/item.hpp" + +int main(int argv, char** args) +{ + // Object instances + ::aaa::Item aaa_item; + ::aaa::bbb::Item aaa_bbb_item; + ::bbb::Item bbb_item; + ::bbb::aaa::Item bbb_aaa_item; + ::ccc::Item ccc_item; + return 0; +} https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=04b220a713c10791a2e576d620f7189421ca5749 commit 04b220a713c10791a2e576d620f7189421ca5749 Author: Sebastian Holtermann AuthorDate: Sat Aug 6 14:57:52 2016 +0200 Commit: Brad King CommitDate: Tue Aug 9 09:14:38 2016 -0400 QtAutogen: Allow multiple qrc files with the same name Use cmFilePathUuid for qrc files. diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index d5634e8..7efb333 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -13,6 +13,7 @@ #include "cmQtAutoGeneratorInitializer.h" +#include "cmFilePathUuid.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmSourceFile.h" @@ -25,6 +26,34 @@ #include "cmGlobalVisualStudioGenerator.h" #endif +static std::string GetAutogenTargetName(cmGeneratorTarget const* target) +{ + std::string autogenTargetName = target->GetName(); + autogenTargetName += "_automoc"; + return autogenTargetName; +} + +static std::string GetAutogenTargetDir(cmGeneratorTarget const* target) +{ + cmMakefile* makefile = target->Target->GetMakefile(); + std::string targetDir = makefile->GetCurrentBinaryDirectory(); + targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory(); + targetDir += "/"; + targetDir += GetAutogenTargetName(target); + targetDir += ".dir/"; + return targetDir; +} + +static std::string GetAutogenTargetBuildDir(cmGeneratorTarget const* target) +{ + cmMakefile* makefile = target->Target->GetMakefile(); + std::string targetDir = makefile->GetCurrentBinaryDirectory(); + targetDir += "/"; + targetDir += GetAutogenTargetName(target); + targetDir += ".dir/"; + return targetDir; +} + static void SetupSourceFiles(cmGeneratorTarget const* target, std::vector& skipMoc, std::vector& mocSources, @@ -38,6 +67,7 @@ static void SetupSourceFiles(cmGeneratorTarget const* target, std::vector newRccFiles; + cmFilePathUuid fpathUuid(makefile); for (std::vector::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; @@ -55,13 +85,12 @@ static void SetupSourceFiles(cmGeneratorTarget const* target, if (target->GetPropertyAsBool("AUTORCC")) { if (ext == "qrc" && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { - std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); - std::string rcc_output_dir = target->GetSupportDirectory(); - cmSystemTools::MakeDirectory(rcc_output_dir.c_str()); - std::string rcc_output_file = rcc_output_dir; - rcc_output_file += "/qrc_" + basename + ".cpp"; + std::string rcc_output_file = GetAutogenTargetBuildDir(target); + // Create output directory + cmSystemTools::MakeDirectory(rcc_output_file.c_str()); + rcc_output_file += fpathUuid.get(absFile, "qrc_", ".cpp"); + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", rcc_output_file.c_str(), false); makefile->GetOrCreateSource(rcc_output_file, true); @@ -365,24 +394,6 @@ static void MergeRccOptions(std::vector& opts, opts.insert(opts.end(), extraOpts.begin(), extraOpts.end()); } -std::string GetAutogenTargetName(cmGeneratorTarget const* target) -{ - std::string autogenTargetName = target->GetName(); - autogenTargetName += "_automoc"; - return autogenTargetName; -} - -std::string GetAutogenTargetDir(cmGeneratorTarget const* target) -{ - cmMakefile* makefile = target->Target->GetMakefile(); - std::string targetDir = makefile->GetCurrentBinaryDirectory(); - targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory(); - targetDir += "/"; - targetDir += GetAutogenTargetName(target); - targetDir += ".dir/"; - return targetDir; -} - static void copyTargetProperty(cmTarget* destinationTarget, cmTarget* sourceTarget, const std::string& propertyName) @@ -737,6 +748,7 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( ) { std::vector srcFiles; target->GetConfigCommonSourceFiles(srcFiles); + cmFilePathUuid fpathUuid(makefile); for (std::vector::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; @@ -747,15 +759,13 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( if (target->GetPropertyAsBool("AUTORCC")) { if (ext == "qrc" && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { - std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); - - std::string rcc_output_dir = target->GetSupportDirectory(); - cmSystemTools::MakeDirectory(rcc_output_dir.c_str()); - std::string rcc_output_file = rcc_output_dir; - rcc_output_file += "/qrc_" + basename + ".cpp"; - rcc_output.push_back(rcc_output_file); - + { + std::string rcc_output_file = GetAutogenTargetBuildDir(target); + // Create output directory + cmSystemTools::MakeDirectory(rcc_output_file.c_str()); + rcc_output_file += fpathUuid.get(absFile, "qrc_", ".cpp"); + rcc_output.push_back(rcc_output_file); + } if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { if (qtMajorVersion == "5") { ListQt5RccInputs(sf, target, depends); diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 33f7a54..a261962 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -88,6 +88,23 @@ static std::string extractSubDir(const std::string& absPath, return subDir; } +static bool FileNameIsUnique(const std::string& filePath, + const std::map& fileMap) +{ + size_t count(0); + const std::string fileName = cmsys::SystemTools::GetFilenameName(filePath); + for (std::map::const_iterator si = fileMap.begin(); + si != fileMap.end(); ++si) { + if (cmsys::SystemTools::GetFilenameName(si->first) == fileName) { + ++count; + if (count > 1) { + return false; + } + } + } + return true; +} + cmQtAutoGenerators::cmQtAutoGenerators() : Verbose(cmsys::SystemTools::HasEnv("VERBOSE")) , ColorOutput(true) @@ -1257,15 +1274,18 @@ bool cmQtAutoGenerators::GenerateQrcFiles() { // generate single map with input / output names std::map qrcGenMap; - for (std::vector::const_iterator si = this->RccSources.begin(); - si != this->RccSources.end(); ++si) { - const std::string ext = cmsys::SystemTools::GetFilenameLastExtension(*si); - if (ext == ".qrc") { - std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(*si); - std::string qrcOutputFile = "CMakeFiles/" + this->OriginTargetName + - ".dir/qrc_" + basename + ".cpp"; - qrcGenMap[*si] = qrcOutputFile; + { + cmFilePathUuid fpathUuid(this->Srcdir, this->Builddir, + this->ProjectSourceDir, this->ProjectBinaryDir); + for (std::vector::const_iterator si = + this->RccSources.begin(); + si != this->RccSources.end(); ++si) { + const std::string ext = + cmsys::SystemTools::GetFilenameLastExtension(*si); + if (ext == ".qrc") { + qrcGenMap[*si] = + (this->TargetBuildSubDir + fpathUuid.get(*si, "qrc_", ".cpp")); + } } } @@ -1287,7 +1307,8 @@ bool cmQtAutoGenerators::GenerateQrcFiles() for (std::map::const_iterator si = qrcGenMap.begin(); si != qrcGenMap.end(); ++si) { - if (!this->GenerateQrc(si->first, si->second)) { + bool unique = FileNameIsUnique(si->first, qrcGenMap); + if (!this->GenerateQrc(si->first, si->second, unique)) { if (this->RunRccFailed) { return false; } @@ -1297,10 +1318,23 @@ bool cmQtAutoGenerators::GenerateQrcFiles() } bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, - const std::string& qrcOutputFile) + const std::string& qrcOutputFile, + bool unique_n) { - const std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); + std::string symbolName; + if (unique_n) { + symbolName = + cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); + } else { + symbolName = + cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcOutputFile); + // Remove "qrc_" at string begin + symbolName.erase(0, 4); + } + // Replace '-' with '_'. The former is valid for + // file names but not for symbol names. + std::replace(symbolName.begin(), symbolName.end(), '-', '_'); + const std::string qrcBuildFile = this->Builddir + qrcOutputFile; int sourceNewerThanQrc = 0; @@ -1327,7 +1361,7 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, } command.push_back("-name"); - command.push_back(basename); + command.push_back(symbolName); command.push_back("-o"); command.push_back(qrcBuildFile); command.push_back(qrcInputFile); diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 216b0b0..fab2d19 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -51,7 +51,8 @@ private: const std::string& uiOutputFile); bool GenerateQrcFiles(); bool GenerateQrc(const std::string& qrcInputFile, - const std::string& qrcOutputFile); + const std::string& qrcOutputFile, bool unique_n); + void ParseCppFile( const std::string& absFilename, const std::vector& headerExtensions, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c84623b72dae79f9bf61d7e31b0d851e65a9ff1d commit c84623b72dae79f9bf61d7e31b0d851e65a9ff1d Author: Sebastian Holtermann AuthorDate: Sat Aug 6 13:33:46 2016 +0200 Commit: Brad King CommitDate: Tue Aug 9 09:14:38 2016 -0400 QtAutogen: Allow multiple moc files with the same name Use cmFilePathUuid for moc files. Closes: #12873 diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index ea8db71..33f7a54 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -14,6 +14,7 @@ #include "cmQtAutoGenerators.h" #include "cmAlgorithms.h" +#include "cmFilePathUuid.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmOutputConverter.h" @@ -358,11 +359,13 @@ void cmQtAutoGenerators::WriteOldMocDefinitionsFile( void cmQtAutoGenerators::Init() { + this->TargetBuildSubDir = this->TargetName; + this->TargetBuildSubDir += ".dir/"; + this->OutMocCppFilenameRel = this->TargetName; this->OutMocCppFilenameRel += ".cpp"; - this->OutMocCppFilename = this->Builddir; - this->OutMocCppFilename += this->OutMocCppFilenameRel; + this->OutMocCppFilenameAbs = this->Builddir + this->OutMocCppFilenameRel; std::vector cdefList; cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList); @@ -439,7 +442,7 @@ static std::string ReadAll(const std::string& filename) bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile) { - if (!cmsys::SystemTools::FileExists(this->OutMocCppFilename.c_str()) || + if (!cmsys::SystemTools::FileExists(this->OutMocCppFilenameAbs.c_str()) || (this->OldCompileSettingsStr != this->CurrentCompileSettingsStr)) { this->GenerateAll = true; } @@ -933,6 +936,8 @@ void cmQtAutoGenerators::ParseHeaders( std::map& notIncludedMocs, std::map >& includedUis) { + cmFilePathUuid fpathUuid(this->Srcdir, this->Builddir, + this->ProjectSourceDir, this->ProjectBinaryDir); for (std::set::const_iterator hIt = absHeaders.begin(); hIt != absHeaders.end(); ++hIt) { const std::string& headerName = *hIt; @@ -946,13 +951,10 @@ void cmQtAutoGenerators::ParseHeaders( this->LogInfo(err.str()); } - const std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(headerName); - - const std::string currentMoc = "moc_" + basename + ".cpp"; std::string macroName; if (requiresMocing(contents, macroName)) { - notIncludedMocs[headerName] = currentMoc; + notIncludedMocs[headerName] = + this->TargetBuildSubDir + fpathUuid.get(headerName, "moc_", ".cpp"); } } this->ParseForUic(headerName, contents, includedUis); @@ -1029,7 +1031,7 @@ bool cmQtAutoGenerators::GenerateMocFiles( // check if we even need to update _automoc.cpp if (!automocCppChanged) { // compare contents of the _automoc.cpp file - const std::string oldContents = ReadAll(this->OutMocCppFilename); + const std::string oldContents = ReadAll(this->OutMocCppFilenameAbs); if (oldContents == automocSource) { // nothing changed: don't touch the _automoc.cpp file if (this->Verbose) { @@ -1052,7 +1054,7 @@ bool cmQtAutoGenerators::GenerateMocFiles( } { cmsys::ofstream outfile; - outfile.open(this->OutMocCppFilename.c_str(), std::ios::trunc); + outfile.open(this->OutMocCppFilenameAbs.c_str(), std::ios::trunc); outfile << automocSource; outfile.close(); } diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 86913f0..216b0b0 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -123,8 +123,9 @@ private: std::string CurrentCompileSettingsStr; std::string OldCompileSettingsStr; + std::string TargetBuildSubDir; std::string OutMocCppFilenameRel; - std::string OutMocCppFilename; + std::string OutMocCppFilenameAbs; std::list MocIncludes; std::list MocDefinitions; std::vector MocOptions; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4b4bafda73b0f7221498153e7bed69b9d44e7982 commit 4b4bafda73b0f7221498153e7bed69b9d44e7982 Author: Sebastian Holtermann AuthorDate: Sat Aug 6 14:05:23 2016 +0200 Commit: Brad King CommitDate: Tue Aug 9 09:14:38 2016 -0400 QtAutogen: Use std:: instead of ::std:: diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 174760f..ea8db71 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -1183,7 +1183,7 @@ bool cmQtAutoGenerators::GenerateUi(const std::string& realName, cmsys::SystemTools::MakeDirectory(this->Builddir.c_str()); } - const ::std::string uiBuildFile = this->Builddir + uiOutputFile; + const std::string uiBuildFile = this->Builddir + uiOutputFile; int sourceNewerThanUi = 0; bool success = cmsys::SystemTools::FileTimeCompare(uiInputFile, uiBuildFile, @@ -1299,7 +1299,7 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, { const std::string basename = cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); - const ::std::string qrcBuildFile = this->Builddir + qrcOutputFile; + const std::string qrcBuildFile = this->Builddir + qrcOutputFile; int sourceNewerThanQrc = 0; bool generateQrc = !cmsys::SystemTools::FileTimeCompare( https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=096d0ba6919cf78b127408cf5bb5b5404a77bb80 commit 096d0ba6919cf78b127408cf5bb5b5404a77bb80 Author: Sebastian Holtermann AuthorDate: Sat Aug 6 13:09:59 2016 +0200 Commit: Brad King CommitDate: Tue Aug 9 09:14:37 2016 -0400 cmFilePathUuid: Add class to generate deterministic unique file names The class generates a semi-unique (checksum based) pathless file name from a full source file path. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index a790994..cdc8fb1 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -238,6 +238,8 @@ set(SRCS cmFileLockPool.h cmFileLockResult.cxx cmFileLockResult.h + cmFilePathUuid.cxx + cmFilePathUuid.h cmFileTimeComparison.cxx cmFileTimeComparison.h cmFortranLexer.cxx diff --git a/Source/cmFilePathUuid.cxx b/Source/cmFilePathUuid.cxx new file mode 100644 index 0000000..592c3a6 --- /dev/null +++ b/Source/cmFilePathUuid.cxx @@ -0,0 +1,156 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2016 Sebastian Holtermann (sebholt at xwmw.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmFilePathUuid.h" + +#include "cmCryptoHash.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" +#include "cmsys/Base64.h" + +cmFilePathUuid::cmFilePathUuid(cmMakefile* makefile) +{ + initParentDirs(makefile->GetCurrentSourceDirectory(), + makefile->GetCurrentBinaryDirectory(), + makefile->GetHomeDirectory(), + makefile->GetHomeOutputDirectory()); +} + +cmFilePathUuid::cmFilePathUuid(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir) +{ + initParentDirs(currentSrcDir, currentBinDir, projectSrcDir, projectBinDir); +} + +void cmFilePathUuid::initParentDirs(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir) +{ + parentDirs[0].first = cmsys::SystemTools::GetRealPath(currentSrcDir); + parentDirs[1].first = cmsys::SystemTools::GetRealPath(currentBinDir); + parentDirs[2].first = cmsys::SystemTools::GetRealPath(projectSrcDir); + parentDirs[3].first = cmsys::SystemTools::GetRealPath(projectBinDir); + + parentDirs[0].second = "CurrentSource"; + parentDirs[1].second = "CurrentBinary"; + parentDirs[2].second = "ProjectSource"; + parentDirs[3].second = "ProjectBinary"; +} + +std::string cmFilePathUuid::get(const std::string& filePath, + const char* outputPrefix, + const char* outputSuffix) +{ + std::string sourceFilename = cmsys::SystemTools::GetFilenameName(filePath); + std::string sourceBasename = + cmsys::SystemTools::GetFilenameWithoutLastExtension(sourceFilename); + + // Acquire checksum string + std::string checksum; + { + std::string sourceRelPath; + std::string sourceRelSeed; + GetRelPathSeed(filePath, sourceRelPath, sourceRelSeed); + checksum = GetChecksumString(sourceFilename, sourceRelPath, sourceRelSeed); + } + + // Compose the file name + std::string uuid; + if (outputPrefix) { + uuid += outputPrefix; + } + uuid += sourceBasename.substr(0, partLengthName); + uuid += "_"; + uuid += checksum.substr(0, partLengthCheckSum); + if (outputSuffix) { + uuid += outputSuffix; + } + return uuid; +} + +void cmFilePathUuid::GetRelPathSeed(const std::string& filePath, + std::string& sourceRelPath, + std::string& sourceRelSeed) +{ + const std::string sourceNameReal = cmsys::SystemTools::GetRealPath(filePath); + std::string parentDirectory; + // Find closest project parent directory + for (size_t ii = 0; ii != numParentDirs; ++ii) { + const std::string& pDir = parentDirs[ii].first; + if (!pDir.empty() && + cmsys::SystemTools::IsSubDirectory(sourceNameReal, pDir)) { + sourceRelSeed = parentDirs[ii].second; + parentDirectory = pDir; + break; + } + } + // Check if the file path is below a known project directory + if (parentDirectory.empty()) { + // Use file syste root as fallback parent directory + sourceRelSeed = "FileSystemRoot"; + cmsys::SystemTools::SplitPathRootComponent(sourceNameReal, + &parentDirectory); + } + sourceRelPath = cmsys::SystemTools::RelativePath( + parentDirectory, cmsys::SystemTools::GetParentDirectory(sourceNameReal)); +} + +std::string cmFilePathUuid::GetChecksumString( + const std::string& sourceFilename, const std::string& sourceRelPath, + const std::string& sourceRelSeed) +{ + // Calculate the file ( seed + relative path + name ) checksum + std::string checksumBase64; + + std::vector hashBytes; + { + // Acquire hash in a hex value string + std::string hexHash = cmCryptoHash::New("SHA256")->HashString( + (sourceRelSeed + sourceRelPath + sourceFilename).c_str()); + // Convert hex value string to bytes + hashBytes.resize(hexHash.size() / 2); + for (unsigned int ii = 0; ii != hashBytes.size(); ++ii) { + unsigned char hbyte[2] = { 0, 0 }; + for (unsigned int jj = 0; jj != 2; ++jj) { + const unsigned char nibble = hexHash[ii * 2 + jj]; + if ('0' <= nibble && nibble <= '9') { + hbyte[jj] = static_cast(nibble - '0'); + } else if ('a' <= nibble && nibble <= 'f') { + hbyte[jj] = static_cast(nibble - 'a' + 10); + } else if ('A' <= nibble && nibble <= 'f') { + hbyte[jj] = static_cast(nibble - 'A' + 10); + } else { + // Unexpected non hex character + std::cerr << "Unexpected non hex character in checksum string"; + exit(-1); + } + } + hashBytes[ii] = static_cast(hbyte[1] | (hbyte[0] << 4)); + } + } + // Convert hash bytes to Base64 text string + { + std::vector base64Bytes(hashBytes.size() * 2, 0); + cmsysBase64_Encode(&hashBytes[0], hashBytes.size(), &base64Bytes[0], 0); + checksumBase64 = reinterpret_cast(&base64Bytes[0]); + // Base64 allows '+' and '/' characters. + // Both are problematic when used in file names. + // Replace them with safer alternatives. + std::replace(checksumBase64.begin(), checksumBase64.end(), '+', '_'); + std::replace(checksumBase64.begin(), checksumBase64.end(), '/', '-'); + } + + return checksumBase64; +} diff --git a/Source/cmFilePathUuid.h b/Source/cmFilePathUuid.h new file mode 100644 index 0000000..42e89b1 --- /dev/null +++ b/Source/cmFilePathUuid.h @@ -0,0 +1,77 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2016 Sebastian Holtermann (sebholt at xwmw.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmFilePathUuid_h +#define cmFilePathUuid_h + +#include "cmStandardIncludes.h" + +#include +#include + +class cmMakefile; + +/** \class cmFilePathUuid + * @brief Generates a unique pathless file name with a checksum component + * calculated from the file path. + * + * The checksum is calculated from the relative file path to the + * closest known project directory. This guarantees reproducibility + * when source and build directory differ e.g. for different project + * build directories. + */ +class cmFilePathUuid +{ +public: + /// Maximum number of characters to use from the file name + static const size_t partLengthName = 14; + /// Maximum number of characters to use from the path checksum + static const size_t partLengthCheckSum = 14; + + /// @brief Initilizes the parent directories from a makefile + cmFilePathUuid(cmMakefile* makefile); + + /// @brief Initilizes the parent directories manually + cmFilePathUuid(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir); + + /* @brief Calculates and returns the uuid for a file path + * + * @arg outputPrefix optional string to prepend to the result + * @arg outputSuffix optional string to append to the result + */ + std::string get(const std::string& filePath, const char* outputPrefix = NULL, + const char* outputSuffix = NULL); + +private: + void initParentDirs(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir); + + /// Returns the relative path and the parent directory key string (seed) + void GetRelPathSeed(const std::string& filePath, std::string& sourceRelPath, + std::string& sourceRelSeed); + + std::string GetChecksumString(const std::string& sourceFilename, + const std::string& sourceRelPath, + const std::string& sourceRelSeed); + + /// Size of the parent directory list + static const size_t numParentDirs = 4; + /// List of (directory name, seed name) pairs + std::pair parentDirs[numParentDirs]; +}; + +#endif ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 9 09:20:15 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 9 Aug 2016 09:20:15 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-586-g892ffe4 Message-ID: <20160809132015.33B88F5532@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 892ffe4ebd5ca0fd36255671efe37edc9448b470 (commit) via 17bbf6af1ecca15194a693d31fdd8163aacfd994 (commit) from 982b4cd602fc125c9d2165145100d5e574644bf9 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=892ffe4ebd5ca0fd36255671efe37edc9448b470 commit 892ffe4ebd5ca0fd36255671efe37edc9448b470 Merge: 982b4cd 17bbf6a Author: Brad King AuthorDate: Tue Aug 9 09:20:13 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 9 09:20:13 2016 -0400 Merge topic 'wix-custom-install-dir' 17bbf6af CPackWIX: Implement new CPACK_WIX_SKIP_PROGRAM_FOLDER feature ----------------------------------------------------------------------- Summary of changes: Help/release/dev/wix-custom-install-dir.rst | 7 +++++++ Modules/CPackWIX.cmake | 17 +++++++++++++++++ Source/CPack/WiX/cmCPackWIXGenerator.cxx | 9 +++++++++ Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx | 10 +++++++--- Source/CPack/WiX/cmWIXFilesSourceWriter.cxx | 14 +++++++++++++- Source/CPack/WiX/cmWIXFilesSourceWriter.h | 2 ++ 6 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 Help/release/dev/wix-custom-install-dir.rst hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 9 09:20:17 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 9 Aug 2016 09:20:17 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-588-ga8c8196 Message-ID: <20160809132017.D6D85F5554@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via a8c819659be76426804abc28bb6221a2dc3bf333 (commit) via 955c2a630aae9b925b468e98e7c323384d943cb0 (commit) from 892ffe4ebd5ca0fd36255671efe37edc9448b470 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a8c819659be76426804abc28bb6221a2dc3bf333 commit a8c819659be76426804abc28bb6221a2dc3bf333 Merge: 892ffe4 955c2a6 Author: Brad King AuthorDate: Tue Aug 9 09:20:15 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 9 09:20:15 2016 -0400 Merge topic 'ninja-full-path' 955c2a63 Ninja: Use full path for all source files ----------------------------------------------------------------------- Summary of changes: Source/cmNinjaTargetGenerator.cxx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 9 09:20:20 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 9 Aug 2016 09:20:20 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-590-ga5b73e7 Message-ID: <20160809132020.6E7A6F5558@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via a5b73e719a744a75be6ccf149360b14aaebbb273 (commit) via 5f3c8f6ab2c6633bdbfc083b9e96b477c1700c80 (commit) from a8c819659be76426804abc28bb6221a2dc3bf333 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a5b73e719a744a75be6ccf149360b14aaebbb273 commit a5b73e719a744a75be6ccf149360b14aaebbb273 Merge: a8c8196 5f3c8f6 Author: Brad King AuthorDate: Tue Aug 9 09:20:18 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 9 09:20:18 2016 -0400 Merge topic 'GetPrerequisites-grep-a' 5f3c8f6a GetPrerequisites: Always filter objdump output as text ----------------------------------------------------------------------- Summary of changes: Modules/GetPrerequisites.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 9 09:20:23 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 9 Aug 2016 09:20:23 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-593-g4689d16 Message-ID: <20160809132023.97415F541C@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 4689d16e8aa90e57a8456357251b6575131529d7 (commit) via 551b4c90626357ee9b6048e89c7406f3b4063fbb (commit) via 3a7be4f3943e160b1c0c144d914d3dd2ba42819e (commit) from a5b73e719a744a75be6ccf149360b14aaebbb273 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4689d16e8aa90e57a8456357251b6575131529d7 commit 4689d16e8aa90e57a8456357251b6575131529d7 Merge: a5b73e7 551b4c9 Author: Brad King AuthorDate: Tue Aug 9 09:20:21 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 9 09:20:21 2016 -0400 Merge topic 'fix-string-append' 551b4c90 Revert the use of string(APPEND) in .cmake.in files 3a7be4f3 prefer list(APPEND) over string(APPEND) where appropriate ----------------------------------------------------------------------- Summary of changes: Modules/BasicConfigVersion-AnyNewerVersion.cmake.in | 2 +- Modules/BasicConfigVersion-ExactVersion.cmake.in | 2 +- Modules/BasicConfigVersion-SameMajorVersion.cmake.in | 2 +- Modules/ExternalProject.cmake | 2 +- Modules/FindQt4.cmake | 2 +- Tests/RunCMake/CPack/VerifyResult.cmake | 4 ++-- Tests/SimpleInstall/CMakeLists.txt | 4 ++-- Tests/SimpleInstallS2/CMakeLists.txt | 4 ++-- 8 files changed, 11 insertions(+), 11 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 9 09:20:38 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 9 Aug 2016 09:20:38 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1191-gabfa202 Message-ID: <20160809132038.DAB60F5557@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via abfa2025ae10de25d5135b6ad010750c0addd3f7 (commit) via 4689d16e8aa90e57a8456357251b6575131529d7 (commit) via a5b73e719a744a75be6ccf149360b14aaebbb273 (commit) via a8c819659be76426804abc28bb6221a2dc3bf333 (commit) via 892ffe4ebd5ca0fd36255671efe37edc9448b470 (commit) via 982b4cd602fc125c9d2165145100d5e574644bf9 (commit) from 81666a6fb2567c8f71649db3c45ac00bdc7287ca (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=abfa2025ae10de25d5135b6ad010750c0addd3f7 commit abfa2025ae10de25d5135b6ad010750c0addd3f7 Merge: 81666a6 4689d16 Author: Brad King AuthorDate: Tue Aug 9 09:20:30 2016 -0400 Commit: Brad King CommitDate: Tue Aug 9 09:20:30 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 9 09:30:28 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 9 Aug 2016 09:30:28 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1194-gdaf8cd4 Message-ID: <20160809133028.5A00DF5937@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via daf8cd4836854ba7640edeb629d9049e9f89a8f3 (commit) via f38a17f8898caca1019d5b1952760315bab7aeca (commit) via 62a18526df331e96c3e3e5a3fc4dcaec24657f80 (commit) from abfa2025ae10de25d5135b6ad010750c0addd3f7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=daf8cd4836854ba7640edeb629d9049e9f89a8f3 commit daf8cd4836854ba7640edeb629d9049e9f89a8f3 Merge: abfa202 f38a17f Author: Brad King AuthorDate: Tue Aug 9 09:30:27 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 9 09:30:27 2016 -0400 Merge topic 'add-extra-boolean-comparisons' into next f38a17f8 fixup! Add additional <= and >= comparison operators 62a18526 fixup! Add additional <= and >= comparison operators https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f38a17f8898caca1019d5b1952760315bab7aeca commit f38a17f8898caca1019d5b1952760315bab7aeca Author: Brad King AuthorDate: Tue Aug 9 09:24:04 2016 -0400 Commit: Brad King CommitDate: Tue Aug 9 09:24:04 2016 -0400 fixup! Add additional <= and >= comparison operators diff --git a/Help/release/dev/add-extra-boolean-comparisons.rst b/Help/release/dev/add-extra-boolean-comparisons.rst index a69b212..a928994 100644 --- a/Help/release/dev/add-extra-boolean-comparisons.rst +++ b/Help/release/dev/add-extra-boolean-comparisons.rst @@ -1,5 +1,6 @@ add-extra-boolean-comparisons ----------------------------- -* Add LESS_EQUAL, GREATER_EQUAL, and thier associated STR and VERSION - equivalents to use the combined <= and >= functionality. +* The :command:`if` command gained new boolean comparison operations + ``LESS_EQUAL``, ``GREATER_EQUAL``, ``STRLESS_EQUAL``, ``STRGREATER_EQUAL``, + ``VERSION_LESS_EQUAL``, and ``VERSION_GREATER_EQUAL``. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=62a18526df331e96c3e3e5a3fc4dcaec24657f80 commit 62a18526df331e96c3e3e5a3fc4dcaec24657f80 Author: Brad King AuthorDate: Tue Aug 9 09:21:32 2016 -0400 Commit: Brad King CommitDate: Tue Aug 9 09:21:32 2016 -0400 fixup! Add additional <= and >= comparison operators diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 141a00e..8a856a8 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -366,9 +366,8 @@ bool cmCTest::ShouldCompressTestOutput() if (!this->ComputedCompressTestOutput) { std::string cdashVersion = this->GetCDashVersion(); // version >= 1.6? - bool cdashSupportsGzip = - cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, - cdashVersion.c_str(), "1.6"); + bool cdashSupportsGzip = cmSystemTools::VersionCompare( + cmSystemTools::OP_GREATER_EQUAL, cdashVersion.c_str(), "1.6"); this->CompressTestOutput &= cdashSupportsGzip; this->ComputedCompressTestOutput = true; } diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index 705fc7d..3c913ee 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -484,9 +484,9 @@ bool cmStringCommand::HandleCompareCommand( return false; } std::string mode = args[1]; - if ((mode == "EQUAL") || (mode == "NOTEQUAL") || - (mode == "LESS") || (mode == "LESS_EQUAL") || - (mode == "GREATER") || (mode == "GREATER_EQUAL")) { + if ((mode == "EQUAL") || (mode == "NOTEQUAL") || (mode == "LESS") || + (mode == "LESS_EQUAL") || (mode == "GREATER") || + (mode == "GREATER_EQUAL")) { if (args.size() < 5) { std::string e = "sub-command COMPARE, mode "; e += mode; diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index f031273..d0a28e1 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -284,10 +284,10 @@ public: enum CompareOp { - OP_EQUAL = 1, - OP_LESS = 2, + OP_EQUAL = 1, + OP_LESS = 2, OP_GREATER = 4, - OP_LESS_EQUAL = OP_LESS | OP_EQUAL, + OP_LESS_EQUAL = OP_LESS | OP_EQUAL, OP_GREATER_EQUAL = OP_GREATER | OP_EQUAL }; diff --git a/Tests/Complex/Executable/complex.cxx b/Tests/Complex/Executable/complex.cxx index f335d67..3b09229 100644 --- a/Tests/Complex/Executable/complex.cxx +++ b/Tests/Complex/Executable/complex.cxx @@ -509,7 +509,8 @@ int main() #endif #ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL - cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL is defined."); + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL is defined."); #else cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL is not defined."); #endif @@ -616,13 +617,15 @@ int main() #endif #ifdef SHOULD_NOT_BE_DEFINED_STRGREATER - cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); #else cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER is not defined."); #endif #ifndef SHOULD_BE_DEFINED_STRGREATER - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined."); + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER is defined."); #endif @@ -650,7 +653,7 @@ int main() #ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL is not defined."); + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL is defined."); #endif @@ -698,29 +701,29 @@ int main() #endif #ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 - cmFailed( - "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is defined."); + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is " + "defined."); #else cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); #endif #ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL2 - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is not " + "defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 - cmFailed( - "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is defined."); + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is " + "defined."); #else cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); #endif #ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL3 - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is not " + "defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is defined."); #endif diff --git a/Tests/ComplexOneConfig/Executable/complex.cxx b/Tests/ComplexOneConfig/Executable/complex.cxx index eeff948..9e4eaad 100644 --- a/Tests/ComplexOneConfig/Executable/complex.cxx +++ b/Tests/ComplexOneConfig/Executable/complex.cxx @@ -509,13 +509,15 @@ int main() #endif #ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL - cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL is defined."); + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL is defined."); #else cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL is not defined."); #endif #ifndef SHOULD_BE_DEFINED_LESS_EQUAL - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL is not defined."); + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL is not defined."); #else cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL is defined."); #endif @@ -615,13 +617,15 @@ int main() #endif #ifdef SHOULD_NOT_BE_DEFINED_STRGREATER - cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined."); #else cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER is not defined."); #endif #ifndef SHOULD_BE_DEFINED_STRGREATER - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined."); + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER is defined."); #endif @@ -697,29 +701,29 @@ int main() #endif #ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 - cmFailed( - "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is defined."); + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is " + "defined."); #else cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); #endif #ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL2 - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is not " + "defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 - cmFailed( - "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is defined."); + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is " + "defined."); #else cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); #endif #ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL3 - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is not " + "defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is defined."); #endif ----------------------------------------------------------------------- Summary of changes: Help/release/dev/add-extra-boolean-comparisons.rst | 5 ++-- Source/cmCTest.cxx | 5 ++-- Source/cmStringCommand.cxx | 6 ++--- Source/cmSystemTools.h | 6 ++--- Tests/Complex/Executable/complex.cxx | 27 ++++++++++--------- Tests/ComplexOneConfig/Executable/complex.cxx | 28 +++++++++++--------- 6 files changed, 42 insertions(+), 35 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 9 09:30:43 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 9 Aug 2016 09:30:43 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1196-g1554a1b Message-ID: <20160809133043.1D0DDF5936@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 1554a1b92f5fbdde852bc08e5e3534e42a914691 (commit) via 02d177c9cc05514baccfa530ab85eec65374fbcb (commit) from daf8cd4836854ba7640edeb629d9049e9f89a8f3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1554a1b92f5fbdde852bc08e5e3534e42a914691 commit 1554a1b92f5fbdde852bc08e5e3534e42a914691 Merge: daf8cd4 02d177c Author: Brad King AuthorDate: Tue Aug 9 09:30:42 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 9 09:30:42 2016 -0400 Merge topic 'add-extra-boolean-comparisons' into next 02d177c9 Add additional <= and >= comparison operators https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=02d177c9cc05514baccfa530ab85eec65374fbcb commit 02d177c9cc05514baccfa530ab85eec65374fbcb Author: Chuck Atkins AuthorDate: Fri Aug 5 14:11:46 2016 -0400 Commit: Brad King CommitDate: Tue Aug 9 09:30:34 2016 -0400 Add additional <= and >= comparison operators This adds the LESS_EQUAL, GREATER_EQUAL, and associated STR and VERSION equivalents to use the combined <= and >= functionality. diff --git a/Help/command/if.rst b/Help/command/if.rst index 56e618c..0941029 100644 --- a/Help/command/if.rst +++ b/Help/command/if.rst @@ -30,10 +30,12 @@ else and endif clause is optional. Long expressions can be used and there is a traditional order of precedence. Parenthetical expressions are evaluated first followed by unary tests such as ``EXISTS``, ``COMMAND``, and ``DEFINED``. Then any binary tests such as -``EQUAL``, ``LESS``, ``GREATER``, ``STRLESS``, ``STRGREATER``, -``STREQUAL``, and ``MATCHES`` will be evaluated. Then boolean ``NOT`` -operators and finally boolean ``AND`` and then ``OR`` operators will -be evaluated. +``EQUAL``, ``LESS``, ``LESS_EQUAL, ``GREATER``, ``GREATER_EQUAL``, +``STREQUAL``, ``STRLESS``, ``STRLESS_EQUAL``, ``STRGREATER``, +``STRGREATER_EQUAL``, ``VERSION_EQUAL``, ``VERSION_LESS``, +``VERSION_LESS_EQUAL``, ``VERSION_GREATER``, ``VERSION_GREATER_EQUAL``, +and ``MATCHES`` will be evaluated. Then boolean ``NOT`` operators and +finally boolean ``AND`` and then ``OR`` operators will be evaluated. Possible expressions are: @@ -115,6 +117,14 @@ Possible expressions are: True if the given string or variable's value is a valid number and equal to that on the right. +``if( LESS_EQUAL )`` + True if the given string or variable's value is a valid number and less + than or equal to that on the right. + +``if( GREATER_EQUAL )`` + True if the given string or variable's value is a valid number and greater + than or equal to that on the right. + ``if( STRLESS )`` True if the given string or variable's value is lexicographically less than the string or variable on the right. @@ -127,15 +137,31 @@ Possible expressions are: True if the given string or variable's value is lexicographically equal to the string or variable on the right. +``if( STRLESS_EQUAL )`` + True if the given string or variable's value is lexicographically less + than or equal to the string or variable on the right. + +``if( STRGREATER_EQUAL )`` + True if the given string or variable's value is lexicographically greater + than or equal to the string or variable on the right. + ``if( VERSION_LESS )`` Component-wise integer version number comparison (version format is ``major[.minor[.patch[.tweak]]]``). +``if( VERSION_GREATER )`` + Component-wise integer version number comparison (version format is + ``major[.minor[.patch[.tweak]]]``). + ``if( VERSION_EQUAL )`` Component-wise integer version number comparison (version format is ``major[.minor[.patch[.tweak]]]``). -``if( VERSION_GREATER )`` +``if( VERSION_LESS_EQUAL )`` + Component-wise integer version number comparison (version format is + ``major[.minor[.patch[.tweak]]]``). + +``if( VERSION_GREATER_EQUAL )`` Component-wise integer version number comparison (version format is ``major[.minor[.patch[.tweak]]]``). @@ -186,20 +212,21 @@ above-documented signature accepts ````: * If the left hand argument to ``MATCHES`` is missing it returns false without error -* Both left and right hand arguments to ``LESS``, ``GREATER``, and - ``EQUAL`` are independently tested to see if they are defined - variables, if so their defined values are used otherwise the original - value is used. +* Both left and right hand arguments to ``LESS``, ``GREATER``, ``EQUAL``, + ``LESS_EQUAL``, and ``GREATER_EQUAL``, are independently tested to see if + they are defined variables, if so their defined values are used otherwise + the original value is used. -* Both left and right hand arguments to ``STRLESS``, ``STREQUAL``, and - ``STRGREATER`` are independently tested to see if they are defined - variables, if so their defined values are used otherwise the original - value is used. +* Both left and right hand arguments to ``STRLESS``, ``STRGREATER``, + ``STREQUAL``, ``STRLESS_EQUAL``, and ``STRGREATER_EQUAL`` are independently + tested to see if they are defined variables, if so their defined values are + used otherwise the original value is used. * Both left and right hand arguments to ``VERSION_LESS``, - ``VERSION_EQUAL``, and ``VERSION_GREATER`` are independently tested - to see if they are defined variables, if so their defined values are - used otherwise the original value is used. + ``VERSION_GREATER``, ``VERSION_EQUAL``, ``VERSION_LESS_EQUAL``, and + ``VERSION_GREATER_EQUAL`` are independently tested to see if they are defined + variables, if so their defined values are used otherwise the original value + is used. * The right hand argument to ``NOT`` is tested to see if it is a boolean constant, if so the value is used, otherwise it is assumed to be a diff --git a/Help/command/string.rst b/Help/command/string.rst index 3f4050e..19a095a 100644 --- a/Help/command/string.rst +++ b/Help/command/string.rst @@ -197,10 +197,12 @@ Comparison :: - string(COMPARE EQUAL ) - string(COMPARE NOTEQUAL ) string(COMPARE LESS ) string(COMPARE GREATER ) + string(COMPARE EQUAL ) + string(COMPARE NOTEQUAL ) + string(COMPARE LESS_EQUAL ) + string(COMPARE GREATER_EQUAL ) Compare the strings and store true or false in the output variable. diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index d4f47dd..64d15a9 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -66,12 +66,16 @@ Available logical expressions are: ``1`` if the CMake-id of the C compiler matches ``comp``, otherwise ``0``. ``$`` ``1`` if the CMake-id of the CXX compiler matches ``comp``, otherwise ``0``. -``$`` - ``1`` if ``v1`` is a version greater than ``v2``, else ``0``. ``$`` ``1`` if ``v1`` is a version less than ``v2``, else ``0``. +``$`` + ``1`` if ``v1`` is a version greater than ``v2``, else ``0``. ``$`` ``1`` if ``v1`` is the same version as ``v2``, else ``0``. +``$`` + ``1`` if ``v1`` is a version less than or equal to ``v2``, else ``0``. +``$`` + ``1`` if ``v1`` is a version greater than or equal to ``v2``, else ``0``. ``$`` ``1`` if the version of the C compiler matches ``ver``, otherwise ``0``. ``$`` diff --git a/Help/release/dev/add-extra-boolean-comparisons.rst b/Help/release/dev/add-extra-boolean-comparisons.rst new file mode 100644 index 0000000..a928994 --- /dev/null +++ b/Help/release/dev/add-extra-boolean-comparisons.rst @@ -0,0 +1,6 @@ +add-extra-boolean-comparisons +----------------------------- + +* The :command:`if` command gained new boolean comparison operations + ``LESS_EQUAL``, ``GREATER_EQUAL``, ``STRLESS_EQUAL``, ``STRGREATER_EQUAL``, + ``VERSION_LESS_EQUAL``, and ``VERSION_GREATER_EQUAL``. diff --git a/Help/variable/CMAKE_VERSION.rst b/Help/variable/CMAKE_VERSION.rst index bbb1d91..872e2fa 100644 --- a/Help/variable/CMAKE_VERSION.rst +++ b/Help/variable/CMAKE_VERSION.rst @@ -26,11 +26,11 @@ Individual component values are also available in variables: * :variable:`CMAKE_PATCH_VERSION` * :variable:`CMAKE_TWEAK_VERSION` -Use the :command:`if` command ``VERSION_LESS``, ``VERSION_EQUAL``, or -``VERSION_GREATER`` operators to compare version string values against -``CMAKE_VERSION`` using a component-wise test. Version component -values may be 10 or larger so do not attempt to compare version -strings as floating-point numbers. +Use the :command:`if` command ``VERSION_LESS``, ``VERSION_GREATER``, +``VERSION_EQUAL``, ``VERSION_LESS_EQUAL``, or ``VERSION_GREATER_EQUAL`` +operators to compare version string values against ``CMAKE_VERSION`` using a +component-wise test. Version component values may be 10 or larger so do not +attempt to compare version strings as floating-point numbers. .. note:: diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 0101049..8a856a8 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -366,11 +366,8 @@ bool cmCTest::ShouldCompressTestOutput() if (!this->ComputedCompressTestOutput) { std::string cdashVersion = this->GetCDashVersion(); // version >= 1.6? - bool cdashSupportsGzip = - cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, - cdashVersion.c_str(), "1.6") || - cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, - cdashVersion.c_str(), "1.6"); + bool cdashSupportsGzip = cmSystemTools::VersionCompare( + cmSystemTools::OP_GREATER_EQUAL, cdashVersion.c_str(), "1.6"); this->CompressTestOutput &= cdashSupportsGzip; this->ComputedCompressTestOutput = true; } diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index e02221c..d7532b3 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -21,12 +21,14 @@ static std::string const keyDEFINED = "DEFINED"; static std::string const keyEQUAL = "EQUAL"; static std::string const keyEXISTS = "EXISTS"; static std::string const keyGREATER = "GREATER"; +static std::string const keyGREATER_EQUAL = "GREATER_EQUAL"; static std::string const keyIN_LIST = "IN_LIST"; static std::string const keyIS_ABSOLUTE = "IS_ABSOLUTE"; static std::string const keyIS_DIRECTORY = "IS_DIRECTORY"; static std::string const keyIS_NEWER_THAN = "IS_NEWER_THAN"; static std::string const keyIS_SYMLINK = "IS_SYMLINK"; static std::string const keyLESS = "LESS"; +static std::string const keyLESS_EQUAL = "LESS_EQUAL"; static std::string const keyMATCHES = "MATCHES"; static std::string const keyNOT = "NOT"; static std::string const keyOR = "OR"; @@ -35,12 +37,16 @@ static std::string const keyParenR = ")"; static std::string const keyPOLICY = "POLICY"; static std::string const keySTREQUAL = "STREQUAL"; static std::string const keySTRGREATER = "STRGREATER"; +static std::string const keySTRGREATER_EQUAL = "STRGREATER_EQUAL"; static std::string const keySTRLESS = "STRLESS"; +static std::string const keySTRLESS_EQUAL = "STRLESS_EQUAL"; static std::string const keyTARGET = "TARGET"; static std::string const keyTEST = "TEST"; static std::string const keyVERSION_EQUAL = "VERSION_EQUAL"; static std::string const keyVERSION_GREATER = "VERSION_GREATER"; +static std::string const keyVERSION_GREATER_EQUAL = "VERSION_GREATER_EQUAL"; static std::string const keyVERSION_LESS = "VERSION_LESS"; +static std::string const keyVERSION_LESS_EQUAL = "VERSION_LESS_EQUAL"; cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile, const cmListFileContext& context, @@ -559,7 +565,9 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, if (argP1 != newArgs.end() && argP2 != newArgs.end() && (this->IsKeyword(keyLESS, *argP1) || + this->IsKeyword(keyLESS_EQUAL, *argP1) || this->IsKeyword(keyGREATER, *argP1) || + this->IsKeyword(keyGREATER_EQUAL, *argP1) || this->IsKeyword(keyEQUAL, *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); @@ -570,8 +578,12 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, result = false; } else if (*(argP1) == keyLESS) { result = (lhs < rhs); + } else if (*(argP1) == keyLESS_EQUAL) { + result = (lhs <= rhs); } else if (*(argP1) == keyGREATER) { result = (lhs > rhs); + } else if (*(argP1) == keyGREATER_EQUAL) { + result = (lhs >= rhs); } else { result = (lhs == rhs); } @@ -580,16 +592,22 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, if (argP1 != newArgs.end() && argP2 != newArgs.end() && (this->IsKeyword(keySTRLESS, *argP1) || - this->IsKeyword(keySTREQUAL, *argP1) || - this->IsKeyword(keySTRGREATER, *argP1))) { + this->IsKeyword(keySTRLESS_EQUAL, *argP1) || + this->IsKeyword(keySTRGREATER, *argP1) || + this->IsKeyword(keySTRGREATER_EQUAL, *argP1) || + this->IsKeyword(keySTREQUAL, *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); int val = strcmp(def, def2); bool result; if (*(argP1) == keySTRLESS) { result = (val < 0); + } else if (*(argP1) == keySTRLESS_EQUAL) { + result = (val <= 0); } else if (*(argP1) == keySTRGREATER) { result = (val > 0); + } else if (*(argP1) == keySTRGREATER_EQUAL) { + result = (val >= 0); } else // strequal { result = (val == 0); @@ -599,15 +617,23 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, if (argP1 != newArgs.end() && argP2 != newArgs.end() && (this->IsKeyword(keyVERSION_LESS, *argP1) || + this->IsKeyword(keyVERSION_LESS_EQUAL, *argP1) || this->IsKeyword(keyVERSION_GREATER, *argP1) || + this->IsKeyword(keyVERSION_GREATER_EQUAL, *argP1) || this->IsKeyword(keyVERSION_EQUAL, *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); - cmSystemTools::CompareOp op = cmSystemTools::OP_EQUAL; + cmSystemTools::CompareOp op; if (*argP1 == keyVERSION_LESS) { op = cmSystemTools::OP_LESS; + } else if (*argP1 == keyVERSION_LESS_EQUAL) { + op = cmSystemTools::OP_LESS_EQUAL; } else if (*argP1 == keyVERSION_GREATER) { op = cmSystemTools::OP_GREATER; + } else if (*argP1 == keyVERSION_GREATER_EQUAL) { + op = cmSystemTools::OP_GREATER_EQUAL; + } else { // version_equal + op = cmSystemTools::OP_EQUAL; } bool result = cmSystemTools::VersionCompare(op, def, def2); this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2); diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index ca7250b..6e2b16a 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -545,6 +545,25 @@ static const struct VersionGreaterNode : public cmGeneratorExpressionNode } } versionGreaterNode; +static const struct VersionGreaterEqNode : public cmGeneratorExpressionNode +{ + VersionGreaterEqNode() {} + + int NumExpectedParameters() const CM_OVERRIDE { return 2; } + + std::string Evaluate(const std::vector& parameters, + cmGeneratorExpressionContext*, + const GeneratorExpressionContent*, + cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + { + return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, + parameters.front().c_str(), + parameters[1].c_str()) + ? "1" + : "0"; + } +} versionGreaterEqNode; + static const struct VersionLessNode : public cmGeneratorExpressionNode { VersionLessNode() {} @@ -564,6 +583,25 @@ static const struct VersionLessNode : public cmGeneratorExpressionNode } } versionLessNode; +static const struct VersionLessEqNode : public cmGeneratorExpressionNode +{ + VersionLessEqNode() {} + + int NumExpectedParameters() const CM_OVERRIDE { return 2; } + + std::string Evaluate(const std::vector& parameters, + cmGeneratorExpressionContext*, + const GeneratorExpressionContent*, + cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + { + return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS_EQUAL, + parameters.front().c_str(), + parameters[1].c_str()) + ? "1" + : "0"; + } +} versionLessEqNode; + static const struct VersionEqualNode : public cmGeneratorExpressionNode { VersionEqualNode() {} @@ -1641,7 +1679,9 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( nodeMap["C_COMPILER_ID"] = &cCompilerIdNode; nodeMap["CXX_COMPILER_ID"] = &cxxCompilerIdNode; nodeMap["VERSION_GREATER"] = &versionGreaterNode; + nodeMap["VERSION_GREATER_EQUAL"] = &versionGreaterEqNode; nodeMap["VERSION_LESS"] = &versionLessNode; + nodeMap["VERSION_LESS_EQUAL"] = &versionLessEqNode; nodeMap["VERSION_EQUAL"] = &versionEqualNode; nodeMap["C_COMPILER_VERSION"] = &cCompilerVersionNode; nodeMap["CXX_COMPILER_VERSION"] = &cxxCompilerVersionNode; diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index dce4687..3c913ee 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -485,7 +485,8 @@ bool cmStringCommand::HandleCompareCommand( } std::string mode = args[1]; if ((mode == "EQUAL") || (mode == "NOTEQUAL") || (mode == "LESS") || - (mode == "GREATER")) { + (mode == "LESS_EQUAL") || (mode == "GREATER") || + (mode == "GREATER_EQUAL")) { if (args.size() < 5) { std::string e = "sub-command COMPARE, mode "; e += mode; @@ -500,8 +501,12 @@ bool cmStringCommand::HandleCompareCommand( bool result; if (mode == "LESS") { result = (left < right); + } else if (mode == "LESS_EQUAL") { + result = (left <= right); } else if (mode == "GREATER") { result = (left > right); + } else if (mode == "GREATER_EQUAL") { + result = (left >= right); } else if (mode == "EQUAL") { result = (left == right); } else // if(mode == "NOTEQUAL") diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 9740ef7..5745a01 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -2380,10 +2380,10 @@ bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op, if (lhs < rhs) { // lhs < rhs, so true if operation is LESS - return op == cmSystemTools::OP_LESS; + return (op & cmSystemTools::OP_LESS) != 0; } else if (lhs > rhs) { // lhs > rhs, so true if operation is GREATER - return op == cmSystemTools::OP_GREATER; + return (op & cmSystemTools::OP_GREATER) != 0; } if (*endr == '.') { @@ -2395,7 +2395,7 @@ bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op, } } // lhs == rhs, so true if operation is EQUAL - return op == cmSystemTools::OP_EQUAL; + return (op & cmSystemTools::OP_EQUAL) != 0; } bool cmSystemTools::VersionCompareEqual(std::string const& lhs, @@ -2412,6 +2412,13 @@ bool cmSystemTools::VersionCompareGreater(std::string const& lhs, rhs.c_str()); } +bool cmSystemTools::VersionCompareGreaterEq(std::string const& lhs, + std::string const& rhs) +{ + return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, + lhs.c_str(), rhs.c_str()); +} + bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, bool* removed) { diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 39e7994..d0a28e1 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -284,9 +284,11 @@ public: enum CompareOp { - OP_LESS, - OP_GREATER, - OP_EQUAL + OP_EQUAL = 1, + OP_LESS = 2, + OP_GREATER = 4, + OP_LESS_EQUAL = OP_LESS | OP_EQUAL, + OP_GREATER_EQUAL = OP_GREATER | OP_EQUAL }; /** @@ -297,6 +299,8 @@ public: std::string const& rhs); static bool VersionCompareGreater(std::string const& lhs, std::string const& rhs); + static bool VersionCompareGreaterEq(std::string const& lhs, + std::string const& rhs); /** * Determine the file type based on the extension diff --git a/Tests/CMakeTests/VersionTest.cmake.in b/Tests/CMakeTests/VersionTest.cmake.in index 4e946ab..f045605 100644 --- a/Tests/CMakeTests/VersionTest.cmake.in +++ b/Tests/CMakeTests/VersionTest.cmake.in @@ -83,10 +83,24 @@ foreach(v IN LISTS LESSV) message(FATAL_ERROR "${CMAKE_MATCH_2} is less than ${CMAKE_MATCH_1}?") endif() + # check greater or equal (same as less negative) + if(CMAKE_MATCH_2 VERSION_GREATER_EQUAL CMAKE_MATCH_1) + message(STATUS "${CMAKE_MATCH_2} is not less than ${CMAKE_MATCH_1}") + else() + message(FATAL_ERROR "${CMAKE_MATCH_2} is less than ${CMAKE_MATCH_1}?") + endif() + # check greater negative case if(NOT CMAKE_MATCH_1 VERSION_GREATER CMAKE_MATCH_2) message(STATUS "${CMAKE_MATCH_1} is not greater than ${CMAKE_MATCH_2}") else() message(FATAL_ERROR "${CMAKE_MATCH_1} is greater than ${CMAKE_MATCH_2}?") endif() + + # check less or equal (same as greater negative) case + if(CMAKE_MATCH_1 VERSION_LESS_EQUAL CMAKE_MATCH_2) + message(STATUS "${CMAKE_MATCH_1} is not greater than ${CMAKE_MATCH_2}") + else() + message(FATAL_ERROR "${CMAKE_MATCH_1} is greater than ${CMAKE_MATCH_2}?") + endif() endforeach() diff --git a/Tests/CTestTestStopTime/GetDate.cmake b/Tests/CTestTestStopTime/GetDate.cmake index edc6519..1f4cb24 100644 --- a/Tests/CTestTestStopTime/GetDate.cmake +++ b/Tests/CTestTestStopTime/GetDate.cmake @@ -106,11 +106,11 @@ macro(ADD_SECONDS sec) set(new_min ${${GD_PREFIX}MINUTE}) set(new_hr ${${GD_PREFIX}HOUR}) math(EXPR new_sec "${sec} + ${${GD_PREFIX}SECOND}") - while(${new_sec} GREATER 60 OR ${new_sec} EQUAL 60) + while(${new_sec} GREATER_EQUAL 60) math(EXPR new_sec "${new_sec} - 60") math(EXPR new_min "${${GD_PREFIX}MINUTE} + 1") endwhile() - while(${new_min} GREATER 60 OR ${new_min} EQUAL 60) + while(${new_min} GREATER_EQUAL 60) math(EXPR new_min "${new_min} - 60") math(EXPR new_hr "${${GD_PREFIX}HOUR} + 1") endwhile() diff --git a/Tests/Complex/CMakeLists.txt b/Tests/Complex/CMakeLists.txt index 80cc2e3..075faa7 100644 --- a/Tests/Complex/CMakeLists.txt +++ b/Tests/Complex/CMakeLists.txt @@ -92,6 +92,12 @@ endif() if(NOT 2.4 EQUAL 2.4) message(FATAL_ERROR "Failed: NOT 2.4 EQUAL 2.4") endif() +if(NOT 2.4 LESS_EQUAL 2.4) + message(FATAL_ERROR "Failed: NOT 2.4 LESS_EQUAL 2.4") +endif() +if(NOT 2.4 GREATER_EQUAL 2.4) + message(FATAL_ERROR "Failed: NOT 2.4 GREATER_EQUAL 2.4") +endif() if(CMAKE_SYSTEM MATCHES "OSF1-V") if(NOT CMAKE_COMPILER_IS_GNUCXX) diff --git a/Tests/Complex/Executable/complex.cxx b/Tests/Complex/Executable/complex.cxx index 5f79ac0..3b09229 100644 --- a/Tests/Complex/Executable/complex.cxx +++ b/Tests/Complex/Executable/complex.cxx @@ -455,7 +455,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_LESS - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS is not defined."); #else cmPassed("SHOULD_BE_DEFINED_LESS is defined."); #endif @@ -467,7 +467,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_LESS2 - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS2 is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_LESS2 is defined."); #endif @@ -478,6 +478,24 @@ int main() cmPassed("SHOULD_NOT_BE_DEFINED_GREATER is not defined."); #endif +#ifndef SHOULD_BE_DEFINED_GREATER + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); +#endif + #ifdef SHOULD_NOT_BE_DEFINED_EQUAL cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_EQUAL is defined."); #else @@ -485,28 +503,93 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_EQUAL - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_EQUAL is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_EQUAL is not defined."); #else cmPassed("SHOULD_BE_DEFINED_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined.\n"); +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL is not defined."); #endif -#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 - cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL is not defined."); #else - cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER2 +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL3 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRLESS @@ -516,7 +599,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS is defined."); #endif @@ -528,8 +611,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS2 - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS2 is defined."); #endif @@ -543,7 +625,7 @@ int main() #ifndef SHOULD_BE_DEFINED_STRGREATER cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined.\n"); + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER is defined."); #endif @@ -557,11 +639,95 @@ int main() #ifndef SHOULD_BE_DEFINED_STRGREATER2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER2 is defined."); #endif +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is " + "defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is not " + "defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is " + "defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is not " + "defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is defined."); +#endif + // ---------------------------------------------------------------------- // Test FOREACH diff --git a/Tests/Complex/VarTests.cmake b/Tests/Complex/VarTests.cmake index 9d35949..8be59be 100644 --- a/Tests/Complex/VarTests.cmake +++ b/Tests/Complex/VarTests.cmake @@ -126,6 +126,12 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER) endif () +if (SNUM1_VAR GREATER SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER2) +endif () + if (SNUM2_VAR EQUAL SNUM1_VAR) add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) else () @@ -138,10 +144,40 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) endif () -if (SNUM1_VAR GREATER SNUM2_VAR) - add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +if (SNUM1_VAR LESS_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL) else () - add_definitions(-DSHOULD_BE_DEFINED_GREATER2) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL) +endif () + +if (SNUM2_VAR LESS_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL2) +endif () + +if (SNUM1_VAR LESS_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL3) +else () + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL3) +endif () + +if (SNUM2_VAR GREATER_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL2) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL3) endif () set (SSTR1_VAR "abc") @@ -171,6 +207,42 @@ else () add_definitions(-DSHOULD_BE_DEFINED_STRGREATER2) endif () +if (SSTR1_VAR STRLESS_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL) +endif () + +if (SSTR2_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL2) +endif () + +if (SSTR1_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3) +endif () + +if (SSTR2_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL2) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3) +endif () + # # Test FOREACH # diff --git a/Tests/ComplexOneConfig/Executable/complex.cxx b/Tests/ComplexOneConfig/Executable/complex.cxx index 5f79ac0..9e4eaad 100644 --- a/Tests/ComplexOneConfig/Executable/complex.cxx +++ b/Tests/ComplexOneConfig/Executable/complex.cxx @@ -478,6 +478,24 @@ int main() cmPassed("SHOULD_NOT_BE_DEFINED_GREATER is not defined."); #endif +#ifndef SHOULD_BE_DEFINED_GREATER + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined.\n"); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER2 + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); +#endif + #ifdef SHOULD_NOT_BE_DEFINED_EQUAL cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_EQUAL is defined."); #else @@ -490,23 +508,88 @@ int main() cmPassed("SHOULD_BE_DEFINED_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined.\n"); +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL is not defined."); #endif -#ifdef SHOULD_NOT_BE_DEFINED_GREATER2 - cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined."); +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL is not defined."); #else - cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined."); + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL is defined."); #endif -#ifndef SHOULD_BE_DEFINED_GREATER2 +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is defined."); #else - cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined."); + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_LESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL3 is defined."); #endif #ifdef SHOULD_NOT_BE_DEFINED_STRLESS @@ -516,7 +599,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS - cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS is defined."); #endif @@ -528,8 +611,7 @@ int main() #endif #ifndef SHOULD_BE_DEFINED_STRLESS2 - cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined.\n"); + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRLESS2 is defined."); #endif @@ -543,7 +625,7 @@ int main() #ifndef SHOULD_BE_DEFINED_STRGREATER cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined.\n"); + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER is defined."); #endif @@ -557,11 +639,95 @@ int main() #ifndef SHOULD_BE_DEFINED_STRGREATER2 cmFailed( - "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined.\n"); + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined."); #else cmPassed("SHOULD_BE_DEFINED_STRGREATER2 is defined."); #endif +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL2 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL2 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL3 + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL3 is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL3 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL + cmFailed( + "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL is not defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is " + "defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL2 + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is not " + "defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is defined."); +#endif + +#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is " + "defined."); +#else + cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is not defined."); +#endif + +#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL3 + cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is not " + "defined."); +#else + cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is defined."); +#endif + // ---------------------------------------------------------------------- // Test FOREACH diff --git a/Tests/ComplexOneConfig/VarTests.cmake b/Tests/ComplexOneConfig/VarTests.cmake index 9d35949..7dd8519 100644 --- a/Tests/ComplexOneConfig/VarTests.cmake +++ b/Tests/ComplexOneConfig/VarTests.cmake @@ -126,6 +126,12 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER) endif () +if (SNUM1_VAR GREATER SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER2) +endif () + if (SNUM2_VAR EQUAL SNUM1_VAR) add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) else () @@ -138,10 +144,40 @@ else () add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL) endif () -if (SNUM1_VAR GREATER SNUM2_VAR) - add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2) +if (SNUM1_VAR LESS_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL) else () - add_definitions(-DSHOULD_BE_DEFINED_GREATER2) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL) +endif () + +if (SNUM2_VAR LESS_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL2) +endif () + +if (SNUM1_VAR LESS_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL3) +endif () + +if (SNUM2_VAR GREATER_EQUAL SNUM1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL2) +endif () + +if (SNUM1_VAR GREATER_EQUAL SNUM3_VAR) + add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL3) endif () set (SSTR1_VAR "abc") @@ -171,6 +207,42 @@ else () add_definitions(-DSHOULD_BE_DEFINED_STRGREATER2) endif () +if (SSTR1_VAR STRLESS_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL) +endif () + +if (SSTR2_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL2) +endif () + +if (SSTR1_VAR STRLESS_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3) +endif () + +if (SSTR2_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR2_VAR) + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2) +else () + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL2) +endif () + +if (SSTR1_VAR STRGREATER_EQUAL SSTR1_VAR) + add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL3) +else () + add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3) +endif () + # # Test FOREACH # ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 9 10:10:22 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 9 Aug 2016 10:10:22 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1198-g0ed4b78 Message-ID: <20160809141022.481ECF2ECE@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 0ed4b78da380e9c0f2ed5c2489863bfe47124c09 (commit) via c7a319ab057172071bf8fb909c4498ca87b1235a (commit) from 1554a1b92f5fbdde852bc08e5e3534e42a914691 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0ed4b78da380e9c0f2ed5c2489863bfe47124c09 commit 0ed4b78da380e9c0f2ed5c2489863bfe47124c09 Merge: 1554a1b c7a319a Author: Brad King AuthorDate: Tue Aug 9 10:10:21 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 9 10:10:21 2016 -0400 Merge topic 'install-export-staging-dir' into next c7a319ab install(EXPORT): Fix support for mid-length install destinations on Windows https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c7a319ab057172071bf8fb909c4498ca87b1235a commit c7a319ab057172071bf8fb909c4498ca87b1235a Author: Brad King AuthorDate: Tue Aug 9 09:53:16 2016 -0400 Commit: Brad King CommitDate: Tue Aug 9 10:09:52 2016 -0400 install(EXPORT): Fix support for mid-length install destinations on Windows The implementation of `install(EXPORT)` generates files into a staging directory for later installation. We use the full install destination in the path to the staging directory to avoid collisions. In order to avoid exceeding maximum path lengths (especially on Windows) we compute a hash of the install destination when it is too long. Fix this logic to account for the length of the file name(s) when deciding whether to switch to the hashed name. Reported-by: Alan W. Irwin diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index 6250012..0fcd8ba 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -74,9 +74,12 @@ void cmInstallExportGenerator::ComputeTempDir() #else std::string::size_type const max_total_len = 1000; #endif - if (this->TempDir.size() < max_total_len) { + // Will generate files of the form "/-.". + std::string::size_type const len = this->TempDir.size() + 1 + + this->FileName.size() + 1 + this->GetMaxConfigLength(); + if (len < max_total_len) { // Keep the total path length below the limit. - std::string::size_type max_len = max_total_len - this->TempDir.size(); + std::string::size_type const max_len = max_total_len - len; if (this->Destination.size() > max_len) { useMD5 = true; } @@ -102,6 +105,26 @@ void cmInstallExportGenerator::ComputeTempDir() } } +size_t cmInstallExportGenerator::GetMaxConfigLength() const +{ + // Always use at least 8 for "noconfig". + size_t len = 8; + if (this->ConfigurationTypes->empty()) { + if (this->ConfigurationName.size() > 8) { + len = this->ConfigurationName.size(); + } + } else { + for (std::vector::const_iterator ci = + this->ConfigurationTypes->begin(); + ci != this->ConfigurationTypes->end(); ++ci) { + if (ci->size() > len) { + len = ci->size(); + } + } + } + return len; +} + void cmInstallExportGenerator::GenerateScript(std::ostream& os) { // Skip empty sets. diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h index 4435f53..22e661b 100644 --- a/Source/cmInstallExportGenerator.h +++ b/Source/cmInstallExportGenerator.h @@ -53,6 +53,7 @@ protected: void GenerateImportFile(cmExportSet const* exportSet); void GenerateImportFile(const char* config, cmExportSet const* exportSet); void ComputeTempDir(); + size_t GetMaxConfigLength() const; cmExportSet* ExportSet; std::string FilePermissions; ----------------------------------------------------------------------- Summary of changes: Source/cmInstallExportGenerator.cxx | 27 +++++++++++++++++++++++++-- Source/cmInstallExportGenerator.h | 1 + 2 files changed, 26 insertions(+), 2 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 9 11:22:21 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 9 Aug 2016 11:22:21 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1200-ga15e369 Message-ID: <20160809152221.2A03AF560A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via a15e3696ff5b80792bc6de10a27b1826735f1825 (commit) via e9c984267e5539b798a2b1af8431e5715f261cfd (commit) from 0ed4b78da380e9c0f2ed5c2489863bfe47124c09 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a15e3696ff5b80792bc6de10a27b1826735f1825 commit a15e3696ff5b80792bc6de10a27b1826735f1825 Merge: 0ed4b78 e9c9842 Author: Brad King AuthorDate: Tue Aug 9 11:22:20 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 9 11:22:20 2016 -0400 Merge topic 'NAG-Fortran-no-fPIE' into next e9c98426 NAG: Use -PIC for Fortran position-independent executable code https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e9c984267e5539b798a2b1af8431e5715f261cfd commit e9c984267e5539b798a2b1af8431e5715f261cfd Author: Neil Carlson AuthorDate: Tue Aug 9 11:14:13 2016 -0400 Commit: Brad King CommitDate: Tue Aug 9 11:15:14 2016 -0400 NAG: Use -PIC for Fortran position-independent executable code The Numerical Algorithms Group (NAG) Fortran compiler documents -PIC for position-independent code and does not have a separate option for PIE. We added `-PIC` for PIC in commit v2.8.11~174^2 (NAG: Use -PIC for Fortran position-independent code, 2013-02-18). Follow up for PIE. Closes: #16236 diff --git a/Modules/Compiler/NAG-Fortran.cmake b/Modules/Compiler/NAG-Fortran.cmake index 18f141e..39aae18 100644 --- a/Modules/Compiler/NAG-Fortran.cmake +++ b/Modules/Compiler/NAG-Fortran.cmake @@ -33,3 +33,4 @@ set(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "-PIC") set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-fixed") set(CMAKE_Fortran_FORMAT_FREE_FLAG "-free") set(CMAKE_Fortran_COMPILE_OPTIONS_PIC "-PIC") +set(CMAKE_Fortran_COMPILE_OPTIONS_PIE "-PIC") ----------------------------------------------------------------------- Summary of changes: Modules/Compiler/NAG-Fortran.cmake | 1 + 1 file changed, 1 insertion(+) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 9 15:16:02 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 9 Aug 2016 15:16:02 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1203-gc056653 Message-ID: <20160809191602.7E794F4CA8@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via c0566538859b568a58f23eabe12e49ff2370a140 (commit) via 0278989405eea53ca7e5f1bfa6af9aea7a0b49c5 (commit) via a88c99f1bc301276a1780fec683d5061ca13f66f (commit) from a15e3696ff5b80792bc6de10a27b1826735f1825 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c0566538859b568a58f23eabe12e49ff2370a140 commit c0566538859b568a58f23eabe12e49ff2370a140 Merge: a15e369 0278989 Author: Brad King AuthorDate: Tue Aug 9 15:15:59 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 9 15:15:59 2016 -0400 Merge topic 'ninja-directory-targets' into next 02789894 Ninja: Add `$subdir/{test,install,package}` targets a88c99f1 Ninja: Simplify computation of GLOBAL_TARGET outputs https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0278989405eea53ca7e5f1bfa6af9aea7a0b49c5 commit 0278989405eea53ca7e5f1bfa6af9aea7a0b49c5 Author: Brad King AuthorDate: Fri Aug 5 15:55:32 2016 -0400 Commit: Brad King CommitDate: Tue Aug 9 15:15:24 2016 -0400 Ninja: Add `$subdir/{test,install,package}` targets With the Makefile generator one can use `cd $subdir; make install` to build and install targets associated with a given subdirectory. This is not possible to do with the Ninja generator since there is only one `build.ninja` file at the top of the build tree. However, we can approximate it by allowing one to run `ninja $subdir/install` at the top of the tree to build the targets in the corresponding subdirectory and install them. This also makes sense for `test`, `package`, and other GLOBAL_TARGET targets. It was already done for `all` by commit v3.6.0-rc1~240^2~2 (Ninja: Add `$subdir/all` targets, 2016-03-11). diff --git a/Help/generator/Ninja.rst b/Help/generator/Ninja.rst index d94e5f6..ef0e28b 100644 --- a/Help/generator/Ninja.rst +++ b/Help/generator/Ninja.rst @@ -7,6 +7,17 @@ A build.ninja file is generated into the build tree. Recent versions of the ninja program can build the project through the "all" target. An "install" target is also provided. -For each subdirectory ``sub/dir`` of the project an additional target -named ``sub/dir/all`` is generated that depends on all targets required -by that subdirectory. +For each subdirectory ``sub/dir`` of the project, additional targets +are generated: + +``sub/dir/all`` + Depends on all targets required by the subdirectory. + +``sub/dir/install`` + Runs the install step in the subdirectory, if any. + +``sub/dir/test`` + Runs the test step in the subdirectory, if any. + +``sub/dir/package`` + Runs the package step in the subdirectory, if any. diff --git a/Help/release/dev/ninja-directory-targets.rst b/Help/release/dev/ninja-directory-targets.rst new file mode 100644 index 0000000..c4269d8 --- /dev/null +++ b/Help/release/dev/ninja-directory-targets.rst @@ -0,0 +1,8 @@ +ninja-directory-targets +----------------------- + +* The :generator:`Ninja` generator learned to produce phony targets + of the form ``sub/dir/{test,install,package}`` to drive the build + of a subdirectory installation, test or packaging target. + This is equivalent to ``cd sub/dir; make {test,install,package}`` + with :ref:`Makefile Generators`. diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index afd43b8..3b8aaa6 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -885,10 +885,15 @@ void cmGlobalNinjaGenerator::AppendTargetDepends( cmGeneratorTarget const* target, cmNinjaDeps& outputs) { if (target->GetType() == cmState::GLOBAL_TARGET) { - // Global targets only depend on other utilities, which may not appear in - // the TargetDepends set (e.g. "all"). + // These depend only on other CMake-provided targets, e.g. "all". std::set const& utils = target->GetUtilities(); - std::copy(utils.begin(), utils.end(), std::back_inserter(outputs)); + for (std::set::const_iterator i = utils.begin(); + i != utils.end(); ++i) { + std::string d = + target->GetLocalGenerator()->GetCurrentBinaryDirectory() + + std::string("/") + *i; + outputs.push_back(this->ConvertToNinjaPath(d)); + } } else { cmNinjaDeps outs; cmTargetDependSet const& targetDeps = this->GetTargetDirectDepends(target); diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 1466f8a..9030e05 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -38,19 +38,8 @@ cmNinjaTargetGenerator* cmNinjaTargetGenerator::New(cmGeneratorTarget* target) return new cmNinjaNormalTargetGenerator(target); case cmState::UTILITY: + case cmState::GLOBAL_TARGET: return new cmNinjaUtilityTargetGenerator(target); - ; - - case cmState::GLOBAL_TARGET: { - // We only want to process global targets that live in the home - // (i.e. top-level) directory. CMake creates copies of these targets - // in every directory, which we don't need. - if (strcmp(target->GetLocalGenerator()->GetCurrentSourceDirectory(), - target->GetLocalGenerator()->GetSourceDirectory()) == 0) { - return new cmNinjaUtilityTargetGenerator(target); - } - // else fallthrough - } default: return CM_NULLPTR; diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx index c549646..96a17ff 100644 --- a/Source/cmNinjaUtilityTargetGenerator.cxx +++ b/Source/cmNinjaUtilityTargetGenerator.cxx @@ -31,10 +31,12 @@ cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator() void cmNinjaUtilityTargetGenerator::Generate() { - std::string utilCommandName = cmake::GetCMakeFilesDirectoryPostSlash(); + std::string utilCommandName = + this->GetLocalGenerator()->GetCurrentBinaryDirectory(); + utilCommandName += cmake::GetCMakeFilesDirectory(); + utilCommandName += "/"; utilCommandName += this->GetTargetName() + ".util"; - utilCommandName = - this->GetGlobalGenerator()->NinjaOutputPath(utilCommandName); + utilCommandName = this->ConvertToNinjaPath(utilCommandName); std::vector commands; cmNinjaDeps deps, outputs, util_outputs(1, utilCommandName); @@ -144,6 +146,11 @@ void cmNinjaUtilityTargetGenerator::Generate() cmNinjaDeps(1, utilCommandName)); } - this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(), - this->GetGeneratorTarget()); + // Add an alias for the logical target name regardless of what directory + // contains it. Skip this for GLOBAL_TARGET because they are meant to + // be per-directory and have one at the top-level anyway. + if (this->GetGeneratorTarget()->GetType() != cmState::GLOBAL_TARGET) { + this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(), + this->GetGeneratorTarget()); + } } diff --git a/Tests/RunCMake/Ninja/RunCMakeTest.cmake b/Tests/RunCMake/Ninja/RunCMakeTest.cmake index c73f852..622c327 100644 --- a/Tests/RunCMake/Ninja/RunCMakeTest.cmake +++ b/Tests/RunCMake/Ninja/RunCMakeTest.cmake @@ -41,10 +41,16 @@ function(run_SubDir) run_cmake(SubDir) if(WIN32) set(SubDir_all [[SubDir\all]]) + set(SubDir_test [[SubDir\test]]) + set(SubDir_install [[SubDir\install]]) else() set(SubDir_all [[SubDir/all]]) + set(SubDir_test [[SubDir/test]]) + set(SubDir_install [[SubDir/install]]) endif() run_cmake_command(SubDir-build ${CMAKE_COMMAND} --build . --target ${SubDir_all}) + run_cmake_command(SubDir-test ${CMAKE_COMMAND} --build . --target ${SubDir_test}) + run_cmake_command(SubDir-install ${CMAKE_COMMAND} --build . --target ${SubDir_install}) endfunction() run_SubDir() diff --git a/Tests/RunCMake/Ninja/SubDir-install-stdout.txt b/Tests/RunCMake/Ninja/SubDir-install-stdout.txt new file mode 100644 index 0000000..4261b0e --- /dev/null +++ b/Tests/RunCMake/Ninja/SubDir-install-stdout.txt @@ -0,0 +1 @@ +-- Installing SubDir diff --git a/Tests/RunCMake/Ninja/SubDir-test-stdout.txt b/Tests/RunCMake/Ninja/SubDir-test-stdout.txt new file mode 100644 index 0000000..9c493ac --- /dev/null +++ b/Tests/RunCMake/Ninja/SubDir-test-stdout.txt @@ -0,0 +1 @@ +1/1 Test #1: SubDirTest diff --git a/Tests/RunCMake/Ninja/SubDir.cmake b/Tests/RunCMake/Ninja/SubDir.cmake index 7224ec3..d227753 100644 --- a/Tests/RunCMake/Ninja/SubDir.cmake +++ b/Tests/RunCMake/Ninja/SubDir.cmake @@ -1,2 +1,7 @@ +include(CTest) add_subdirectory(SubDir) add_custom_target(TopFail ALL COMMAND does_not_exist) +add_test(NAME TopTest COMMAND ${CMAKE_COMMAND} -E echo "Running TopTest") +install(CODE [[ + message(FATAL_ERROR "Installing Top") +]]) diff --git a/Tests/RunCMake/Ninja/SubDir/CMakeLists.txt b/Tests/RunCMake/Ninja/SubDir/CMakeLists.txt index 73ae431..456c1db 100644 --- a/Tests/RunCMake/Ninja/SubDir/CMakeLists.txt +++ b/Tests/RunCMake/Ninja/SubDir/CMakeLists.txt @@ -1,2 +1,6 @@ add_custom_target(SubFail COMMAND does_not_exist) add_custom_target(InAll ALL COMMAND ${CMAKE_COMMAND} -E echo "Building InAll") +add_test(NAME SubDirTest COMMAND ${CMAKE_COMMAND} -E echo "Running SubDirTest") +install(CODE [[ + message(STATUS "Installing SubDir") +]]) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a88c99f1bc301276a1780fec683d5061ca13f66f commit a88c99f1bc301276a1780fec683d5061ca13f66f Author: Brad King AuthorDate: Fri Aug 5 14:58:16 2016 -0400 Commit: Brad King CommitDate: Tue Aug 9 14:36:04 2016 -0400 Ninja: Simplify computation of GLOBAL_TARGET outputs In cmGlobalNinjaGenerator::AppendTargetOutputs we previously handled GLOBAL_TARGET outputs specially in order to avoid adding directory components to the output. However, this is not necessary because cmNinjaTargetGenerator::New already filters out copies of these targets that are not at the top level. Instead we can simply follow the same output computation code path as UTILITY targets. diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 44418f2..afd43b8 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -867,6 +867,7 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( break; } case cmState::OBJECT_LIBRARY: + case cmState::GLOBAL_TARGET: case cmState::UTILITY: { std::string path = target->GetLocalGenerator()->GetCurrentBinaryDirectory() + @@ -875,12 +876,6 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( break; } - case cmState::GLOBAL_TARGET: - // Always use the target in HOME instead of an unused duplicate in a - // subdirectory. - outputs.push_back(this->NinjaOutputPath(target->GetName())); - break; - default: return; } ----------------------------------------------------------------------- Summary of changes: Help/generator/Ninja.rst | 17 ++++++++++++++--- Help/release/dev/ninja-directory-targets.rst | 8 ++++++++ Source/cmGlobalNinjaGenerator.cxx | 18 +++++++++--------- Source/cmNinjaTargetGenerator.cxx | 13 +------------ Source/cmNinjaUtilityTargetGenerator.cxx | 17 ++++++++++++----- Tests/RunCMake/Ninja/RunCMakeTest.cmake | 6 ++++++ Tests/RunCMake/Ninja/SubDir-install-stdout.txt | 1 + Tests/RunCMake/Ninja/SubDir-test-stdout.txt | 1 + Tests/RunCMake/Ninja/SubDir.cmake | 5 +++++ Tests/RunCMake/Ninja/SubDir/CMakeLists.txt | 4 ++++ 10 files changed, 61 insertions(+), 29 deletions(-) create mode 100644 Help/release/dev/ninja-directory-targets.rst create mode 100644 Tests/RunCMake/Ninja/SubDir-install-stdout.txt create mode 100644 Tests/RunCMake/Ninja/SubDir-test-stdout.txt hooks/post-receive -- CMake From gjasny at googlemail.com Tue Aug 9 15:25:56 2016 From: gjasny at googlemail.com (Gregor Jasny) Date: Tue, 9 Aug 2016 15:25:56 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1205-g8bbcf86 Message-ID: <20160809192556.A9DCDF55AB@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 8bbcf863e5d24a91a371ee9dec87381d6e09da9f (commit) via 93ac2a78d5e0dbb6607105cc8d2a3f19ebdd8583 (commit) from c0566538859b568a58f23eabe12e49ff2370a140 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8bbcf863e5d24a91a371ee9dec87381d6e09da9f commit 8bbcf863e5d24a91a371ee9dec87381d6e09da9f Merge: c056653 93ac2a7 Author: Gregor Jasny AuthorDate: Tue Aug 9 15:25:55 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 9 15:25:55 2016 -0400 Merge topic '15687-xcode-support-system-include' into next 93ac2a78 Xcode: Obey SYSTEM keyword for includes (#15687) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=93ac2a78d5e0dbb6607105cc8d2a3f19ebdd8583 commit 93ac2a78d5e0dbb6607105cc8d2a3f19ebdd8583 Author: Gregor Jasny AuthorDate: Mon Aug 31 22:33:37 2015 +0200 Commit: Gregor Jasny CommitDate: Tue Aug 9 20:30:07 2016 +0200 Xcode: Obey SYSTEM keyword for includes (#15687) CMake used to put all header search paths into HEADER_SEARCH_PATHS attribute. Unfortunately this attribute does not support to declare a search path as a system include. As a hack one could add a -isystem /path to the cflags but then include ordering is not deterministic. A better approach was chosen with this patch by not filling HEADER_SEARCH_PATHS at all and to populate the C, C++, and Fortran flags directly. The include paths used by Xcode should be now identical to the ones used by Unix Makefiles and Ninja generator. diff --git a/Modules/CMakeSwiftInformation.cmake b/Modules/CMakeSwiftInformation.cmake index 61ad928..85d3143 100644 --- a/Modules/CMakeSwiftInformation.cmake +++ b/Modules/CMakeSwiftInformation.cmake @@ -13,6 +13,7 @@ # License text for the above reference.) set(CMAKE_Swift_OUTPUT_EXTENSION .o) +set(CMAKE_INCLUDE_FLAG_Swift "-I") # Load compiler-specific information. if(CMAKE_Swift_COMPILER_ID) diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index b396ea1..780ca90 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1907,23 +1907,40 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, BuildObjectListOrString dirs(this, this->XcodeVersion >= 30); BuildObjectListOrString fdirs(this, this->XcodeVersion >= 30); - std::vector includes; - this->CurrentLocalGenerator->GetIncludeDirectories(includes, gtgt, "C", - configName); std::set emitted; emitted.insert("/System/Library/Frameworks"); - for (std::vector::iterator i = includes.begin(); - i != includes.end(); ++i) { - if (this->NameResolvesToFramework(i->c_str())) { - std::string frameworkDir = *i; - frameworkDir += "/../"; - frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir); - if (emitted.insert(frameworkDir).second) { - fdirs.Add(this->XCodeEscapePath(frameworkDir)); + + if (this->XcodeVersion < 60) { + std::vector includes; + this->CurrentLocalGenerator->GetIncludeDirectories(includes, gtgt, "C", + configName); + for (std::vector::iterator i = includes.begin(); + i != includes.end(); ++i) { + if (this->NameResolvesToFramework(i->c_str())) { + std::string frameworkDir = *i; + frameworkDir += "/../"; + frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir); + if (emitted.insert(frameworkDir).second) { + fdirs.Add(this->XCodeEscapePath(frameworkDir)); + } + } else { + std::string incpath = this->XCodeEscapePath(*i); + dirs.Add(incpath); + } + } + } else { + for (std::set::iterator li = languages.begin(); + li != languages.end(); ++li) { + std::vector includes; + this->CurrentLocalGenerator->GetIncludeDirectories(includes, gtgt, *li, + configName); + std::string includeFlags = this->CurrentLocalGenerator->GetIncludeFlags( + includes, gtgt, *li, true, false, configName); + + std::string& flags = cflags[*li]; + if (!includeFlags.empty()) { + flags += " " + includeFlags; } - } else { - std::string incpath = this->XCodeEscapePath(*i); - dirs.Add(incpath); } } // Add framework search paths needed for linking. @@ -2008,6 +2025,9 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, this->CreateString(flags)); } else if (*li == "C") { buildSettings->AddAttribute("OTHER_CFLAGS", this->CreateString(flags)); + } else if (*li == "Swift") { + buildSettings->AddAttribute("OTHER_SWIFT_FLAGS", + this->CreateString(flags)); } } diff --git a/Tests/IncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/CMakeLists.txt index 4920582..db18462 100644 --- a/Tests/IncludeDirectories/CMakeLists.txt +++ b/Tests/IncludeDirectories/CMakeLists.txt @@ -3,7 +3,9 @@ project(IncludeDirectories) if (((CMAKE_C_COMPILER_ID STREQUAL GNU AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.4) OR CMAKE_C_COMPILER_ID STREQUAL Clang OR CMAKE_C_COMPILER_ID STREQUAL AppleClang) - AND (CMAKE_GENERATOR STREQUAL "Unix Makefiles" OR CMAKE_GENERATOR STREQUAL "Ninja")) + AND (CMAKE_GENERATOR STREQUAL "Unix Makefiles" + OR CMAKE_GENERATOR STREQUAL "Ninja" + OR (CMAKE_GENERATOR STREQUAL "Xcode" AND NOT XCODE_VERSION VERSION_LESS 6.0))) include(CheckCXXCompilerFlag) check_cxx_compiler_flag(-Wunused-variable run_sys_includes_test) if(run_sys_includes_test) diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt index dcee85e..5078f30 100644 --- a/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt +++ b/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt @@ -15,10 +15,17 @@ target_include_directories(upstream SYSTEM PUBLIC ) add_library(config_specific INTERFACE) -set(testConfig ${CMAKE_BUILD_TYPE}) -target_include_directories(config_specific SYSTEM INTERFACE - "$<$:${CMAKE_CURRENT_SOURCE_DIR}/config_specific>" -) +if(CMAKE_GENERATOR STREQUAL "Xcode") + # CMAKE_BUILD_TYPE does not work here for multi-config generators + target_include_directories(config_specific SYSTEM INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/config_specific" + ) +else() + set(testConfig ${CMAKE_BUILD_TYPE}) + target_include_directories(config_specific SYSTEM INTERFACE + "$<$:${CMAKE_CURRENT_SOURCE_DIR}/config_specific>" + ) +endif() add_library(consumer consumer.cpp) target_link_libraries(consumer upstream config_specific) ----------------------------------------------------------------------- Summary of changes: Modules/CMakeSwiftInformation.cmake | 1 + Source/cmGlobalXCodeGenerator.cxx | 48 ++++++++++++++------ Tests/IncludeDirectories/CMakeLists.txt | 4 +- .../SystemIncludeDirectories/CMakeLists.txt | 15 ++++-- 4 files changed, 49 insertions(+), 19 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 9 16:00:48 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 9 Aug 2016 16:00:48 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1207-g1b020c5 Message-ID: <20160809200048.B6946F512B@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 1b020c5d0ce1085199bf3d68654ee02eb401d5ac (commit) via 677e73cb8a7c6f3e598375cb4ff29a24e43a1492 (commit) from 8bbcf863e5d24a91a371ee9dec87381d6e09da9f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1b020c5d0ce1085199bf3d68654ee02eb401d5ac commit 1b020c5d0ce1085199bf3d68654ee02eb401d5ac Merge: 8bbcf86 677e73c Author: Brad King AuthorDate: Tue Aug 9 16:00:47 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 9 16:00:47 2016 -0400 Merge topic 'fix-test-macOS-case-sensitive' into next 677e73cb Tests: Fix RunCMake.Framework on case sensitive file systems. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=677e73cb8a7c6f3e598375cb4ff29a24e43a1492 commit 677e73cb8a7c6f3e598375cb4ff29a24e43a1492 Author: Chaoren Lin AuthorDate: Tue Aug 9 12:47:06 2016 -0700 Commit: Brad King CommitDate: Tue Aug 9 16:00:27 2016 -0400 Tests: Fix RunCMake.Framework on case sensitive file systems. The file is lowercase: Tests/RunCMake/Framework/osx.cmake diff --git a/Tests/RunCMake/Framework/RunCMakeTest.cmake b/Tests/RunCMake/Framework/RunCMakeTest.cmake index d810283..eeea6f1 100644 --- a/Tests/RunCMake/Framework/RunCMakeTest.cmake +++ b/Tests/RunCMake/Framework/RunCMakeTest.cmake @@ -20,7 +20,7 @@ unset(RunCMake_TEST_OPTIONS) set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/OSXFrameworkLayout-build) set(RunCMake_TEST_NO_CLEAN 1) -set(RunCMake_TEST_OPTIONS "-DCMAKE_TOOLCHAIN_FILE=${RunCMake_SOURCE_DIR}/OSX.cmake") +set(RunCMake_TEST_OPTIONS "-DCMAKE_TOOLCHAIN_FILE=${RunCMake_SOURCE_DIR}/osx.cmake") file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") ----------------------------------------------------------------------- Summary of changes: Tests/RunCMake/Framework/RunCMakeTest.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From kwrobot at kitware.com Wed Aug 10 00:01:08 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Wed, 10 Aug 2016 00:01:08 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-594-g5aabfec Message-ID: <20160810040108.1B0F9F5793@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 5aabfec9308bb8b85f19077c2514a0c34f1dbb87 (commit) from 4689d16e8aa90e57a8456357251b6575131529d7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5aabfec9308bb8b85f19077c2514a0c34f1dbb87 commit 5aabfec9308bb8b85f19077c2514a0c34f1dbb87 Author: Kitware Robot AuthorDate: Wed Aug 10 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Wed Aug 10 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 55a9958..f354b57 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160809) +set(CMake_VERSION_PATCH 20160810) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 10 11:15:49 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 10 Aug 2016 11:15:49 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-596-g4887640 Message-ID: <20160810151549.A8E42F46A4@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 4887640b7a69ee1febc19c50add55f8e07bb42b8 (commit) via 02d177c9cc05514baccfa530ab85eec65374fbcb (commit) from 5aabfec9308bb8b85f19077c2514a0c34f1dbb87 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4887640b7a69ee1febc19c50add55f8e07bb42b8 commit 4887640b7a69ee1febc19c50add55f8e07bb42b8 Merge: 5aabfec 02d177c Author: Brad King AuthorDate: Wed Aug 10 11:15:47 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 10 11:15:47 2016 -0400 Merge topic 'add-extra-boolean-comparisons' 02d177c9 Add additional <= and >= comparison operators ----------------------------------------------------------------------- Summary of changes: Help/command/if.rst | 59 ++++-- Help/command/string.rst | 6 +- Help/manual/cmake-generator-expressions.7.rst | 8 +- Help/release/dev/add-extra-boolean-comparisons.rst | 6 + Help/variable/CMAKE_VERSION.rst | 10 +- Source/cmCTest.cxx | 7 +- Source/cmConditionEvaluator.cxx | 32 +++- Source/cmGeneratorExpressionNode.cxx | 40 ++++ Source/cmStringCommand.cxx | 7 +- Source/cmSystemTools.cxx | 13 +- Source/cmSystemTools.h | 10 +- Tests/CMakeTests/VersionTest.cmake.in | 14 ++ Tests/CTestTestStopTime/GetDate.cmake | 4 +- Tests/Complex/CMakeLists.txt | 6 + Tests/Complex/Executable/complex.cxx | 200 ++++++++++++++++++-- Tests/Complex/VarTests.cmake | 78 +++++++- Tests/ComplexOneConfig/Executable/complex.cxx | 194 +++++++++++++++++-- Tests/ComplexOneConfig/VarTests.cmake | 78 +++++++- 18 files changed, 693 insertions(+), 79 deletions(-) create mode 100644 Help/release/dev/add-extra-boolean-comparisons.rst hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 10 11:15:52 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 10 Aug 2016 11:15:52 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-598-gf4cec30 Message-ID: <20160810151552.71309F46C3@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via f4cec30b5326804b7c82c09dad85e78ce8fa3b32 (commit) via c7a319ab057172071bf8fb909c4498ca87b1235a (commit) from 4887640b7a69ee1febc19c50add55f8e07bb42b8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f4cec30b5326804b7c82c09dad85e78ce8fa3b32 commit f4cec30b5326804b7c82c09dad85e78ce8fa3b32 Merge: 4887640 c7a319a Author: Brad King AuthorDate: Wed Aug 10 11:15:50 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 10 11:15:50 2016 -0400 Merge topic 'install-export-staging-dir' c7a319ab install(EXPORT): Fix support for mid-length install destinations on Windows ----------------------------------------------------------------------- Summary of changes: Source/cmInstallExportGenerator.cxx | 27 +++++++++++++++++++++++++-- Source/cmInstallExportGenerator.h | 1 + 2 files changed, 26 insertions(+), 2 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 10 11:15:55 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 10 Aug 2016 11:15:55 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-600-g627ffb4 Message-ID: <20160810151555.21611F4994@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 627ffb4bd768609019014828d7480c22997cda0c (commit) via e9c984267e5539b798a2b1af8431e5715f261cfd (commit) from f4cec30b5326804b7c82c09dad85e78ce8fa3b32 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=627ffb4bd768609019014828d7480c22997cda0c commit 627ffb4bd768609019014828d7480c22997cda0c Merge: f4cec30 e9c9842 Author: Brad King AuthorDate: Wed Aug 10 11:15:53 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 10 11:15:53 2016 -0400 Merge topic 'NAG-Fortran-no-fPIE' e9c98426 NAG: Use -PIC for Fortran position-independent executable code ----------------------------------------------------------------------- Summary of changes: Modules/Compiler/NAG-Fortran.cmake | 1 + 1 file changed, 1 insertion(+) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 10 11:15:58 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 10 Aug 2016 11:15:58 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-603-ge01c576 Message-ID: <20160810151558.0EA32F497D@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via e01c576338ae448d9cbf18cc065567fde5c89f3b (commit) via 0278989405eea53ca7e5f1bfa6af9aea7a0b49c5 (commit) via a88c99f1bc301276a1780fec683d5061ca13f66f (commit) from 627ffb4bd768609019014828d7480c22997cda0c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e01c576338ae448d9cbf18cc065567fde5c89f3b commit e01c576338ae448d9cbf18cc065567fde5c89f3b Merge: 627ffb4 0278989 Author: Brad King AuthorDate: Wed Aug 10 11:15:55 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 10 11:15:55 2016 -0400 Merge topic 'ninja-directory-targets' 02789894 Ninja: Add `$subdir/{test,install,package}` targets a88c99f1 Ninja: Simplify computation of GLOBAL_TARGET outputs ----------------------------------------------------------------------- Summary of changes: Help/generator/Ninja.rst | 17 ++++++++++++++--- Help/release/dev/ninja-directory-targets.rst | 8 ++++++++ Source/cmGlobalNinjaGenerator.cxx | 18 +++++++++--------- Source/cmNinjaTargetGenerator.cxx | 13 +------------ Source/cmNinjaUtilityTargetGenerator.cxx | 17 ++++++++++++----- Tests/RunCMake/Ninja/RunCMakeTest.cmake | 6 ++++++ Tests/RunCMake/Ninja/SubDir-install-stdout.txt | 1 + Tests/RunCMake/Ninja/SubDir-test-stdout.txt | 1 + Tests/RunCMake/Ninja/SubDir.cmake | 5 +++++ Tests/RunCMake/Ninja/SubDir/CMakeLists.txt | 4 ++++ 10 files changed, 61 insertions(+), 29 deletions(-) create mode 100644 Help/release/dev/ninja-directory-targets.rst create mode 100644 Tests/RunCMake/Ninja/SubDir-install-stdout.txt create mode 100644 Tests/RunCMake/Ninja/SubDir-test-stdout.txt hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 10 11:16:00 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 10 Aug 2016 11:16:00 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-605-g655d242 Message-ID: <20160810151600.A54DCF4994@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 655d242b90a06c5904b67ce063361dfb646e85b3 (commit) via 677e73cb8a7c6f3e598375cb4ff29a24e43a1492 (commit) from e01c576338ae448d9cbf18cc065567fde5c89f3b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=655d242b90a06c5904b67ce063361dfb646e85b3 commit 655d242b90a06c5904b67ce063361dfb646e85b3 Merge: e01c576 677e73c Author: Brad King AuthorDate: Wed Aug 10 11:15:58 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 10 11:15:58 2016 -0400 Merge topic 'fix-test-macOS-case-sensitive' 677e73cb Tests: Fix RunCMake.Framework on case sensitive file systems. ----------------------------------------------------------------------- Summary of changes: Tests/RunCMake/Framework/RunCMakeTest.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 10 11:16:03 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 10 Aug 2016 11:16:03 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-607-g50ada75 Message-ID: <20160810151603.A83FDF4803@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 50ada755e3c133149f76dddfd0921eb7a9d32506 (commit) via 93ac2a78d5e0dbb6607105cc8d2a3f19ebdd8583 (commit) from 655d242b90a06c5904b67ce063361dfb646e85b3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=50ada755e3c133149f76dddfd0921eb7a9d32506 commit 50ada755e3c133149f76dddfd0921eb7a9d32506 Merge: 655d242 93ac2a7 Author: Brad King AuthorDate: Wed Aug 10 11:16:01 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 10 11:16:01 2016 -0400 Merge topic '15687-xcode-support-system-include' 93ac2a78 Xcode: Obey SYSTEM keyword for includes (#15687) ----------------------------------------------------------------------- Summary of changes: Modules/CMakeSwiftInformation.cmake | 1 + Source/cmGlobalXCodeGenerator.cxx | 48 ++++++++++++++------ Tests/IncludeDirectories/CMakeLists.txt | 4 +- .../SystemIncludeDirectories/CMakeLists.txt | 15 ++++-- 4 files changed, 49 insertions(+), 19 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 10 11:16:18 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 10 Aug 2016 11:16:18 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1215-g1c9b455 Message-ID: <20160810151618.D48E0F4994@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 1c9b455c48aed37ef0992f40fd4cf189e648c45f (commit) via 50ada755e3c133149f76dddfd0921eb7a9d32506 (commit) via 655d242b90a06c5904b67ce063361dfb646e85b3 (commit) via e01c576338ae448d9cbf18cc065567fde5c89f3b (commit) via 627ffb4bd768609019014828d7480c22997cda0c (commit) via f4cec30b5326804b7c82c09dad85e78ce8fa3b32 (commit) via 4887640b7a69ee1febc19c50add55f8e07bb42b8 (commit) via 5aabfec9308bb8b85f19077c2514a0c34f1dbb87 (commit) from 1b020c5d0ce1085199bf3d68654ee02eb401d5ac (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1c9b455c48aed37ef0992f40fd4cf189e648c45f commit 1c9b455c48aed37ef0992f40fd4cf189e648c45f Merge: 1b020c5 50ada75 Author: Brad King AuthorDate: Wed Aug 10 11:16:11 2016 -0400 Commit: Brad King CommitDate: Wed Aug 10 11:16:11 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 10 11:52:01 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 10 Aug 2016 11:52:01 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1221-gb2d8050 Message-ID: <20160810155201.55A08F3D9D@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via b2d8050a9bc4ade6a4ca5b41af91c61cb1bd33ab (commit) via 48137ebcf2e3a03e804223bbbb409421a424a9ea (commit) via 0529ab5c59664c55c70f3e294374161e93fb1e4f (commit) via 36f230df30f4308a6b8db51aad38cbd0028ebdc8 (commit) via 14b4657dcceb1a7025e895fb55a61c14e62b6d1e (commit) via 57090700171551a723a1a25628b6bf806a358d02 (commit) from 1c9b455c48aed37ef0992f40fd4cf189e648c45f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b2d8050a9bc4ade6a4ca5b41af91c61cb1bd33ab commit b2d8050a9bc4ade6a4ca5b41af91c61cb1bd33ab Merge: 1c9b455 48137eb Author: Brad King AuthorDate: Wed Aug 10 11:52:00 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 10 11:52:00 2016 -0400 Merge topic 'autogen-same-name' into next 48137ebc cmFilePathUuid: Use Binary interface of cmCryptoHash 0529ab5c cmCryptoHash: New ByteHash methods that return a byte vector 36f230df cmCryptoHash: Return byte vector from internal Finalize method 14b4657d cmCryptoHash: New byte hash to string function 57090700 cmCryptoHash: Documentation comments https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=48137ebcf2e3a03e804223bbbb409421a424a9ea commit 48137ebcf2e3a03e804223bbbb409421a424a9ea Author: Sebastian Holtermann AuthorDate: Wed Aug 10 11:59:05 2016 +0200 Commit: Brad King CommitDate: Wed Aug 10 11:51:49 2016 -0400 cmFilePathUuid: Use Binary interface of cmCryptoHash diff --git a/Source/cmFilePathUuid.cxx b/Source/cmFilePathUuid.cxx index 592c3a6..2839b63 100644 --- a/Source/cmFilePathUuid.cxx +++ b/Source/cmFilePathUuid.cxx @@ -111,46 +111,22 @@ std::string cmFilePathUuid::GetChecksumString( const std::string& sourceFilename, const std::string& sourceRelPath, const std::string& sourceRelSeed) { - // Calculate the file ( seed + relative path + name ) checksum std::string checksumBase64; - - std::vector hashBytes; - { - // Acquire hash in a hex value string - std::string hexHash = cmCryptoHash::New("SHA256")->HashString( - (sourceRelSeed + sourceRelPath + sourceFilename).c_str()); - // Convert hex value string to bytes - hashBytes.resize(hexHash.size() / 2); - for (unsigned int ii = 0; ii != hashBytes.size(); ++ii) { - unsigned char hbyte[2] = { 0, 0 }; - for (unsigned int jj = 0; jj != 2; ++jj) { - const unsigned char nibble = hexHash[ii * 2 + jj]; - if ('0' <= nibble && nibble <= '9') { - hbyte[jj] = static_cast(nibble - '0'); - } else if ('a' <= nibble && nibble <= 'f') { - hbyte[jj] = static_cast(nibble - 'a' + 10); - } else if ('A' <= nibble && nibble <= 'f') { - hbyte[jj] = static_cast(nibble - 'A' + 10); - } else { - // Unexpected non hex character - std::cerr << "Unexpected non hex character in checksum string"; - exit(-1); - } - } - hashBytes[ii] = static_cast(hbyte[1] | (hbyte[0] << 4)); - } - } - // Convert hash bytes to Base64 text string { + // Calculate the file ( seed + relative path + name ) checksum + std::vector hashBytes = + cmCryptoHash::New("SHA256")->ByteHashString( + (sourceRelSeed + sourceRelPath + sourceFilename).c_str()); + // Convert hash bytes to Base64 text string std::vector base64Bytes(hashBytes.size() * 2, 0); cmsysBase64_Encode(&hashBytes[0], hashBytes.size(), &base64Bytes[0], 0); checksumBase64 = reinterpret_cast(&base64Bytes[0]); - // Base64 allows '+' and '/' characters. - // Both are problematic when used in file names. - // Replace them with safer alternatives. - std::replace(checksumBase64.begin(), checksumBase64.end(), '+', '_'); - std::replace(checksumBase64.begin(), checksumBase64.end(), '/', '-'); } + // Base64 allows '/', '+' and '=' characters which are problematic + // when used in file names. Replace them with safer alternatives. + std::replace(checksumBase64.begin(), checksumBase64.end(), '/', '-'); + std::replace(checksumBase64.begin(), checksumBase64.end(), '+', '_'); + std::replace(checksumBase64.begin(), checksumBase64.end(), '=', '_'); return checksumBase64; } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0529ab5c59664c55c70f3e294374161e93fb1e4f commit 0529ab5c59664c55c70f3e294374161e93fb1e4f Author: Sebastian Holtermann AuthorDate: Wed Aug 10 11:30:06 2016 +0200 Commit: Brad King CommitDate: Wed Aug 10 11:51:49 2016 -0400 cmCryptoHash: New ByteHash methods that return a byte vector diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx index dafe7c6..ec885d8 100644 --- a/Source/cmCryptoHash.cxx +++ b/Source/cmCryptoHash.cxx @@ -65,43 +65,57 @@ std::string cmCryptoHash::ByteHashToString( return res; } -std::string cmCryptoHash::HashString(const std::string& input) +std::vector cmCryptoHash::ByteHashString( + const std::string& input) { this->Initialize(); this->Append(reinterpret_cast(input.c_str()), static_cast(input.size())); - return ByteHashToString(this->Finalize()); + return this->Finalize(); } -std::string cmCryptoHash::HashFile(const std::string& file) +std::vector cmCryptoHash::ByteHashFile(const std::string& file) { cmsys::ifstream fin(file.c_str(), std::ios::in | std::ios::binary); - if (!fin) { - return ""; + if (fin) { + this->Initialize(); + { + // Should be efficient enough on most system: + cm_sha2_uint64_t buffer[512]; + char* buffer_c = reinterpret_cast(buffer); + unsigned char const* buffer_uc = + reinterpret_cast(buffer); + // 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_c, sizeof(buffer)); + if (int gcount = static_cast(fin.gcount())) { + this->Append(buffer_uc, gcount); + } + } + } + if (fin.eof()) { + // Success + return this->Finalize(); + } + // Finalize anyway + this->Finalize(); } + // Return without success + return std::vector(); +} - this->Initialize(); +std::string cmCryptoHash::HashString(const std::string& input) +{ + return ByteHashToString(this->ByteHashString(input)); +} - // Should be efficient enough on most system: - cm_sha2_uint64_t buffer[512]; - char* buffer_c = reinterpret_cast(buffer); - unsigned char const* buffer_uc = - reinterpret_cast(buffer); - // 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_c, sizeof(buffer)); - if (int gcount = static_cast(fin.gcount())) { - this->Append(buffer_uc, gcount); - } - } - if (fin.eof()) { - return ByteHashToString(this->Finalize()); - } - return ""; +std::string cmCryptoHash::HashFile(const std::string& file) +{ + return ByteHashToString(this->ByteHashFile(file)); } cmCryptoHashMD5::cmCryptoHashMD5() diff --git a/Source/cmCryptoHash.h b/Source/cmCryptoHash.h index ab50e82..4e92b06 100644 --- a/Source/cmCryptoHash.h +++ b/Source/cmCryptoHash.h @@ -23,22 +23,37 @@ class cmCryptoHash { public: virtual ~cmCryptoHash() {} + /// @brief Returns a new hash generator of the requested type /// @arg algo Hash type name. Supported hash types are /// MD5, SHA1, SHA224, SHA256, SHA384, SHA512 /// @return A valid auto pointer if algo is supported or /// an invalid/NULL pointer otherwise static CM_AUTO_PTR New(const char* algo); + /// @brief Converts a hex character to its binary value (4 bits) /// @arg input Hex character [0-9a-fA-F]. /// @arg output Binary value of the input character (4 bits) /// @return True if input was a valid hex character static bool IntFromHexDigit(char input, char& output); + /// @brief Converts a byte hash to a sequence of hex character pairs static std::string ByteHashToString(const std::vector& hash); + + /// @brief Calculates a binary hash from string input data + /// @return Binary hash vector + std::vector ByteHashString(const std::string& input); + + /// @brief Calculates a binary hash from file content + /// @see ByteHashString() + /// @return Non empty binary hash vector if the file was read successfully. + /// An empty vector otherwise. + std::vector ByteHashFile(const std::string& file); + /// @brief Calculates a hash string from string input data /// @return Sequence of hex characters pairs for each byte of the binary hash std::string HashString(const std::string& input); + /// @brief Calculates a hash string from file content /// @see HashString() /// @return Non empty hash string if the file was read successfully. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=36f230df30f4308a6b8db51aad38cbd0028ebdc8 commit 36f230df30f4308a6b8db51aad38cbd0028ebdc8 Author: Sebastian Holtermann AuthorDate: Wed Aug 10 11:08:15 2016 +0200 Commit: Brad King CommitDate: Wed Aug 10 11:51:40 2016 -0400 cmCryptoHash: Return byte vector from internal Finalize method Some callers may want the raw byte vector instead of the hex character string. Convert the internal implementation to use this so that we can later add public APIs to get it. diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx index 59b9abd..dafe7c6 100644 --- a/Source/cmCryptoHash.cxx +++ b/Source/cmCryptoHash.cxx @@ -70,7 +70,7 @@ std::string cmCryptoHash::HashString(const std::string& input) this->Initialize(); this->Append(reinterpret_cast(input.c_str()), static_cast(input.size())); - return this->Finalize(); + return ByteHashToString(this->Finalize()); } std::string cmCryptoHash::HashFile(const std::string& file) @@ -99,7 +99,7 @@ std::string cmCryptoHash::HashFile(const std::string& file) } } if (fin.eof()) { - return this->Finalize(); + return ByteHashToString(this->Finalize()); } return ""; } @@ -124,11 +124,11 @@ void cmCryptoHashMD5::Append(unsigned char const* buf, int sz) cmsysMD5_Append(this->MD5, buf, sz); } -std::string cmCryptoHashMD5::Finalize() +std::vector cmCryptoHashMD5::Finalize() { - char md5out[32]; - cmsysMD5_FinalizeHex(this->MD5, md5out); - return std::string(md5out, 32); + std::vector hash(16, 0); + cmsysMD5_Finalize(this->MD5, &hash[0]); + return hash; } #define cmCryptoHash_SHA_CLASS_IMPL(SHA) \ @@ -142,11 +142,11 @@ std::string cmCryptoHashMD5::Finalize() { \ SHA##_Update(this->SHA, buf, sz); \ } \ - std::string cmCryptoHash##SHA::Finalize() \ + std::vector cmCryptoHash##SHA::Finalize() \ { \ - char out[SHA##_DIGEST_STRING_LENGTH]; \ - SHA##_End(this->SHA, out); \ - return std::string(out, SHA##_DIGEST_STRING_LENGTH - 1); \ + std::vector hash(SHA##_DIGEST_STRING_LENGTH, 0); \ + SHA##_Final(&hash[0], this->SHA); \ + return hash; \ } cmCryptoHash_SHA_CLASS_IMPL(SHA1) cmCryptoHash_SHA_CLASS_IMPL(SHA224) diff --git a/Source/cmCryptoHash.h b/Source/cmCryptoHash.h index 80ab269..ab50e82 100644 --- a/Source/cmCryptoHash.h +++ b/Source/cmCryptoHash.h @@ -48,7 +48,7 @@ public: protected: virtual void Initialize() = 0; virtual void Append(unsigned char const*, int) = 0; - virtual std::string Finalize() = 0; + virtual std::vector Finalize() = 0; }; class cmCryptoHashMD5 : public cmCryptoHash @@ -62,7 +62,7 @@ public: protected: void Initialize() CM_OVERRIDE; void Append(unsigned char const* buf, int sz) CM_OVERRIDE; - std::string Finalize() CM_OVERRIDE; + std::vector Finalize() CM_OVERRIDE; }; #define cmCryptoHash_SHA_CLASS_DECL(SHA) \ @@ -77,7 +77,7 @@ protected: protected: \ virtual void Initialize(); \ virtual void Append(unsigned char const* buf, int sz); \ - virtual std::string Finalize(); \ + virtual std::vector Finalize(); \ } cmCryptoHash_SHA_CLASS_DECL(SHA1); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=14b4657dcceb1a7025e895fb55a61c14e62b6d1e commit 14b4657dcceb1a7025e895fb55a61c14e62b6d1e Author: Sebastian Holtermann AuthorDate: Wed Aug 10 10:35:19 2016 +0200 Commit: Brad King CommitDate: Wed Aug 10 11:46:33 2016 -0400 cmCryptoHash: New byte hash to string function diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx index 8d60c1f..59b9abd 100644 --- a/Source/cmCryptoHash.cxx +++ b/Source/cmCryptoHash.cxx @@ -34,6 +34,37 @@ CM_AUTO_PTR cmCryptoHash::New(const char* algo) } } +bool cmCryptoHash::IntFromHexDigit(char input, char& output) +{ + if (input >= '0' && input <= '9') { + output = char(input - '0'); + return true; + } else if (input >= 'a' && input <= 'f') { + output = char(input - 'a' + 0xA); + return true; + } else if (input >= 'A' && input <= 'F') { + output = char(input - 'A' + 0xA); + return true; + } + return false; +} + +std::string cmCryptoHash::ByteHashToString( + const std::vector& hash) +{ + // 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' }; + + std::string res; + for (std::vector::const_iterator vit = hash.begin(); + vit != hash.end(); ++vit) { + res.push_back(hex[(*vit) >> 4]); + res.push_back(hex[(*vit) & 0xF]); + } + return res; +} + std::string cmCryptoHash::HashString(const std::string& input) { this->Initialize(); diff --git a/Source/cmCryptoHash.h b/Source/cmCryptoHash.h index 84dea9b..80ab269 100644 --- a/Source/cmCryptoHash.h +++ b/Source/cmCryptoHash.h @@ -29,6 +29,13 @@ public: /// @return A valid auto pointer if algo is supported or /// an invalid/NULL pointer otherwise static CM_AUTO_PTR New(const char* algo); + /// @brief Converts a hex character to its binary value (4 bits) + /// @arg input Hex character [0-9a-fA-F]. + /// @arg output Binary value of the input character (4 bits) + /// @return True if input was a valid hex character + static bool IntFromHexDigit(char input, char& output); + /// @brief Converts a byte hash to a sequence of hex character pairs + static std::string ByteHashToString(const std::vector& hash); /// @brief Calculates a hash string from string input data /// @return Sequence of hex characters pairs for each byte of the binary hash std::string HashString(const std::string& input); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=57090700171551a723a1a25628b6bf806a358d02 commit 57090700171551a723a1a25628b6bf806a358d02 Author: Sebastian Holtermann AuthorDate: Wed Aug 10 09:54:49 2016 +0200 Commit: Brad King CommitDate: Wed Aug 10 11:46:33 2016 -0400 cmCryptoHash: Documentation comments diff --git a/Source/cmCryptoHash.h b/Source/cmCryptoHash.h index 6aaaf93..84dea9b 100644 --- a/Source/cmCryptoHash.h +++ b/Source/cmCryptoHash.h @@ -16,12 +16,26 @@ #include +/** + * @brief Abstract base class for cryptographic hash generators + */ class cmCryptoHash { public: virtual ~cmCryptoHash() {} + /// @brief Returns a new hash generator of the requested type + /// @arg algo Hash type name. Supported hash types are + /// MD5, SHA1, SHA224, SHA256, SHA384, SHA512 + /// @return A valid auto pointer if algo is supported or + /// an invalid/NULL pointer otherwise static CM_AUTO_PTR New(const char* algo); + /// @brief Calculates a hash string from string input data + /// @return Sequence of hex characters pairs for each byte of the binary hash std::string HashString(const std::string& input); + /// @brief Calculates a hash string from file content + /// @see HashString() + /// @return Non empty hash string if the file was read successfully. + /// An empty string otherwise. std::string HashFile(const std::string& file); protected: ----------------------------------------------------------------------- Summary of changes: Source/cmCryptoHash.cxx | 111 +++++++++++++++++++++++++++++++-------------- Source/cmCryptoHash.h | 42 +++++++++++++++-- Source/cmFilePathUuid.cxx | 44 ++++-------------- 3 files changed, 127 insertions(+), 70 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 10 13:20:58 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 10 Aug 2016 13:20:58 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1223-g5afd0cb Message-ID: <20160810172058.0A7F8F52FD@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 5afd0cbd9173fde8a7c73c2810a44d0e76c4a294 (commit) via 934a2ecf613e22360ae0aac25294a79a7acab112 (commit) from b2d8050a9bc4ade6a4ca5b41af91c61cb1bd33ab (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5afd0cbd9173fde8a7c73c2810a44d0e76c4a294 commit 5afd0cbd9173fde8a7c73c2810a44d0e76c4a294 Merge: b2d8050 934a2ec Author: Brad King AuthorDate: Wed Aug 10 13:20:57 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 10 13:20:57 2016 -0400 Merge topic 'autogen-same-name' into next 934a2ecf fixup! cmCryptoHash: Return byte vector from internal Finalize method https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=934a2ecf613e22360ae0aac25294a79a7acab112 commit 934a2ecf613e22360ae0aac25294a79a7acab112 Author: Brad King AuthorDate: Wed Aug 10 13:20:12 2016 -0400 Commit: Brad King CommitDate: Wed Aug 10 13:20:22 2016 -0400 fixup! cmCryptoHash: Return byte vector from internal Finalize method diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx index ec885d8..9bd07a3 100644 --- a/Source/cmCryptoHash.cxx +++ b/Source/cmCryptoHash.cxx @@ -158,7 +158,7 @@ std::vector cmCryptoHashMD5::Finalize() } \ std::vector cmCryptoHash##SHA::Finalize() \ { \ - std::vector hash(SHA##_DIGEST_STRING_LENGTH, 0); \ + std::vector hash(SHA##_DIGEST_LENGTH, 0); \ SHA##_Final(&hash[0], this->SHA); \ return hash; \ } ----------------------------------------------------------------------- Summary of changes: Source/cmCryptoHash.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 10 13:29:26 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 10 Aug 2016 13:29:26 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1233-gdf23706 Message-ID: <20160810172926.4C3DFF556B@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via df237068ee8618e19354d2fec3f0f99b5a9fee85 (commit) via e4f508e42397549cd966e47349d4030cb793c354 (commit) via 4e9b97d7397fd526e6b4e4ce43dd305cb8341ac8 (commit) via 41c9e14afb0bc7e68e4530f76329b7c11cdfa0e4 (commit) via 3c3b37b0bbd3fb78aa60a2b38184b6397d2ea47f (commit) via 0a5dd3c700f1873be217707aa89a805d009bac3e (commit) via 3a5f609cbb4ae63fca1eb87918767a4296d16e5f (commit) via f582dba6664e5ea814f3b33c71ae4d83db17b996 (commit) via 74f0d4abcd8de84283858fe144772e688669e46a (commit) via 94c29976d0020b48a5c565234b71f8f6abaf08be (commit) from 5afd0cbd9173fde8a7c73c2810a44d0e76c4a294 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=df237068ee8618e19354d2fec3f0f99b5a9fee85 commit df237068ee8618e19354d2fec3f0f99b5a9fee85 Merge: 5afd0cb e4f508e Author: Brad King AuthorDate: Wed Aug 10 13:29:23 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 10 13:29:23 2016 -0400 Merge topic 'autogen-same-name' into next e4f508e4 Tests/QtAutogen: Test same moc/qrc source names in different directories 4e9b97d7 QtAutogen: Allow multiple qrc files with the same name 41c9e14a QtAutogen: Allow multiple moc files with the same name 3c3b37b0 QtAutogen: Use std:: instead of ::std:: 0a5dd3c7 cmFilePathUuid: Add class to generate deterministic unique file names 3a5f609c cmCryptoHash: New ByteHash methods that return a byte vector f582dba6 cmCryptoHash: Return byte vector from internal Finalize method 74f0d4ab cmCryptoHash: New byte hash to string function 94c29976 cmCryptoHash: Documentation comments https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e4f508e42397549cd966e47349d4030cb793c354 commit e4f508e42397549cd966e47349d4030cb793c354 Author: Sebastian Holtermann AuthorDate: Sat Aug 6 15:22:54 2016 +0200 Commit: Brad King CommitDate: Wed Aug 10 13:21:34 2016 -0400 Tests/QtAutogen: Test same moc/qrc source names in different directories diff --git a/Tests/QtAutogen/CMakeLists.txt b/Tests/QtAutogen/CMakeLists.txt index d5aca55..e35e1d1 100644 --- a/Tests/QtAutogen/CMakeLists.txt +++ b/Tests/QtAutogen/CMakeLists.txt @@ -110,6 +110,10 @@ set_target_properties( AUTOMOC TRUE ) +# Test AUTOMOC and AUTORCC on source files with the same name +# but in different subdirectories +add_subdirectory(sameName) + include(GenerateExportHeader) # The order is relevant here. B depends on A, and B headers depend on A # headers both subdirectories use CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE and we diff --git a/Tests/QtAutogen/sameName/CMakeLists.txt b/Tests/QtAutogen/sameName/CMakeLists.txt new file mode 100644 index 0000000..ed045fb --- /dev/null +++ b/Tests/QtAutogen/sameName/CMakeLists.txt @@ -0,0 +1,21 @@ +# Test AUTOMOC and AUTORCC on source files with the same name +# but in different subdirectories + +add_executable(sameName + aaa/bbb/item.cpp + aaa/bbb/data.qrc + aaa/item.cpp + aaa/data.qrc + bbb/aaa/item.cpp + bbb/aaa/data.qrc + bbb/item.cpp + bbb/data.qrc + ccc/item.cpp + ccc/data.qrc + item.cpp + data.qrc + main.cpp +) +target_include_directories(sameName PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_link_libraries(sameName ${QT_LIBRARIES}) +set_target_properties( sameName PROPERTIES AUTOMOC TRUE AUTORCC TRUE ) diff --git a/Tests/QtAutogen/sameName/aaa/bbb/data.qrc b/Tests/QtAutogen/sameName/aaa/bbb/data.qrc new file mode 100644 index 0000000..0ea3537 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/bbb/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/aaa/bbb/item.cpp b/Tests/QtAutogen/sameName/aaa/bbb/item.cpp new file mode 100644 index 0000000..20d0044 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/bbb/item.cpp @@ -0,0 +1,10 @@ +#include "item.hpp" + +namespace aaa { +namespace bbb { + +void Item::go() +{ +} +} +} diff --git a/Tests/QtAutogen/sameName/aaa/bbb/item.hpp b/Tests/QtAutogen/sameName/aaa/bbb/item.hpp new file mode 100644 index 0000000..0855043 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/bbb/item.hpp @@ -0,0 +1,18 @@ +#ifndef AAA_BBB_ITEM_HPP +#define AAA_BBB_ITEM_HPP + +#include + +namespace aaa { +namespace bbb { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} +} + +#endif diff --git a/Tests/QtAutogen/sameName/aaa/data.qrc b/Tests/QtAutogen/sameName/aaa/data.qrc new file mode 100644 index 0000000..379af60 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/aaa/item.cpp b/Tests/QtAutogen/sameName/aaa/item.cpp new file mode 100644 index 0000000..95dd3b6 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/item.cpp @@ -0,0 +1,8 @@ +#include "item.hpp" + +namespace aaa { + +void Item::go() +{ +} +} diff --git a/Tests/QtAutogen/sameName/aaa/item.hpp b/Tests/QtAutogen/sameName/aaa/item.hpp new file mode 100644 index 0000000..b63466f --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/item.hpp @@ -0,0 +1,16 @@ +#ifndef AAA_ITEM_HPP +#define AAA_ITEM_HPP + +#include + +namespace aaa { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} + +#endif diff --git a/Tests/QtAutogen/sameName/bbb/aaa/data.qrc b/Tests/QtAutogen/sameName/bbb/aaa/data.qrc new file mode 100644 index 0000000..da98009 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/aaa/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/bbb/aaa/item.cpp b/Tests/QtAutogen/sameName/bbb/aaa/item.cpp new file mode 100644 index 0000000..ac4b2c2 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/aaa/item.cpp @@ -0,0 +1,10 @@ +#include "item.hpp" + +namespace bbb { +namespace aaa { + +void Item::go() +{ +} +} +} diff --git a/Tests/QtAutogen/sameName/bbb/aaa/item.hpp b/Tests/QtAutogen/sameName/bbb/aaa/item.hpp new file mode 100644 index 0000000..be07ca8 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/aaa/item.hpp @@ -0,0 +1,18 @@ +#ifndef BBB_AAA_ITEM_HPP +#define BBB_AAA_ITEM_HPP + +#include + +namespace bbb { +namespace aaa { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} +} + +#endif diff --git a/Tests/QtAutogen/sameName/bbb/data.qrc b/Tests/QtAutogen/sameName/bbb/data.qrc new file mode 100644 index 0000000..5b080f5 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/bbb/item.cpp b/Tests/QtAutogen/sameName/bbb/item.cpp new file mode 100644 index 0000000..f97a143 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/item.cpp @@ -0,0 +1,8 @@ +#include "item.hpp" + +namespace bbb { + +void Item::go() +{ +} +} diff --git a/Tests/QtAutogen/sameName/bbb/item.hpp b/Tests/QtAutogen/sameName/bbb/item.hpp new file mode 100644 index 0000000..5b7f985 --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/item.hpp @@ -0,0 +1,16 @@ +#ifndef BBB_ITEM_HPP +#define BBB_ITEM_HPP + +#include + +namespace bbb { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} + +#endif diff --git a/Tests/QtAutogen/sameName/ccc/data.qrc b/Tests/QtAutogen/sameName/ccc/data.qrc new file mode 100644 index 0000000..f934c39 --- /dev/null +++ b/Tests/QtAutogen/sameName/ccc/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/ccc/item.cpp b/Tests/QtAutogen/sameName/ccc/item.cpp new file mode 100644 index 0000000..d90b2b8 --- /dev/null +++ b/Tests/QtAutogen/sameName/ccc/item.cpp @@ -0,0 +1,23 @@ +#include "item.hpp" + +namespace ccc { + +void Item::go() +{ +} + +class MocTest : public QObject +{ + Q_OBJECT; + Q_SLOT + void go(); +}; + +void MocTest::go() +{ +} +} + +// Include own moc files +#include "item.moc" +#include "moc_item.cpp" diff --git a/Tests/QtAutogen/sameName/ccc/item.hpp b/Tests/QtAutogen/sameName/ccc/item.hpp new file mode 100644 index 0000000..96fcc24 --- /dev/null +++ b/Tests/QtAutogen/sameName/ccc/item.hpp @@ -0,0 +1,16 @@ +#ifndef CCC_ITEM_HPP +#define CCC_ITEM_HPP + +#include + +namespace ccc { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} + +#endif diff --git a/Tests/QtAutogen/sameName/data.qrc b/Tests/QtAutogen/sameName/data.qrc new file mode 100644 index 0000000..4ce0b4e --- /dev/null +++ b/Tests/QtAutogen/sameName/data.qrc @@ -0,0 +1,5 @@ + + + main.cpp + + diff --git a/Tests/QtAutogen/sameName/item.cpp b/Tests/QtAutogen/sameName/item.cpp new file mode 100644 index 0000000..e013cf3 --- /dev/null +++ b/Tests/QtAutogen/sameName/item.cpp @@ -0,0 +1,5 @@ +#include "item.hpp" + +void Item::go() +{ +} diff --git a/Tests/QtAutogen/sameName/item.hpp b/Tests/QtAutogen/sameName/item.hpp new file mode 100644 index 0000000..91bba3b --- /dev/null +++ b/Tests/QtAutogen/sameName/item.hpp @@ -0,0 +1,13 @@ +#ifndef ITEM_HPP +#define ITEM_HPP + +#include + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; + +#endif diff --git a/Tests/QtAutogen/sameName/main.cpp b/Tests/QtAutogen/sameName/main.cpp new file mode 100644 index 0000000..a4ffcb3 --- /dev/null +++ b/Tests/QtAutogen/sameName/main.cpp @@ -0,0 +1,16 @@ +#include "aaa/bbb/item.hpp" +#include "aaa/item.hpp" +#include "bbb/aaa/item.hpp" +#include "bbb/item.hpp" +#include "ccc/item.hpp" + +int main(int argv, char** args) +{ + // Object instances + ::aaa::Item aaa_item; + ::aaa::bbb::Item aaa_bbb_item; + ::bbb::Item bbb_item; + ::bbb::aaa::Item bbb_aaa_item; + ::ccc::Item ccc_item; + return 0; +} https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4e9b97d7397fd526e6b4e4ce43dd305cb8341ac8 commit 4e9b97d7397fd526e6b4e4ce43dd305cb8341ac8 Author: Sebastian Holtermann AuthorDate: Sat Aug 6 14:57:52 2016 +0200 Commit: Brad King CommitDate: Wed Aug 10 13:21:33 2016 -0400 QtAutogen: Allow multiple qrc files with the same name Use cmFilePathUuid for qrc files. diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index d5634e8..7efb333 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -13,6 +13,7 @@ #include "cmQtAutoGeneratorInitializer.h" +#include "cmFilePathUuid.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmSourceFile.h" @@ -25,6 +26,34 @@ #include "cmGlobalVisualStudioGenerator.h" #endif +static std::string GetAutogenTargetName(cmGeneratorTarget const* target) +{ + std::string autogenTargetName = target->GetName(); + autogenTargetName += "_automoc"; + return autogenTargetName; +} + +static std::string GetAutogenTargetDir(cmGeneratorTarget const* target) +{ + cmMakefile* makefile = target->Target->GetMakefile(); + std::string targetDir = makefile->GetCurrentBinaryDirectory(); + targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory(); + targetDir += "/"; + targetDir += GetAutogenTargetName(target); + targetDir += ".dir/"; + return targetDir; +} + +static std::string GetAutogenTargetBuildDir(cmGeneratorTarget const* target) +{ + cmMakefile* makefile = target->Target->GetMakefile(); + std::string targetDir = makefile->GetCurrentBinaryDirectory(); + targetDir += "/"; + targetDir += GetAutogenTargetName(target); + targetDir += ".dir/"; + return targetDir; +} + static void SetupSourceFiles(cmGeneratorTarget const* target, std::vector& skipMoc, std::vector& mocSources, @@ -38,6 +67,7 @@ static void SetupSourceFiles(cmGeneratorTarget const* target, std::vector newRccFiles; + cmFilePathUuid fpathUuid(makefile); for (std::vector::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; @@ -55,13 +85,12 @@ static void SetupSourceFiles(cmGeneratorTarget const* target, if (target->GetPropertyAsBool("AUTORCC")) { if (ext == "qrc" && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { - std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); - std::string rcc_output_dir = target->GetSupportDirectory(); - cmSystemTools::MakeDirectory(rcc_output_dir.c_str()); - std::string rcc_output_file = rcc_output_dir; - rcc_output_file += "/qrc_" + basename + ".cpp"; + std::string rcc_output_file = GetAutogenTargetBuildDir(target); + // Create output directory + cmSystemTools::MakeDirectory(rcc_output_file.c_str()); + rcc_output_file += fpathUuid.get(absFile, "qrc_", ".cpp"); + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", rcc_output_file.c_str(), false); makefile->GetOrCreateSource(rcc_output_file, true); @@ -365,24 +394,6 @@ static void MergeRccOptions(std::vector& opts, opts.insert(opts.end(), extraOpts.begin(), extraOpts.end()); } -std::string GetAutogenTargetName(cmGeneratorTarget const* target) -{ - std::string autogenTargetName = target->GetName(); - autogenTargetName += "_automoc"; - return autogenTargetName; -} - -std::string GetAutogenTargetDir(cmGeneratorTarget const* target) -{ - cmMakefile* makefile = target->Target->GetMakefile(); - std::string targetDir = makefile->GetCurrentBinaryDirectory(); - targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory(); - targetDir += "/"; - targetDir += GetAutogenTargetName(target); - targetDir += ".dir/"; - return targetDir; -} - static void copyTargetProperty(cmTarget* destinationTarget, cmTarget* sourceTarget, const std::string& propertyName) @@ -737,6 +748,7 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( ) { std::vector srcFiles; target->GetConfigCommonSourceFiles(srcFiles); + cmFilePathUuid fpathUuid(makefile); for (std::vector::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; @@ -747,15 +759,13 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( if (target->GetPropertyAsBool("AUTORCC")) { if (ext == "qrc" && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { - std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); - - std::string rcc_output_dir = target->GetSupportDirectory(); - cmSystemTools::MakeDirectory(rcc_output_dir.c_str()); - std::string rcc_output_file = rcc_output_dir; - rcc_output_file += "/qrc_" + basename + ".cpp"; - rcc_output.push_back(rcc_output_file); - + { + std::string rcc_output_file = GetAutogenTargetBuildDir(target); + // Create output directory + cmSystemTools::MakeDirectory(rcc_output_file.c_str()); + rcc_output_file += fpathUuid.get(absFile, "qrc_", ".cpp"); + rcc_output.push_back(rcc_output_file); + } if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { if (qtMajorVersion == "5") { ListQt5RccInputs(sf, target, depends); diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 33f7a54..a261962 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -88,6 +88,23 @@ static std::string extractSubDir(const std::string& absPath, return subDir; } +static bool FileNameIsUnique(const std::string& filePath, + const std::map& fileMap) +{ + size_t count(0); + const std::string fileName = cmsys::SystemTools::GetFilenameName(filePath); + for (std::map::const_iterator si = fileMap.begin(); + si != fileMap.end(); ++si) { + if (cmsys::SystemTools::GetFilenameName(si->first) == fileName) { + ++count; + if (count > 1) { + return false; + } + } + } + return true; +} + cmQtAutoGenerators::cmQtAutoGenerators() : Verbose(cmsys::SystemTools::HasEnv("VERBOSE")) , ColorOutput(true) @@ -1257,15 +1274,18 @@ bool cmQtAutoGenerators::GenerateQrcFiles() { // generate single map with input / output names std::map qrcGenMap; - for (std::vector::const_iterator si = this->RccSources.begin(); - si != this->RccSources.end(); ++si) { - const std::string ext = cmsys::SystemTools::GetFilenameLastExtension(*si); - if (ext == ".qrc") { - std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(*si); - std::string qrcOutputFile = "CMakeFiles/" + this->OriginTargetName + - ".dir/qrc_" + basename + ".cpp"; - qrcGenMap[*si] = qrcOutputFile; + { + cmFilePathUuid fpathUuid(this->Srcdir, this->Builddir, + this->ProjectSourceDir, this->ProjectBinaryDir); + for (std::vector::const_iterator si = + this->RccSources.begin(); + si != this->RccSources.end(); ++si) { + const std::string ext = + cmsys::SystemTools::GetFilenameLastExtension(*si); + if (ext == ".qrc") { + qrcGenMap[*si] = + (this->TargetBuildSubDir + fpathUuid.get(*si, "qrc_", ".cpp")); + } } } @@ -1287,7 +1307,8 @@ bool cmQtAutoGenerators::GenerateQrcFiles() for (std::map::const_iterator si = qrcGenMap.begin(); si != qrcGenMap.end(); ++si) { - if (!this->GenerateQrc(si->first, si->second)) { + bool unique = FileNameIsUnique(si->first, qrcGenMap); + if (!this->GenerateQrc(si->first, si->second, unique)) { if (this->RunRccFailed) { return false; } @@ -1297,10 +1318,23 @@ bool cmQtAutoGenerators::GenerateQrcFiles() } bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, - const std::string& qrcOutputFile) + const std::string& qrcOutputFile, + bool unique_n) { - const std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); + std::string symbolName; + if (unique_n) { + symbolName = + cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); + } else { + symbolName = + cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcOutputFile); + // Remove "qrc_" at string begin + symbolName.erase(0, 4); + } + // Replace '-' with '_'. The former is valid for + // file names but not for symbol names. + std::replace(symbolName.begin(), symbolName.end(), '-', '_'); + const std::string qrcBuildFile = this->Builddir + qrcOutputFile; int sourceNewerThanQrc = 0; @@ -1327,7 +1361,7 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, } command.push_back("-name"); - command.push_back(basename); + command.push_back(symbolName); command.push_back("-o"); command.push_back(qrcBuildFile); command.push_back(qrcInputFile); diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 216b0b0..fab2d19 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -51,7 +51,8 @@ private: const std::string& uiOutputFile); bool GenerateQrcFiles(); bool GenerateQrc(const std::string& qrcInputFile, - const std::string& qrcOutputFile); + const std::string& qrcOutputFile, bool unique_n); + void ParseCppFile( const std::string& absFilename, const std::vector& headerExtensions, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=41c9e14afb0bc7e68e4530f76329b7c11cdfa0e4 commit 41c9e14afb0bc7e68e4530f76329b7c11cdfa0e4 Author: Sebastian Holtermann AuthorDate: Sat Aug 6 13:33:46 2016 +0200 Commit: Brad King CommitDate: Wed Aug 10 13:21:33 2016 -0400 QtAutogen: Allow multiple moc files with the same name Use cmFilePathUuid for moc files. Closes: #12873 diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index ea8db71..33f7a54 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -14,6 +14,7 @@ #include "cmQtAutoGenerators.h" #include "cmAlgorithms.h" +#include "cmFilePathUuid.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmOutputConverter.h" @@ -358,11 +359,13 @@ void cmQtAutoGenerators::WriteOldMocDefinitionsFile( void cmQtAutoGenerators::Init() { + this->TargetBuildSubDir = this->TargetName; + this->TargetBuildSubDir += ".dir/"; + this->OutMocCppFilenameRel = this->TargetName; this->OutMocCppFilenameRel += ".cpp"; - this->OutMocCppFilename = this->Builddir; - this->OutMocCppFilename += this->OutMocCppFilenameRel; + this->OutMocCppFilenameAbs = this->Builddir + this->OutMocCppFilenameRel; std::vector cdefList; cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList); @@ -439,7 +442,7 @@ static std::string ReadAll(const std::string& filename) bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile) { - if (!cmsys::SystemTools::FileExists(this->OutMocCppFilename.c_str()) || + if (!cmsys::SystemTools::FileExists(this->OutMocCppFilenameAbs.c_str()) || (this->OldCompileSettingsStr != this->CurrentCompileSettingsStr)) { this->GenerateAll = true; } @@ -933,6 +936,8 @@ void cmQtAutoGenerators::ParseHeaders( std::map& notIncludedMocs, std::map >& includedUis) { + cmFilePathUuid fpathUuid(this->Srcdir, this->Builddir, + this->ProjectSourceDir, this->ProjectBinaryDir); for (std::set::const_iterator hIt = absHeaders.begin(); hIt != absHeaders.end(); ++hIt) { const std::string& headerName = *hIt; @@ -946,13 +951,10 @@ void cmQtAutoGenerators::ParseHeaders( this->LogInfo(err.str()); } - const std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(headerName); - - const std::string currentMoc = "moc_" + basename + ".cpp"; std::string macroName; if (requiresMocing(contents, macroName)) { - notIncludedMocs[headerName] = currentMoc; + notIncludedMocs[headerName] = + this->TargetBuildSubDir + fpathUuid.get(headerName, "moc_", ".cpp"); } } this->ParseForUic(headerName, contents, includedUis); @@ -1029,7 +1031,7 @@ bool cmQtAutoGenerators::GenerateMocFiles( // check if we even need to update _automoc.cpp if (!automocCppChanged) { // compare contents of the _automoc.cpp file - const std::string oldContents = ReadAll(this->OutMocCppFilename); + const std::string oldContents = ReadAll(this->OutMocCppFilenameAbs); if (oldContents == automocSource) { // nothing changed: don't touch the _automoc.cpp file if (this->Verbose) { @@ -1052,7 +1054,7 @@ bool cmQtAutoGenerators::GenerateMocFiles( } { cmsys::ofstream outfile; - outfile.open(this->OutMocCppFilename.c_str(), std::ios::trunc); + outfile.open(this->OutMocCppFilenameAbs.c_str(), std::ios::trunc); outfile << automocSource; outfile.close(); } diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 86913f0..216b0b0 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -123,8 +123,9 @@ private: std::string CurrentCompileSettingsStr; std::string OldCompileSettingsStr; + std::string TargetBuildSubDir; std::string OutMocCppFilenameRel; - std::string OutMocCppFilename; + std::string OutMocCppFilenameAbs; std::list MocIncludes; std::list MocDefinitions; std::vector MocOptions; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3c3b37b0bbd3fb78aa60a2b38184b6397d2ea47f commit 3c3b37b0bbd3fb78aa60a2b38184b6397d2ea47f Author: Sebastian Holtermann AuthorDate: Sat Aug 6 14:05:23 2016 +0200 Commit: Brad King CommitDate: Wed Aug 10 13:21:33 2016 -0400 QtAutogen: Use std:: instead of ::std:: diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 174760f..ea8db71 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -1183,7 +1183,7 @@ bool cmQtAutoGenerators::GenerateUi(const std::string& realName, cmsys::SystemTools::MakeDirectory(this->Builddir.c_str()); } - const ::std::string uiBuildFile = this->Builddir + uiOutputFile; + const std::string uiBuildFile = this->Builddir + uiOutputFile; int sourceNewerThanUi = 0; bool success = cmsys::SystemTools::FileTimeCompare(uiInputFile, uiBuildFile, @@ -1299,7 +1299,7 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, { const std::string basename = cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); - const ::std::string qrcBuildFile = this->Builddir + qrcOutputFile; + const std::string qrcBuildFile = this->Builddir + qrcOutputFile; int sourceNewerThanQrc = 0; bool generateQrc = !cmsys::SystemTools::FileTimeCompare( https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0a5dd3c700f1873be217707aa89a805d009bac3e commit 0a5dd3c700f1873be217707aa89a805d009bac3e Author: Sebastian Holtermann AuthorDate: Sat Aug 6 13:09:59 2016 +0200 Commit: Brad King CommitDate: Wed Aug 10 13:21:33 2016 -0400 cmFilePathUuid: Add class to generate deterministic unique file names The class generates a semi-unique (checksum based) pathless file name from a full source file path. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index a790994..cdc8fb1 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -238,6 +238,8 @@ set(SRCS cmFileLockPool.h cmFileLockResult.cxx cmFileLockResult.h + cmFilePathUuid.cxx + cmFilePathUuid.h cmFileTimeComparison.cxx cmFileTimeComparison.h cmFortranLexer.cxx diff --git a/Source/cmFilePathUuid.cxx b/Source/cmFilePathUuid.cxx new file mode 100644 index 0000000..2839b63 --- /dev/null +++ b/Source/cmFilePathUuid.cxx @@ -0,0 +1,132 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2016 Sebastian Holtermann (sebholt at xwmw.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmFilePathUuid.h" + +#include "cmCryptoHash.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" +#include "cmsys/Base64.h" + +cmFilePathUuid::cmFilePathUuid(cmMakefile* makefile) +{ + initParentDirs(makefile->GetCurrentSourceDirectory(), + makefile->GetCurrentBinaryDirectory(), + makefile->GetHomeDirectory(), + makefile->GetHomeOutputDirectory()); +} + +cmFilePathUuid::cmFilePathUuid(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir) +{ + initParentDirs(currentSrcDir, currentBinDir, projectSrcDir, projectBinDir); +} + +void cmFilePathUuid::initParentDirs(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir) +{ + parentDirs[0].first = cmsys::SystemTools::GetRealPath(currentSrcDir); + parentDirs[1].first = cmsys::SystemTools::GetRealPath(currentBinDir); + parentDirs[2].first = cmsys::SystemTools::GetRealPath(projectSrcDir); + parentDirs[3].first = cmsys::SystemTools::GetRealPath(projectBinDir); + + parentDirs[0].second = "CurrentSource"; + parentDirs[1].second = "CurrentBinary"; + parentDirs[2].second = "ProjectSource"; + parentDirs[3].second = "ProjectBinary"; +} + +std::string cmFilePathUuid::get(const std::string& filePath, + const char* outputPrefix, + const char* outputSuffix) +{ + std::string sourceFilename = cmsys::SystemTools::GetFilenameName(filePath); + std::string sourceBasename = + cmsys::SystemTools::GetFilenameWithoutLastExtension(sourceFilename); + + // Acquire checksum string + std::string checksum; + { + std::string sourceRelPath; + std::string sourceRelSeed; + GetRelPathSeed(filePath, sourceRelPath, sourceRelSeed); + checksum = GetChecksumString(sourceFilename, sourceRelPath, sourceRelSeed); + } + + // Compose the file name + std::string uuid; + if (outputPrefix) { + uuid += outputPrefix; + } + uuid += sourceBasename.substr(0, partLengthName); + uuid += "_"; + uuid += checksum.substr(0, partLengthCheckSum); + if (outputSuffix) { + uuid += outputSuffix; + } + return uuid; +} + +void cmFilePathUuid::GetRelPathSeed(const std::string& filePath, + std::string& sourceRelPath, + std::string& sourceRelSeed) +{ + const std::string sourceNameReal = cmsys::SystemTools::GetRealPath(filePath); + std::string parentDirectory; + // Find closest project parent directory + for (size_t ii = 0; ii != numParentDirs; ++ii) { + const std::string& pDir = parentDirs[ii].first; + if (!pDir.empty() && + cmsys::SystemTools::IsSubDirectory(sourceNameReal, pDir)) { + sourceRelSeed = parentDirs[ii].second; + parentDirectory = pDir; + break; + } + } + // Check if the file path is below a known project directory + if (parentDirectory.empty()) { + // Use file syste root as fallback parent directory + sourceRelSeed = "FileSystemRoot"; + cmsys::SystemTools::SplitPathRootComponent(sourceNameReal, + &parentDirectory); + } + sourceRelPath = cmsys::SystemTools::RelativePath( + parentDirectory, cmsys::SystemTools::GetParentDirectory(sourceNameReal)); +} + +std::string cmFilePathUuid::GetChecksumString( + const std::string& sourceFilename, const std::string& sourceRelPath, + const std::string& sourceRelSeed) +{ + std::string checksumBase64; + { + // Calculate the file ( seed + relative path + name ) checksum + std::vector hashBytes = + cmCryptoHash::New("SHA256")->ByteHashString( + (sourceRelSeed + sourceRelPath + sourceFilename).c_str()); + // Convert hash bytes to Base64 text string + std::vector base64Bytes(hashBytes.size() * 2, 0); + cmsysBase64_Encode(&hashBytes[0], hashBytes.size(), &base64Bytes[0], 0); + checksumBase64 = reinterpret_cast(&base64Bytes[0]); + } + // Base64 allows '/', '+' and '=' characters which are problematic + // when used in file names. Replace them with safer alternatives. + std::replace(checksumBase64.begin(), checksumBase64.end(), '/', '-'); + std::replace(checksumBase64.begin(), checksumBase64.end(), '+', '_'); + std::replace(checksumBase64.begin(), checksumBase64.end(), '=', '_'); + + return checksumBase64; +} diff --git a/Source/cmFilePathUuid.h b/Source/cmFilePathUuid.h new file mode 100644 index 0000000..42e89b1 --- /dev/null +++ b/Source/cmFilePathUuid.h @@ -0,0 +1,77 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2016 Sebastian Holtermann (sebholt at xwmw.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmFilePathUuid_h +#define cmFilePathUuid_h + +#include "cmStandardIncludes.h" + +#include +#include + +class cmMakefile; + +/** \class cmFilePathUuid + * @brief Generates a unique pathless file name with a checksum component + * calculated from the file path. + * + * The checksum is calculated from the relative file path to the + * closest known project directory. This guarantees reproducibility + * when source and build directory differ e.g. for different project + * build directories. + */ +class cmFilePathUuid +{ +public: + /// Maximum number of characters to use from the file name + static const size_t partLengthName = 14; + /// Maximum number of characters to use from the path checksum + static const size_t partLengthCheckSum = 14; + + /// @brief Initilizes the parent directories from a makefile + cmFilePathUuid(cmMakefile* makefile); + + /// @brief Initilizes the parent directories manually + cmFilePathUuid(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir); + + /* @brief Calculates and returns the uuid for a file path + * + * @arg outputPrefix optional string to prepend to the result + * @arg outputSuffix optional string to append to the result + */ + std::string get(const std::string& filePath, const char* outputPrefix = NULL, + const char* outputSuffix = NULL); + +private: + void initParentDirs(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir); + + /// Returns the relative path and the parent directory key string (seed) + void GetRelPathSeed(const std::string& filePath, std::string& sourceRelPath, + std::string& sourceRelSeed); + + std::string GetChecksumString(const std::string& sourceFilename, + const std::string& sourceRelPath, + const std::string& sourceRelSeed); + + /// Size of the parent directory list + static const size_t numParentDirs = 4; + /// List of (directory name, seed name) pairs + std::pair parentDirs[numParentDirs]; +}; + +#endif https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3a5f609cbb4ae63fca1eb87918767a4296d16e5f commit 3a5f609cbb4ae63fca1eb87918767a4296d16e5f Author: Sebastian Holtermann AuthorDate: Wed Aug 10 11:30:06 2016 +0200 Commit: Brad King CommitDate: Wed Aug 10 13:21:32 2016 -0400 cmCryptoHash: New ByteHash methods that return a byte vector diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx index 8d96421..9bd07a3 100644 --- a/Source/cmCryptoHash.cxx +++ b/Source/cmCryptoHash.cxx @@ -65,43 +65,57 @@ std::string cmCryptoHash::ByteHashToString( return res; } -std::string cmCryptoHash::HashString(const std::string& input) +std::vector cmCryptoHash::ByteHashString( + const std::string& input) { this->Initialize(); this->Append(reinterpret_cast(input.c_str()), static_cast(input.size())); - return ByteHashToString(this->Finalize()); + return this->Finalize(); } -std::string cmCryptoHash::HashFile(const std::string& file) +std::vector cmCryptoHash::ByteHashFile(const std::string& file) { cmsys::ifstream fin(file.c_str(), std::ios::in | std::ios::binary); - if (!fin) { - return ""; + if (fin) { + this->Initialize(); + { + // Should be efficient enough on most system: + cm_sha2_uint64_t buffer[512]; + char* buffer_c = reinterpret_cast(buffer); + unsigned char const* buffer_uc = + reinterpret_cast(buffer); + // 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_c, sizeof(buffer)); + if (int gcount = static_cast(fin.gcount())) { + this->Append(buffer_uc, gcount); + } + } + } + if (fin.eof()) { + // Success + return this->Finalize(); + } + // Finalize anyway + this->Finalize(); } + // Return without success + return std::vector(); +} - this->Initialize(); +std::string cmCryptoHash::HashString(const std::string& input) +{ + return ByteHashToString(this->ByteHashString(input)); +} - // Should be efficient enough on most system: - cm_sha2_uint64_t buffer[512]; - char* buffer_c = reinterpret_cast(buffer); - unsigned char const* buffer_uc = - reinterpret_cast(buffer); - // 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_c, sizeof(buffer)); - if (int gcount = static_cast(fin.gcount())) { - this->Append(buffer_uc, gcount); - } - } - if (fin.eof()) { - return ByteHashToString(this->Finalize()); - } - return ""; +std::string cmCryptoHash::HashFile(const std::string& file) +{ + return ByteHashToString(this->ByteHashFile(file)); } cmCryptoHashMD5::cmCryptoHashMD5() diff --git a/Source/cmCryptoHash.h b/Source/cmCryptoHash.h index ab50e82..4e92b06 100644 --- a/Source/cmCryptoHash.h +++ b/Source/cmCryptoHash.h @@ -23,22 +23,37 @@ class cmCryptoHash { public: virtual ~cmCryptoHash() {} + /// @brief Returns a new hash generator of the requested type /// @arg algo Hash type name. Supported hash types are /// MD5, SHA1, SHA224, SHA256, SHA384, SHA512 /// @return A valid auto pointer if algo is supported or /// an invalid/NULL pointer otherwise static CM_AUTO_PTR New(const char* algo); + /// @brief Converts a hex character to its binary value (4 bits) /// @arg input Hex character [0-9a-fA-F]. /// @arg output Binary value of the input character (4 bits) /// @return True if input was a valid hex character static bool IntFromHexDigit(char input, char& output); + /// @brief Converts a byte hash to a sequence of hex character pairs static std::string ByteHashToString(const std::vector& hash); + + /// @brief Calculates a binary hash from string input data + /// @return Binary hash vector + std::vector ByteHashString(const std::string& input); + + /// @brief Calculates a binary hash from file content + /// @see ByteHashString() + /// @return Non empty binary hash vector if the file was read successfully. + /// An empty vector otherwise. + std::vector ByteHashFile(const std::string& file); + /// @brief Calculates a hash string from string input data /// @return Sequence of hex characters pairs for each byte of the binary hash std::string HashString(const std::string& input); + /// @brief Calculates a hash string from file content /// @see HashString() /// @return Non empty hash string if the file was read successfully. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f582dba6664e5ea814f3b33c71ae4d83db17b996 commit f582dba6664e5ea814f3b33c71ae4d83db17b996 Author: Sebastian Holtermann AuthorDate: Wed Aug 10 11:08:15 2016 +0200 Commit: Brad King CommitDate: Wed Aug 10 13:21:32 2016 -0400 cmCryptoHash: Return byte vector from internal Finalize method Some callers may want the raw byte vector instead of the hex character string. Convert the internal implementation to use this so that we can later add public APIs to get it. diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx index 59b9abd..8d96421 100644 --- a/Source/cmCryptoHash.cxx +++ b/Source/cmCryptoHash.cxx @@ -70,7 +70,7 @@ std::string cmCryptoHash::HashString(const std::string& input) this->Initialize(); this->Append(reinterpret_cast(input.c_str()), static_cast(input.size())); - return this->Finalize(); + return ByteHashToString(this->Finalize()); } std::string cmCryptoHash::HashFile(const std::string& file) @@ -99,7 +99,7 @@ std::string cmCryptoHash::HashFile(const std::string& file) } } if (fin.eof()) { - return this->Finalize(); + return ByteHashToString(this->Finalize()); } return ""; } @@ -124,11 +124,11 @@ void cmCryptoHashMD5::Append(unsigned char const* buf, int sz) cmsysMD5_Append(this->MD5, buf, sz); } -std::string cmCryptoHashMD5::Finalize() +std::vector cmCryptoHashMD5::Finalize() { - char md5out[32]; - cmsysMD5_FinalizeHex(this->MD5, md5out); - return std::string(md5out, 32); + std::vector hash(16, 0); + cmsysMD5_Finalize(this->MD5, &hash[0]); + return hash; } #define cmCryptoHash_SHA_CLASS_IMPL(SHA) \ @@ -142,11 +142,11 @@ std::string cmCryptoHashMD5::Finalize() { \ SHA##_Update(this->SHA, buf, sz); \ } \ - std::string cmCryptoHash##SHA::Finalize() \ + std::vector cmCryptoHash##SHA::Finalize() \ { \ - char out[SHA##_DIGEST_STRING_LENGTH]; \ - SHA##_End(this->SHA, out); \ - return std::string(out, SHA##_DIGEST_STRING_LENGTH - 1); \ + std::vector hash(SHA##_DIGEST_LENGTH, 0); \ + SHA##_Final(&hash[0], this->SHA); \ + return hash; \ } cmCryptoHash_SHA_CLASS_IMPL(SHA1) cmCryptoHash_SHA_CLASS_IMPL(SHA224) diff --git a/Source/cmCryptoHash.h b/Source/cmCryptoHash.h index 80ab269..ab50e82 100644 --- a/Source/cmCryptoHash.h +++ b/Source/cmCryptoHash.h @@ -48,7 +48,7 @@ public: protected: virtual void Initialize() = 0; virtual void Append(unsigned char const*, int) = 0; - virtual std::string Finalize() = 0; + virtual std::vector Finalize() = 0; }; class cmCryptoHashMD5 : public cmCryptoHash @@ -62,7 +62,7 @@ public: protected: void Initialize() CM_OVERRIDE; void Append(unsigned char const* buf, int sz) CM_OVERRIDE; - std::string Finalize() CM_OVERRIDE; + std::vector Finalize() CM_OVERRIDE; }; #define cmCryptoHash_SHA_CLASS_DECL(SHA) \ @@ -77,7 +77,7 @@ protected: protected: \ virtual void Initialize(); \ virtual void Append(unsigned char const* buf, int sz); \ - virtual std::string Finalize(); \ + virtual std::vector Finalize(); \ } cmCryptoHash_SHA_CLASS_DECL(SHA1); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=74f0d4abcd8de84283858fe144772e688669e46a commit 74f0d4abcd8de84283858fe144772e688669e46a Author: Sebastian Holtermann AuthorDate: Wed Aug 10 10:35:19 2016 +0200 Commit: Brad King CommitDate: Wed Aug 10 13:09:55 2016 -0400 cmCryptoHash: New byte hash to string function diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx index 8d60c1f..59b9abd 100644 --- a/Source/cmCryptoHash.cxx +++ b/Source/cmCryptoHash.cxx @@ -34,6 +34,37 @@ CM_AUTO_PTR cmCryptoHash::New(const char* algo) } } +bool cmCryptoHash::IntFromHexDigit(char input, char& output) +{ + if (input >= '0' && input <= '9') { + output = char(input - '0'); + return true; + } else if (input >= 'a' && input <= 'f') { + output = char(input - 'a' + 0xA); + return true; + } else if (input >= 'A' && input <= 'F') { + output = char(input - 'A' + 0xA); + return true; + } + return false; +} + +std::string cmCryptoHash::ByteHashToString( + const std::vector& hash) +{ + // 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' }; + + std::string res; + for (std::vector::const_iterator vit = hash.begin(); + vit != hash.end(); ++vit) { + res.push_back(hex[(*vit) >> 4]); + res.push_back(hex[(*vit) & 0xF]); + } + return res; +} + std::string cmCryptoHash::HashString(const std::string& input) { this->Initialize(); diff --git a/Source/cmCryptoHash.h b/Source/cmCryptoHash.h index 84dea9b..80ab269 100644 --- a/Source/cmCryptoHash.h +++ b/Source/cmCryptoHash.h @@ -29,6 +29,13 @@ public: /// @return A valid auto pointer if algo is supported or /// an invalid/NULL pointer otherwise static CM_AUTO_PTR New(const char* algo); + /// @brief Converts a hex character to its binary value (4 bits) + /// @arg input Hex character [0-9a-fA-F]. + /// @arg output Binary value of the input character (4 bits) + /// @return True if input was a valid hex character + static bool IntFromHexDigit(char input, char& output); + /// @brief Converts a byte hash to a sequence of hex character pairs + static std::string ByteHashToString(const std::vector& hash); /// @brief Calculates a hash string from string input data /// @return Sequence of hex characters pairs for each byte of the binary hash std::string HashString(const std::string& input); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=94c29976d0020b48a5c565234b71f8f6abaf08be commit 94c29976d0020b48a5c565234b71f8f6abaf08be Author: Sebastian Holtermann AuthorDate: Wed Aug 10 09:54:49 2016 +0200 Commit: Brad King CommitDate: Wed Aug 10 13:09:54 2016 -0400 cmCryptoHash: Documentation comments diff --git a/Source/cmCryptoHash.h b/Source/cmCryptoHash.h index 6aaaf93..84dea9b 100644 --- a/Source/cmCryptoHash.h +++ b/Source/cmCryptoHash.h @@ -16,12 +16,26 @@ #include +/** + * @brief Abstract base class for cryptographic hash generators + */ class cmCryptoHash { public: virtual ~cmCryptoHash() {} + /// @brief Returns a new hash generator of the requested type + /// @arg algo Hash type name. Supported hash types are + /// MD5, SHA1, SHA224, SHA256, SHA384, SHA512 + /// @return A valid auto pointer if algo is supported or + /// an invalid/NULL pointer otherwise static CM_AUTO_PTR New(const char* algo); + /// @brief Calculates a hash string from string input data + /// @return Sequence of hex characters pairs for each byte of the binary hash std::string HashString(const std::string& input); + /// @brief Calculates a hash string from file content + /// @see HashString() + /// @return Non empty hash string if the file was read successfully. + /// An empty string otherwise. std::string HashFile(const std::string& file); protected: ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 10 15:40:31 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 10 Aug 2016 15:40:31 -0400 (EDT) Subject: [Cmake-commits] CMake branch, dashboard, updated. e92ba4123b610e11f39e5d9d08637cfc496dd8c0 Message-ID: <20160810194031.5868BF2C4A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, dashboard has been updated via e92ba4123b610e11f39e5d9d08637cfc496dd8c0 (commit) from cb56d71de1bd40e06db17cb0266d1fbeabea75a3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e92ba4123b610e11f39e5d9d08637cfc496dd8c0 commit e92ba4123b610e11f39e5d9d08637cfc496dd8c0 Author: Brad King AuthorDate: Tue Aug 9 11:08:56 2016 -0400 Commit: Brad King CommitDate: Tue Aug 9 11:08:56 2016 -0400 kwsys_common: Enable launchers and make program for Ninja generator diff --git a/kwsys_common.cmake b/kwsys_common.cmake index 02b4008..8050f2c 100644 --- a/kwsys_common.cmake +++ b/kwsys_common.cmake @@ -113,8 +113,8 @@ if(NOT DEFINED CTEST_BUILD_CONFIGURATION) endif() # Choose CTest reporting mode. -if(NOT "${CTEST_CMAKE_GENERATOR}" MATCHES "Make") - # Launchers work only with Makefile generators. +if(NOT "${CTEST_CMAKE_GENERATOR}" MATCHES "Make|Ninja") + # Launchers work only with Makefile and Ninja generators. set(CTEST_USE_LAUNCHERS 0) elseif(NOT DEFINED CTEST_USE_LAUNCHERS) set(CTEST_USE_LAUNCHERS 1) @@ -304,7 +304,7 @@ set(ENV{LC_ALL} C) macro(write_cache) set(cache_build_type "") set(cache_make_program "") - if(CTEST_CMAKE_GENERATOR MATCHES "Make") + if(CTEST_CMAKE_GENERATOR MATCHES "Make|Ninja") set(cache_build_type CMAKE_BUILD_TYPE:STRING=${CTEST_BUILD_CONFIGURATION}) if(CMAKE_MAKE_PROGRAM) set(cache_make_program CMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}) ----------------------------------------------------------------------- Summary of changes: kwsys_common.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) hooks/post-receive -- CMake From kwrobot at kitware.com Thu Aug 11 00:01:08 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Thu, 11 Aug 2016 00:01:08 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-608-g3c4d2e8 Message-ID: <20160811040108.18927F541C@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 3c4d2e84d2659459eeecd2b9da0fceb22a2fb852 (commit) from 50ada755e3c133149f76dddfd0921eb7a9d32506 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3c4d2e84d2659459eeecd2b9da0fceb22a2fb852 commit 3c4d2e84d2659459eeecd2b9da0fceb22a2fb852 Author: Kitware Robot AuthorDate: Thu Aug 11 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Thu Aug 11 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index f354b57..a4e305a 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160810) +set(CMake_VERSION_PATCH 20160811) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 11 13:48:41 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 11 Aug 2016 13:48:41 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-613-gf203694 Message-ID: <20160811174844.3A3D1F42D0@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via f203694bb848e7a4bd2c623348053532b1b4e589 (commit) via 3a5f609cbb4ae63fca1eb87918767a4296d16e5f (commit) via f582dba6664e5ea814f3b33c71ae4d83db17b996 (commit) via 74f0d4abcd8de84283858fe144772e688669e46a (commit) via 94c29976d0020b48a5c565234b71f8f6abaf08be (commit) from 3c4d2e84d2659459eeecd2b9da0fceb22a2fb852 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f203694bb848e7a4bd2c623348053532b1b4e589 commit f203694bb848e7a4bd2c623348053532b1b4e589 Merge: 3c4d2e8 3a5f609 Author: Brad King AuthorDate: Thu Aug 11 13:48:37 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 11 13:48:37 2016 -0400 Merge topic 'cmCryptoHash-raw-digest' 3a5f609c cmCryptoHash: New ByteHash methods that return a byte vector f582dba6 cmCryptoHash: Return byte vector from internal Finalize method 74f0d4ab cmCryptoHash: New byte hash to string function 94c29976 cmCryptoHash: Documentation comments ----------------------------------------------------------------------- Summary of changes: Source/cmCryptoHash.cxx | 111 +++++++++++++++++++++++++++++++++-------------- Source/cmCryptoHash.h | 42 ++++++++++++++++-- 2 files changed, 117 insertions(+), 36 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 11 13:49:01 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 11 Aug 2016 13:49:01 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1236-g7dbdc86 Message-ID: <20160811174901.B5BB8F43F3@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 7dbdc8675b1235e2f416c05dbb9b00f07c956ade (commit) via f203694bb848e7a4bd2c623348053532b1b4e589 (commit) via 3c4d2e84d2659459eeecd2b9da0fceb22a2fb852 (commit) from df237068ee8618e19354d2fec3f0f99b5a9fee85 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7dbdc8675b1235e2f416c05dbb9b00f07c956ade commit 7dbdc8675b1235e2f416c05dbb9b00f07c956ade Merge: df23706 f203694 Author: Brad King AuthorDate: Thu Aug 11 13:48:52 2016 -0400 Commit: Brad King CommitDate: Thu Aug 11 13:48:52 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From kwrobot at kitware.com Fri Aug 12 00:01:06 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Fri, 12 Aug 2016 00:01:06 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-614-gf99df80 Message-ID: <20160812040106.E737DF5780@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via f99df80794df7acc383d93d47b5da3ac8450e117 (commit) from f203694bb848e7a4bd2c623348053532b1b4e589 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f99df80794df7acc383d93d47b5da3ac8450e117 commit f99df80794df7acc383d93d47b5da3ac8450e117 Author: Kitware Robot AuthorDate: Fri Aug 12 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Fri Aug 12 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index a4e305a..1e20881 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160811) +set(CMake_VERSION_PATCH 20160812) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 12 09:35:24 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 12 Aug 2016 09:35:24 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1239-g4f29b32 Message-ID: <20160812133526.815ECF5AED@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 4f29b3241f92887edc055c98b033953d2adea973 (commit) via 1aa5c1bec82537ccbff8e05ae989b8befbdd286e (commit) via aab1f6e984e81f732ec2dd5c33ff8f7bf604a0f2 (commit) from 7dbdc8675b1235e2f416c05dbb9b00f07c956ade (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4f29b3241f92887edc055c98b033953d2adea973 commit 4f29b3241f92887edc055c98b033953d2adea973 Merge: 7dbdc86 1aa5c1b Author: Brad King AuthorDate: Fri Aug 12 09:35:21 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 12 09:35:21 2016 -0400 Merge topic 'FindCUDA-fixes' into next 1aa5c1be FindCUDA: Fix missing librt on Linux when using static cuda runtime. aab1f6e9 FindCUDA: Restore default behavior of CUDA_USE_STATIC_CUDA_RUNTIME https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1aa5c1bec82537ccbff8e05ae989b8befbdd286e commit 1aa5c1bec82537ccbff8e05ae989b8befbdd286e Author: Stephen Sorley AuthorDate: Thu Aug 11 15:54:28 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 09:28:38 2016 -0400 FindCUDA: Fix missing librt on Linux when using static cuda runtime. Commit 7229ae72 (FindCUDA: Refactor Android(Tegra) support, 2016-04-19) changed the logic to only add librt to the link line for CUDA versions 6.5 and older. However, newer versions of CUDA still require librt. diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake index 972068b..78b716d 100644 --- a/Modules/FindCUDA.cmake +++ b/Modules/FindCUDA.cmake @@ -818,12 +818,13 @@ if(CUDA_USE_STATIC_CUDA_RUNTIME) else() unset(CMAKE_THREAD_PREFER_PTHREAD) endif() - endif() - if (UNIX AND NOT APPLE AND CUDA_VERSION VERSION_LESS "7.0") - # Before CUDA 7.0, there was librt that has things such as, clock_gettime, shm_open, and shm_unlink. - find_library(CUDA_rt_LIBRARY rt) - if (NOT CUDA_rt_LIBRARY) - message(WARNING "Expecting to find librt for libcudart_static, but didn't find it.") + + if(NOT APPLE) + #On Linux, you must link against librt when using the static cuda runtime. + find_library(CUDA_rt_LIBRARY rt) + if (NOT CUDA_rt_LIBRARY) + message(WARNING "Expecting to find librt for libcudart_static, but didn't find it.") + endif() endif() endif() endif() https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=aab1f6e984e81f732ec2dd5c33ff8f7bf604a0f2 commit aab1f6e984e81f732ec2dd5c33ff8f7bf604a0f2 Author: Stephen Sorley AuthorDate: Thu Aug 11 15:20:17 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 09:26:30 2016 -0400 FindCUDA: Restore default behavior of CUDA_USE_STATIC_CUDA_RUNTIME Fix bug introduced by commit 7229ae72 (FindCUDA: Refactor Android(Tegra) support, 2016-04-19). `CUDA_USE_STATIC_CUDA_RUNTIME` should be enabled by default if `cudart_static` is available, and silently disabled if it is not. diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake index d7c9d8a..972068b 100644 --- a/Modules/FindCUDA.cmake +++ b/Modules/FindCUDA.cmake @@ -779,18 +779,19 @@ if(CUDA_VERSION VERSION_EQUAL "3.0") ) endif() -if(CUDA_USE_STATIC_CUDA_RUNTIME AND NOT CUDA_VERSION VERSION_LESS "5.5") +if(NOT CUDA_VERSION VERSION_LESS "5.5") cuda_find_library_local_first(CUDA_cudart_static_LIBRARY cudart_static "static CUDA runtime library") mark_as_advanced(CUDA_cudart_static_LIBRARY) endif() if(CUDA_cudart_static_LIBRARY) - # Set whether to use the static cuda runtime. + # If static cudart available, use it by default, but provide a user-visible option to disable it. option(CUDA_USE_STATIC_CUDA_RUNTIME "Use the static version of the CUDA runtime library if available" ON) set(CUDA_CUDART_LIBRARY_VAR CUDA_cudart_static_LIBRARY) else() - option(CUDA_USE_STATIC_CUDA_RUNTIME "Use the static version of the CUDA runtime library if available" OFF) + # If not available, silently disable the option. + set(CUDA_USE_STATIC_CUDA_RUNTIME OFF CACHE INTERNAL "") set(CUDA_CUDART_LIBRARY_VAR CUDA_CUDART_LIBRARY) endif() ----------------------------------------------------------------------- Summary of changes: Modules/FindCUDA.cmake | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 12 10:31:08 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 12 Aug 2016 10:31:08 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1241-g2cd471c Message-ID: <20160812143108.ED647F5A51@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 2cd471cea4e4101180871087aa4d3080e0a040ac (commit) via a2d5c25a7a2b344ba7cf74d44c43bd6054263f59 (commit) from 4f29b3241f92887edc055c98b033953d2adea973 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2cd471cea4e4101180871087aa4d3080e0a040ac commit 2cd471cea4e4101180871087aa4d3080e0a040ac Merge: 4f29b32 a2d5c25 Author: Brad King AuthorDate: Fri Aug 12 10:31:08 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 12 10:31:08 2016 -0400 Merge topic 'GetPrerequisites-fix-regression' into next a2d5c25a GetPrerequisites: Fix regression in gp_resolved_file_type https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a2d5c25a7a2b344ba7cf74d44c43bd6054263f59 commit a2d5c25a7a2b344ba7cf74d44c43bd6054263f59 Author: Brad King AuthorDate: Fri Aug 12 10:18:43 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:24:48 2016 -0400 GetPrerequisites: Fix regression in gp_resolved_file_type Since commit v3.6.0-rc1~287^2 (GetPrerequisites: Fix gp_resolved_file_type on non-canonical paths, 2016-03-08) we accidentally convert relative paths (e.g. system dll file names) to absolute paths even when we do not know the base directory. Fix this by canonicalizing only paths that are already absolute. Closes: #16240 diff --git a/Modules/GetPrerequisites.cmake b/Modules/GetPrerequisites.cmake index aa5bf28..fb7bf93 100644 --- a/Modules/GetPrerequisites.cmake +++ b/Modules/GetPrerequisites.cmake @@ -500,7 +500,9 @@ function(gp_resolved_file_type original_file file exepath dirs type_var) if(NOT IS_ABSOLUTE "${original_file}") message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file") endif() - get_filename_component(original_file "${original_file}" ABSOLUTE) # canonicalize path + if(IS_ABSOLUTE "${original_file}") + get_filename_component(original_file "${original_file}" ABSOLUTE) # canonicalize path + endif() set(is_embedded 0) set(is_local 0) @@ -516,7 +518,9 @@ function(gp_resolved_file_type original_file file exepath dirs type_var) if(NOT IS_ABSOLUTE "${file}") gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file "${rpaths}") endif() - get_filename_component(resolved_file "${resolved_file}" ABSOLUTE) # canonicalize path + if(IS_ABSOLUTE "${resolved_file}") + get_filename_component(resolved_file "${resolved_file}" ABSOLUTE) # canonicalize path + endif() string(TOLOWER "${original_file}" original_lower) string(TOLOWER "${resolved_file}" lower) ----------------------------------------------------------------------- Summary of changes: Modules/GetPrerequisites.cmake | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) hooks/post-receive -- CMake From kwrobot at kitware.com Sat Aug 13 00:01:10 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Sat, 13 Aug 2016 00:01:10 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-615-g77c171a Message-ID: <20160813040110.A6E12F5820@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 77c171a37ce005399c8b81b32721f6e167a78913 (commit) from f99df80794df7acc383d93d47b5da3ac8450e117 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=77c171a37ce005399c8b81b32721f6e167a78913 commit 77c171a37ce005399c8b81b32721f6e167a78913 Author: Kitware Robot AuthorDate: Sat Aug 13 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Sat Aug 13 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 1e20881..8481ce2 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160812) +set(CMake_VERSION_PATCH 20160813) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From kwrobot at kitware.com Sun Aug 14 00:01:05 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Sun, 14 Aug 2016 00:01:05 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-616-g5726af6 Message-ID: <20160814040105.B22FFF56D6@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 5726af681a9eb9b1c8d2a1bee4c5c93e61f6e109 (commit) from 77c171a37ce005399c8b81b32721f6e167a78913 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5726af681a9eb9b1c8d2a1bee4c5c93e61f6e109 commit 5726af681a9eb9b1c8d2a1bee4c5c93e61f6e109 Author: Kitware Robot AuthorDate: Sun Aug 14 00:01:03 2016 -0400 Commit: Kitware Robot CommitDate: Sun Aug 14 00:01:03 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 8481ce2..b963882 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160813) +set(CMake_VERSION_PATCH 20160814) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From kwrobot at kitware.com Mon Aug 15 00:01:06 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Mon, 15 Aug 2016 00:01:06 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-617-g272a2bf Message-ID: <20160815040106.E54F7F53DC@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 272a2bf19d26bb325ae5c9dda9a885c64016918d (commit) from 5726af681a9eb9b1c8d2a1bee4c5c93e61f6e109 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=272a2bf19d26bb325ae5c9dda9a885c64016918d commit 272a2bf19d26bb325ae5c9dda9a885c64016918d Author: Kitware Robot AuthorDate: Mon Aug 15 00:01:03 2016 -0400 Commit: Kitware Robot CommitDate: Mon Aug 15 00:01:03 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index b963882..58b0448 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160814) +set(CMake_VERSION_PATCH 20160815) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 15 08:57:27 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 15 Aug 2016 08:57:27 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1243-gc1b34cc Message-ID: <20160815125727.C5C68F481F@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via c1b34ccff27b65a058d7c880941dd57a144e9541 (commit) via 61a607e8d43e0d02ff80cca6e60441f56a6741b5 (commit) from 2cd471cea4e4101180871087aa4d3080e0a040ac (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c1b34ccff27b65a058d7c880941dd57a144e9541 commit c1b34ccff27b65a058d7c880941dd57a144e9541 Merge: 2cd471c 61a607e Author: Brad King AuthorDate: Mon Aug 15 08:57:27 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 15 08:57:27 2016 -0400 Merge topic 'autogen-same-name' into next 61a607e8 Help: Document AUTORCC behavior for same .qrc name case https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=61a607e8d43e0d02ff80cca6e60441f56a6741b5 commit 61a607e8d43e0d02ff80cca6e60441f56a6741b5 Author: Sebastian Holtermann AuthorDate: Mon Aug 15 09:07:36 2016 +0200 Commit: Brad King CommitDate: Mon Aug 15 08:57:17 2016 -0400 Help: Document AUTORCC behavior for same .qrc name case diff --git a/Help/prop_tgt/AUTORCC.rst b/Help/prop_tgt/AUTORCC.rst index 8dce6b1..158fdf8 100644 --- a/Help/prop_tgt/AUTORCC.rst +++ b/Help/prop_tgt/AUTORCC.rst @@ -19,5 +19,10 @@ Additional command line options for rcc can be set via the The global property :prop_gbl:`AUTOGEN_TARGETS_FOLDER` can be used to group the autorcc targets together in an IDE, e.g. in MSVS. +When there are multiple ``.qrc`` files with the same name, CMake will +generate unspecified unique names for ``rcc``. Therefore if +``Q_INIT_RESOURCE()`` or ``Q_CLEANUP_RESOURCE()`` need to be used the +``.qrc`` file name must be unique. + See the :manual:`cmake-qt(7)` manual for more information on using CMake with Qt. ----------------------------------------------------------------------- Summary of changes: Help/prop_tgt/AUTORCC.rst | 5 +++++ 1 file changed, 5 insertions(+) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 15 08:59:45 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 15 Aug 2016 08:59:45 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-619-gd47abe4 Message-ID: <20160815125945.3B96DF49D9@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via d47abe40b6532095fa28f5f1305e2ecad5feb6b7 (commit) via a2d5c25a7a2b344ba7cf74d44c43bd6054263f59 (commit) from 272a2bf19d26bb325ae5c9dda9a885c64016918d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d47abe40b6532095fa28f5f1305e2ecad5feb6b7 commit d47abe40b6532095fa28f5f1305e2ecad5feb6b7 Merge: 272a2bf a2d5c25 Author: Brad King AuthorDate: Mon Aug 15 08:59:43 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 15 08:59:43 2016 -0400 Merge topic 'GetPrerequisites-fix-regression' a2d5c25a GetPrerequisites: Fix regression in gp_resolved_file_type ----------------------------------------------------------------------- Summary of changes: Modules/GetPrerequisites.cmake | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 15 08:59:48 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 15 Aug 2016 08:59:48 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-626-g33d4aff Message-ID: <20160815125948.40308F49D9@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 33d4aff50d50907d05b49c92ed01376264d84389 (commit) via 61a607e8d43e0d02ff80cca6e60441f56a6741b5 (commit) via e4f508e42397549cd966e47349d4030cb793c354 (commit) via 4e9b97d7397fd526e6b4e4ce43dd305cb8341ac8 (commit) via 41c9e14afb0bc7e68e4530f76329b7c11cdfa0e4 (commit) via 3c3b37b0bbd3fb78aa60a2b38184b6397d2ea47f (commit) via 0a5dd3c700f1873be217707aa89a805d009bac3e (commit) from d47abe40b6532095fa28f5f1305e2ecad5feb6b7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=33d4aff50d50907d05b49c92ed01376264d84389 commit 33d4aff50d50907d05b49c92ed01376264d84389 Merge: d47abe4 61a607e Author: Brad King AuthorDate: Mon Aug 15 08:59:46 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 15 08:59:46 2016 -0400 Merge topic 'autogen-same-name' 61a607e8 Help: Document AUTORCC behavior for same .qrc name case e4f508e4 Tests/QtAutogen: Test same moc/qrc source names in different directories 4e9b97d7 QtAutogen: Allow multiple qrc files with the same name 41c9e14a QtAutogen: Allow multiple moc files with the same name 3c3b37b0 QtAutogen: Use std:: instead of ::std:: 0a5dd3c7 cmFilePathUuid: Add class to generate deterministic unique file names ----------------------------------------------------------------------- Summary of changes: Help/prop_tgt/AUTORCC.rst | 5 ++ Source/CMakeLists.txt | 2 + Source/cmFilePathUuid.cxx | 132 +++++++++++++++++++++++++++++ Source/cmFilePathUuid.h | 77 +++++++++++++++++ Source/cmQtAutoGeneratorInitializer.cxx | 76 +++++++++-------- Source/cmQtAutoGenerators.cxx | 88 +++++++++++++------ Source/cmQtAutoGenerators.h | 6 +- Tests/QtAutogen/CMakeLists.txt | 4 + Tests/QtAutogen/sameName/CMakeLists.txt | 21 +++++ Tests/QtAutogen/sameName/aaa/bbb/data.qrc | 6 ++ Tests/QtAutogen/sameName/aaa/bbb/item.cpp | 10 +++ Tests/QtAutogen/sameName/aaa/bbb/item.hpp | 18 ++++ Tests/QtAutogen/sameName/aaa/data.qrc | 6 ++ Tests/QtAutogen/sameName/aaa/item.cpp | 8 ++ Tests/QtAutogen/sameName/aaa/item.hpp | 16 ++++ Tests/QtAutogen/sameName/bbb/aaa/data.qrc | 6 ++ Tests/QtAutogen/sameName/bbb/aaa/item.cpp | 10 +++ Tests/QtAutogen/sameName/bbb/aaa/item.hpp | 18 ++++ Tests/QtAutogen/sameName/bbb/data.qrc | 6 ++ Tests/QtAutogen/sameName/bbb/item.cpp | 8 ++ Tests/QtAutogen/sameName/bbb/item.hpp | 16 ++++ Tests/QtAutogen/sameName/ccc/data.qrc | 6 ++ Tests/QtAutogen/sameName/ccc/item.cpp | 23 +++++ Tests/QtAutogen/sameName/ccc/item.hpp | 16 ++++ Tests/QtAutogen/sameName/data.qrc | 5 ++ Tests/QtAutogen/sameName/item.cpp | 5 ++ Tests/QtAutogen/sameName/item.hpp | 13 +++ Tests/QtAutogen/sameName/main.cpp | 16 ++++ 28 files changed, 562 insertions(+), 61 deletions(-) create mode 100644 Source/cmFilePathUuid.cxx create mode 100644 Source/cmFilePathUuid.h create mode 100644 Tests/QtAutogen/sameName/CMakeLists.txt create mode 100644 Tests/QtAutogen/sameName/aaa/bbb/data.qrc create mode 100644 Tests/QtAutogen/sameName/aaa/bbb/item.cpp create mode 100644 Tests/QtAutogen/sameName/aaa/bbb/item.hpp create mode 100644 Tests/QtAutogen/sameName/aaa/data.qrc create mode 100644 Tests/QtAutogen/sameName/aaa/item.cpp create mode 100644 Tests/QtAutogen/sameName/aaa/item.hpp create mode 100644 Tests/QtAutogen/sameName/bbb/aaa/data.qrc create mode 100644 Tests/QtAutogen/sameName/bbb/aaa/item.cpp create mode 100644 Tests/QtAutogen/sameName/bbb/aaa/item.hpp create mode 100644 Tests/QtAutogen/sameName/bbb/data.qrc create mode 100644 Tests/QtAutogen/sameName/bbb/item.cpp create mode 100644 Tests/QtAutogen/sameName/bbb/item.hpp create mode 100644 Tests/QtAutogen/sameName/ccc/data.qrc create mode 100644 Tests/QtAutogen/sameName/ccc/item.cpp create mode 100644 Tests/QtAutogen/sameName/ccc/item.hpp create mode 100644 Tests/QtAutogen/sameName/data.qrc create mode 100644 Tests/QtAutogen/sameName/item.cpp create mode 100644 Tests/QtAutogen/sameName/item.hpp create mode 100644 Tests/QtAutogen/sameName/main.cpp hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 15 08:59:50 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 15 Aug 2016 08:59:50 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-629-g7fe5c79 Message-ID: <20160815125950.D1EA4F4AA6@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 7fe5c79dd07da5d23fc61070884a1efa95c0fafd (commit) via 1aa5c1bec82537ccbff8e05ae989b8befbdd286e (commit) via aab1f6e984e81f732ec2dd5c33ff8f7bf604a0f2 (commit) from 33d4aff50d50907d05b49c92ed01376264d84389 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7fe5c79dd07da5d23fc61070884a1efa95c0fafd commit 7fe5c79dd07da5d23fc61070884a1efa95c0fafd Merge: 33d4aff 1aa5c1b Author: Brad King AuthorDate: Mon Aug 15 08:59:48 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 15 08:59:48 2016 -0400 Merge topic 'FindCUDA-fixes' 1aa5c1be FindCUDA: Fix missing librt on Linux when using static cuda runtime. aab1f6e9 FindCUDA: Restore default behavior of CUDA_USE_STATIC_CUDA_RUNTIME ----------------------------------------------------------------------- Summary of changes: Modules/FindCUDA.cmake | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 15 09:00:21 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 15 Aug 2016 09:00:21 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1251-gb3969f3 Message-ID: <20160815130021.51E68F49D9@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via b3969f32b26ac79586431b90bb0f3cfc5e426b7f (commit) via 7fe5c79dd07da5d23fc61070884a1efa95c0fafd (commit) via 33d4aff50d50907d05b49c92ed01376264d84389 (commit) via d47abe40b6532095fa28f5f1305e2ecad5feb6b7 (commit) via 272a2bf19d26bb325ae5c9dda9a885c64016918d (commit) via 5726af681a9eb9b1c8d2a1bee4c5c93e61f6e109 (commit) via 77c171a37ce005399c8b81b32721f6e167a78913 (commit) via f99df80794df7acc383d93d47b5da3ac8450e117 (commit) from c1b34ccff27b65a058d7c880941dd57a144e9541 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b3969f32b26ac79586431b90bb0f3cfc5e426b7f commit b3969f32b26ac79586431b90bb0f3cfc5e426b7f Merge: c1b34cc 7fe5c79 Author: Brad King AuthorDate: Mon Aug 15 09:00:13 2016 -0400 Commit: Brad King CommitDate: Mon Aug 15 09:00:13 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 15 09:29:40 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 15 Aug 2016 09:29:40 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1253-ga63f6c7 Message-ID: <20160815132942.35FA8F561F@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via a63f6c7ac7e406abe9c12a524bf3f11b1666f74f (commit) via 8ba204a69602ca8744aeec4ca3d808c964715ed5 (commit) from b3969f32b26ac79586431b90bb0f3cfc5e426b7f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a63f6c7ac7e406abe9c12a524bf3f11b1666f74f commit a63f6c7ac7e406abe9c12a524bf3f11b1666f74f Merge: b3969f3 8ba204a Author: Brad King AuthorDate: Mon Aug 15 09:29:39 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 15 09:29:39 2016 -0400 Merge topic 'FindMatlab-mingw' into next 8ba204a6 FindMatlab: Use pre-built libraries for MinGW if needed https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8ba204a69602ca8744aeec4ca3d808c964715ed5 commit 8ba204a69602ca8744aeec4ca3d808c964715ed5 Author: Sebastian Niemann AuthorDate: Fri Aug 12 23:39:27 2016 +0200 Commit: Brad King CommitDate: Mon Aug 15 09:28:54 2016 -0400 FindMatlab: Use pre-built libraries for MinGW if needed diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake index 956dad2..46285aa 100644 --- a/Modules/FindMatlab.cmake +++ b/Modules/FindMatlab.cmake @@ -1287,7 +1287,11 @@ set(Matlab_EXTERN_LIBRARY_DIR ${Matlab_ROOT_DIR}/extern/lib/${_matlab_bin_prefix}${_matlab_current_suffix}) if(WIN32) - set(_matlab_lib_dir_for_search ${Matlab_EXTERN_LIBRARY_DIR}/microsoft) + if(MINGW) + set(_matlab_lib_dir_for_search ${Matlab_EXTERN_LIBRARY_DIR}/mingw64) + else() + set(_matlab_lib_dir_for_search ${Matlab_EXTERN_LIBRARY_DIR}/microsoft) + endif() set(_matlab_lib_prefix_for_search "lib") else() set(_matlab_lib_dir_for_search ${Matlab_BINARIES_DIR}) ----------------------------------------------------------------------- Summary of changes: Modules/FindMatlab.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) hooks/post-receive -- CMake From ben.boeckel at kitware.com Mon Aug 15 09:34:49 2016 From: ben.boeckel at kitware.com (Ben Boeckel) Date: Mon, 15 Aug 2016 09:34:49 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1255-g7d693f7 Message-ID: <20160815133449.D76F4F5716@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 7d693f72615cdef461fc3f22b5aefc7c5d6a93f1 (commit) via 2bdba83e4bbd5435ee6faf5a2eedec4f0d0dfb0a (commit) from a63f6c7ac7e406abe9c12a524bf3f11b1666f74f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7d693f72615cdef461fc3f22b5aefc7c5d6a93f1 commit 7d693f72615cdef461fc3f22b5aefc7c5d6a93f1 Merge: a63f6c7 2bdba83 Author: Ben Boeckel AuthorDate: Mon Aug 15 09:34:48 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 15 09:34:48 2016 -0400 Merge topic 'issue-tracker-urls' into next 2bdba83e issues: update references to the CMake issue tracker https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2bdba83e4bbd5435ee6faf5a2eedec4f0d0dfb0a commit 2bdba83e4bbd5435ee6faf5a2eedec4f0d0dfb0a Author: Ben Boeckel AuthorDate: Fri Aug 12 15:06:35 2016 -0400 Commit: Ben Boeckel CommitDate: Mon Aug 15 09:34:06 2016 -0400 issues: update references to the CMake issue tracker References to specific comments are left as-is since comments were not migrated. diff --git a/Modules/CMakeDetermineCCompiler.cmake b/Modules/CMakeDetermineCCompiler.cmake index 73d9fb3..c566f39 100644 --- a/Modules/CMakeDetermineCCompiler.cmake +++ b/Modules/CMakeDetermineCCompiler.cmake @@ -105,7 +105,7 @@ if(NOT CMAKE_C_COMPILER_ID_RUN) CMAKE_C_COMPILER_ID_PLATFORM_CONTENT) # The IAR compiler produces weird output. - # See https://cmake.org/Bug/view.php?id=10176#c19598 + # See https://gitlab.kitware.com/cmake/cmake/issues/10176#note_153591 list(APPEND CMAKE_C_COMPILER_ID_VENDORS IAR) set(CMAKE_C_COMPILER_ID_VENDOR_FLAGS_IAR ) set(CMAKE_C_COMPILER_ID_VENDOR_REGEX_IAR "IAR .+ Compiler") diff --git a/Modules/CMakeDetermineCXXCompiler.cmake b/Modules/CMakeDetermineCXXCompiler.cmake index 063b68e..fb4155b 100644 --- a/Modules/CMakeDetermineCXXCompiler.cmake +++ b/Modules/CMakeDetermineCXXCompiler.cmake @@ -97,7 +97,7 @@ if(NOT CMAKE_CXX_COMPILER_ID_RUN) CMAKE_CXX_COMPILER_ID_PLATFORM_CONTENT) # The IAR compiler produces weird output. - # See https://cmake.org/Bug/view.php?id=10176#c19598 + # See https://gitlab.kitware.com/cmake/cmake/issues/10176#note_153591 list(APPEND CMAKE_CXX_COMPILER_ID_VENDORS IAR) set(CMAKE_CXX_COMPILER_ID_VENDOR_FLAGS_IAR ) set(CMAKE_CXX_COMPILER_ID_VENDOR_REGEX_IAR "IAR .+ Compiler") diff --git a/Modules/CMakeFindEclipseCDT4.cmake b/Modules/CMakeFindEclipseCDT4.cmake index 5bf738a..e158a73 100644 --- a/Modules/CMakeFindEclipseCDT4.cmake +++ b/Modules/CMakeFindEclipseCDT4.cmake @@ -35,7 +35,7 @@ function(_FIND_ECLIPSE_VERSION) if(NOT DEFINED CMAKE_ECLIPSE_VERSION) if(CMAKE_ECLIPSE_EXECUTABLE) - # use REALPATH to resolve symlinks (http://public.kitware.com/Bug/view.php?id=13036) + # use REALPATH to resolve symlinks (https://gitlab.kitware.com/cmake/cmake/issues/13036) get_filename_component(_REALPATH_CMAKE_ECLIPSE_EXECUTABLE "${CMAKE_ECLIPSE_EXECUTABLE}" REALPATH) get_filename_component(_ECLIPSE_DIR "${_REALPATH_CMAKE_ECLIPSE_EXECUTABLE}" PATH) file(GLOB _ECLIPSE_FEATURE_DIR "${_ECLIPSE_DIR}/features/org.eclipse.platform*") diff --git a/Modules/Compiler/IAR.cmake b/Modules/Compiler/IAR.cmake index 8c6c3f6..8c45276 100644 --- a/Modules/Compiler/IAR.cmake +++ b/Modules/Compiler/IAR.cmake @@ -1,6 +1,6 @@ # This file is processed when the IAR compiler is used for a C or C++ file # Documentation can be downloaded here: http://www.iar.com/website1/1.0.1.0/675/1/ -# The initial feature request is here: https://cmake.org/Bug/view.php?id=10176 +# The initial feature request is here: https://gitlab.kitware.com/cmake/cmake/issues/10176 # It also contains additional links and information. if(_IAR_CMAKE_LOADED) @@ -39,7 +39,8 @@ endif() if(NOT IAR_TARGET_ARCHITECTURE) message(FATAL_ERROR "The IAR compiler for this architecture is not yet supported " - " by CMake. Please go to https://cmake.org/Bug and enter a feature request there.") + "by CMake. Please go to https://gitlab.kitware.com/cmake/cmake/issues " + "and enter a feature request there.") endif() set(CMAKE_LINKER "${CMAKE_IAR_LINKER}" CACHE FILEPATH "The IAR linker" FORCE) diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index fc01976..e27eb72 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -2231,7 +2231,7 @@ function(_ep_add_configure_command name) # If anything about the configure command changes, (command itself, cmake # used, cmake args or cmake generator) then re-run the configure step. - # Fixes issue http://public.kitware.com/Bug/view.php?id=10258 + # Fixes issue https://gitlab.kitware.com/cmake/cmake/issues/10258 # if(NOT EXISTS ${tmp_dir}/${name}-cfgcmd.txt.in) file(WRITE ${tmp_dir}/${name}-cfgcmd.txt.in "cmd='\@cmd\@'\n") diff --git a/Modules/FindHDF5.cmake b/Modules/FindHDF5.cmake index a898386..5e0996c 100644 --- a/Modules/FindHDF5.cmake +++ b/Modules/FindHDF5.cmake @@ -639,7 +639,7 @@ if( NOT HDF5_FOUND ) if(UNIX AND HDF5_USE_STATIC_LIBRARIES) # According to bug 1643 on the CMake bug tracker, this is the # preferred method for searching for a static library. - # See https://cmake.org/Bug/view.php?id=1643. We search + # See https://gitlab.kitware.com/cmake/cmake/issues/1643. We search # first for the full static library name, but fall back to a # generic search on the name if the static search fails. set( THIS_LIBRARY_SEARCH_DEBUG @@ -676,7 +676,7 @@ if( NOT HDF5_FOUND ) if(UNIX AND HDF5_USE_STATIC_LIBRARIES) # According to bug 1643 on the CMake bug tracker, this is the # preferred method for searching for a static library. - # See https://cmake.org/Bug/view.php?id=1643. We search + # See https://gitlab.kitware.com/cmake/cmake/issues/1643. We search # first for the full static library name, but fall back to a # generic search on the name if the static search fails. set( THIS_LIBRARY_SEARCH_DEBUG diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index 3a9bb9b..0ded17a 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -750,7 +750,7 @@ std::string cmExtraCodeBlocksGenerator::BuildMakeCommand( if (generator == "NMake Makefiles") { // For Windows ConvertToOutputPath already adds quotes when required. // These need to be escaped, see - // http://public.kitware.com/Bug/view.php?id=13952 + // https://gitlab.kitware.com/cmake/cmake/issues/13952 std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile); command += " /NOLOGO /f "; command += makefileName; @@ -758,7 +758,7 @@ std::string cmExtraCodeBlocksGenerator::BuildMakeCommand( command += target; } else if (generator == "MinGW Makefiles") { // no escaping of spaces in this case, see - // http://public.kitware.com/Bug/view.php?id=10014 + // https://gitlab.kitware.com/cmake/cmake/issues/10014 std::string makefileName = makefile; command += " -f \""; command += makefileName; diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index 8091bcf..7a277c0 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -404,8 +404,8 @@ void cmExtraEclipseCDT4Generator::CreateProjectFile() if (this->IsOutOfSourceBuild) { // create a linked resource to CMAKE_SOURCE_DIR // (this is not done anymore for each project because of - // http://public.kitware.com/Bug/view.php?id=9978 and because I found it - // actually quite confusing in bigger projects with many directories and + // https://gitlab.kitware.com/cmake/cmake/issues/9978 and because I found + // it actually quite confusing in bigger projects with many directories and // projects, Alex std::string sourceLinkedResourceName = "[Source directory]"; diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index b6bad60..5c909c8 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -302,7 +302,7 @@ std::string cmExtraSublimeTextGenerator::BuildMakeCommand( std::string makefileName; if (generator == "MinGW Makefiles") { // no escaping of spaces in this case, see - // http://public.kitware.com/Bug/view.php?id=10014 + // https://gitlab.kitware.com/cmake/cmake/issues/10014 makefileName = makefile; } else { makefileName = cmSystemTools::ConvertToOutputPath(makefile); diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index d5634e8..f0df65e 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -97,7 +97,7 @@ static void GetCompileDefinitionsAndDirectories( std::vector includeDirs; cmLocalGenerator* localGen = target->GetLocalGenerator(); // Get the include dirs for this target, without stripping the implicit - // include dirs off, see http://public.kitware.com/Bug/view.php?id=13667 + // include dirs off, see https://gitlab.kitware.com/cmake/cmake/issues/13667 localGen->GetIncludeDirectories(includeDirs, target, "CXX", config, false); incs = cmJoin(includeDirs, ";"); diff --git a/Tests/CPackComponents/Issue 7470.html b/Tests/CPackComponents/Issue 7470.html index 12df2c8..c2a1688 100644 --- a/Tests/CPackComponents/Issue 7470.html +++ b/Tests/CPackComponents/Issue 7470.html @@ -3,7 +3,7 @@ The install rule for this file demonstrates the problem described in
CMake issue #7470:

- -http://public.kitware.com/Bug/view.php?id=7470
+ +https://gitlab.kitware.com/cmake/cmake/issues/7470
diff --git a/Tests/CTestLimitDashJ/CMakeLists.txt b/Tests/CTestLimitDashJ/CMakeLists.txt index 0c5950c..92d743f 100644 --- a/Tests/CTestLimitDashJ/CMakeLists.txt +++ b/Tests/CTestLimitDashJ/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.8) project(CTestLimitDashJ NONE) -# This file demonstrates http://public.kitware.com/Bug/view.php?id=12904 +# This file demonstrates https://gitlab.kitware.com/cmake/cmake/issues/12904 # when configured with CMake 2.8.10.2 and earlier, and when running # "ctest -j 4" in the resulting build tree. This example is hard-coded # to assume -j 4 just to reproduce the issue easily. Adjust the ----------------------------------------------------------------------- Summary of changes: Modules/CMakeDetermineCCompiler.cmake | 2 +- Modules/CMakeDetermineCXXCompiler.cmake | 2 +- Modules/CMakeFindEclipseCDT4.cmake | 2 +- Modules/Compiler/IAR.cmake | 5 +++-- Modules/ExternalProject.cmake | 2 +- Modules/FindHDF5.cmake | 4 ++-- Source/cmExtraCodeBlocksGenerator.cxx | 4 ++-- Source/cmExtraEclipseCDT4Generator.cxx | 4 ++-- Source/cmExtraSublimeTextGenerator.cxx | 2 +- Source/cmQtAutoGeneratorInitializer.cxx | 2 +- Tests/CPackComponents/Issue 7470.html | 4 ++-- Tests/CTestLimitDashJ/CMakeLists.txt | 2 +- 12 files changed, 18 insertions(+), 17 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Mon Aug 15 16:13:59 2016 From: brad.king at kitware.com (Brad King) Date: Mon, 15 Aug 2016 16:13:59 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1257-g7a4d351 Message-ID: <20160815201359.5795FF3AF2@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 7a4d3516aedece0736be4c1ad1702522a3526dd6 (commit) via eaccde1e472baaadce7f8417dbc46ee41cde09ad (commit) from 7d693f72615cdef461fc3f22b5aefc7c5d6a93f1 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7a4d3516aedece0736be4c1ad1702522a3526dd6 commit 7a4d3516aedece0736be4c1ad1702522a3526dd6 Merge: 7d693f7 eaccde1 Author: Brad King AuthorDate: Mon Aug 15 16:13:57 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 15 16:13:57 2016 -0400 Merge topic 'ExternalProject-SOURCE_SUBDIR' into next eaccde1e Add SOURCE_SUBDIR option to ExternalProject https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=eaccde1e472baaadce7f8417dbc46ee41cde09ad commit eaccde1e472baaadce7f8417dbc46ee41cde09ad Author: Matthew Woehlke AuthorDate: Mon Aug 15 14:42:22 2016 -0400 Commit: Matthew Woehlke CommitDate: Mon Aug 15 14:42:22 2016 -0400 Add SOURCE_SUBDIR option to ExternalProject Add a new SOURCE_SUBDIR option to ExternalProject_Add that allows specifying the location of the CMakeLists.txt to use as the project root relative to the SOURCE_DIR. This is helpful for projects that have odd layouts, or projects that provide both a superbuild and project-only build depending on which CMakeLists.txt is used. See also http://stackoverflow.com/questions/30028117. Fixes #15118. diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index 2ff18fc..634ef42 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -98,6 +98,8 @@ Create custom targets to build projects in external trees ``SOURCE_DIR `` Source dir to be used for build + ``SOURCE_SUBDIR `` + Path to source CMakeLists.txt relative to ``SOURCE_DIR`` ``CONFIGURE_COMMAND ...`` Build tree configuration command ``CMAKE_COMMAND /.../cmake`` @@ -236,6 +238,11 @@ Create custom targets to build projects in external trees interpreted with respect to the build directory corresponding to the source directory in which ``ExternalProject_Add`` is invoked. + If ``SOURCE_SUBDIR`` is set and no ``CONFIGURE_COMMAND`` is specified, the + configure command will run CMake using the ``CMakeLists.txt`` located in the + relative path specified by ``SOURCE_SUBDIR``, relative to the ``SOURCE_DIR``. + If no ``SOURCE_SUBDIR`` is given, ``SOURCE_DIR`` is used. + If ``SOURCE_DIR`` is explicitly set to an existing directory the project will be built from it. Otherwise a download step must be specified using one of the ``DOWNLOAD_COMMAND``, ``CVS_*``, ``SVN_*``, or ``URL`` @@ -287,8 +294,8 @@ Create custom targets to build projects in external trees The command line, comment, working directory, and byproducts of every standard and custom step are processed to replace tokens ````, - ````, ````, and ```` with - corresponding property values. + ````, ````, ````, and ```` + with corresponding property values. Any builtin step that specifies a ``_COMMAND cmd...`` or custom step that specifies a ``COMMAND cmd...`` may specify additional command @@ -1064,6 +1071,13 @@ function(_ep_set_directories name) endif() set_property(TARGET ${name} PROPERTY _EP_${VAR}_DIR "${${var}_dir}") endforeach() + get_property(source_subdir TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR) + if(NOT source_subdir) + set_property(TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR ".") + elseif(IS_ABSOLUTE "${source_subdir}") + message(FATAL_ERROR + "External project ${name} has non-relative SOURCE_SUBDIR!") + endif() if(build_in_source) get_property(source_dir TARGET ${name} PROPERTY _EP_SOURCE_DIR) set_property(TARGET ${name} PROPERTY _EP_BINARY_DIR "${source_dir}") @@ -1095,7 +1109,7 @@ macro(_ep_replace_location_tags target_name) set(vars ${ARGN}) foreach(var ${vars}) if(${var}) - foreach(dir SOURCE_DIR BINARY_DIR INSTALL_DIR TMP_DIR DOWNLOADED_FILE) + foreach(dir SOURCE_DIR SOURCE_SUBDIR BINARY_DIR INSTALL_DIR TMP_DIR DOWNLOADED_FILE) get_property(val TARGET ${target_name} PROPERTY _EP_${dir}) string(REPLACE "<${dir}>" "${val}" ${var} "${${var}}") endforeach() @@ -2131,7 +2145,7 @@ endfunction() # TODO: Make sure external projects use the proper compiler function(_ep_add_configure_command name) - ExternalProject_Get_Property(${name} source_dir binary_dir tmp_dir) + ExternalProject_Get_Property(${name} source_dir source_subdir binary_dir tmp_dir) # Depend on other external projects (file-level). set(file_deps) @@ -2209,7 +2223,11 @@ function(_ep_add_configure_command name) endif() endif() - list(APPEND cmd "${source_dir}") + if(source_subdir STREQUAL ".") + list(APPEND cmd "${source_dir}") + else() + list(APPEND cmd "${source_dir}/${source_subdir}") + endif() endif() # If anything about the configure command changes, (command itself, cmake diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index f21e430..071da41 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1441,6 +1441,18 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release ) list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectSubdir") + add_test(NAME ExternalProjectSourceSubdir + COMMAND ${CMAKE_CTEST_COMMAND} -C $ + --build-and-test + "${CMake_SOURCE_DIR}/Tests/ExternalProjectSourceSubdir" + "${CMake_BINARY_DIR}/Tests/ExternalProjectSourceSubdir" + ${build_generator_args} + --build-project ExternalProjectSourceSubdir + --force-new-ctest-process + --build-options ${build_options} + ) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectSourceSubdir") + add_test(ExternalProjectLocal ${CMAKE_CTEST_COMMAND} --build-and-test "${CMake_SOURCE_DIR}/Tests/ExternalProjectLocal" diff --git a/Tests/ExternalProjectSourceSubdir/CMakeLists.txt b/Tests/ExternalProjectSourceSubdir/CMakeLists.txt new file mode 100644 index 0000000..4688acf --- /dev/null +++ b/Tests/ExternalProjectSourceSubdir/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.6) +project(ExternalProjectSourceSubdir NONE) +include(ExternalProject) + +ExternalProject_Add(Example + SOURCE_SUBDIR subdir + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Example + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/Example + INSTALL_COMMAND "" + ) diff --git a/Tests/ExternalProjectSourceSubdir/Example/subdir/CMakeLists.txt b/Tests/ExternalProjectSourceSubdir/Example/subdir/CMakeLists.txt new file mode 100644 index 0000000..bbc3ca0 --- /dev/null +++ b/Tests/ExternalProjectSourceSubdir/Example/subdir/CMakeLists.txt @@ -0,0 +1,2 @@ +cmake_minimum_required(VERSION 3.0) +project(empty) ----------------------------------------------------------------------- Summary of changes: Modules/ExternalProject.cmake | 28 ++++++++++++++++---- Tests/CMakeLists.txt | 12 +++++++++ Tests/ExternalProjectSourceSubdir/CMakeLists.txt | 10 +++++++ .../Example/subdir/CMakeLists.txt} | 2 +- 4 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 Tests/ExternalProjectSourceSubdir/CMakeLists.txt copy Tests/{RunCMake/Syntax/UnterminatedBrace0.cmake => ExternalProjectSourceSubdir/Example/subdir/CMakeLists.txt} (70%) hooks/post-receive -- CMake From kwrobot at kitware.com Tue Aug 16 00:01:33 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Tue, 16 Aug 2016 00:01:33 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-630-g6b07972 Message-ID: <20160816040139.B6C0CF5672@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 6b07972fbdf7e8687577a430597e40e7e0b4831d (commit) from 7fe5c79dd07da5d23fc61070884a1efa95c0fafd (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6b07972fbdf7e8687577a430597e40e7e0b4831d commit 6b07972fbdf7e8687577a430597e40e7e0b4831d Author: Kitware Robot AuthorDate: Tue Aug 16 00:01:09 2016 -0400 Commit: Kitware Robot CommitDate: Tue Aug 16 00:01:09 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 58b0448..8d950fd 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160815) +set(CMake_VERSION_PATCH 20160816) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 16 13:24:39 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 16 Aug 2016 13:24:39 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1259-gcac8c65 Message-ID: <20160816172440.123E9F57AE@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via cac8c6542a38c2a234e39af7a99e46e8ad5ab336 (commit) via a8345d65f359d75efb057d22976cfb92b4d477cf (commit) from 7a4d3516aedece0736be4c1ad1702522a3526dd6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cac8c6542a38c2a234e39af7a99e46e8ad5ab336 commit cac8c6542a38c2a234e39af7a99e46e8ad5ab336 Merge: 7a4d351 a8345d6 Author: Brad King AuthorDate: Tue Aug 16 13:24:37 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 16 13:24:37 2016 -0400 Merge topic 'ExternalProject-SOURCE_SUBDIR' into next a8345d65 ExternalProject: Add SOURCE_SUBDIR option https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a8345d65f359d75efb057d22976cfb92b4d477cf commit a8345d65f359d75efb057d22976cfb92b4d477cf Author: Matthew Woehlke AuthorDate: Mon Aug 15 14:42:22 2016 -0400 Commit: Brad King CommitDate: Tue Aug 16 13:18:18 2016 -0400 ExternalProject: Add SOURCE_SUBDIR option Add a new SOURCE_SUBDIR option to ExternalProject_Add that allows specifying the location of the CMakeLists.txt to use as the project root relative to the SOURCE_DIR. This is helpful for projects that have unusual layouts, or projects that provide both a superbuild and project-only build depending on which CMakeLists.txt is used. Fixes: #15118 diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index 2ff18fc..634ef42 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -98,6 +98,8 @@ Create custom targets to build projects in external trees ``SOURCE_DIR `` Source dir to be used for build + ``SOURCE_SUBDIR `` + Path to source CMakeLists.txt relative to ``SOURCE_DIR`` ``CONFIGURE_COMMAND ...`` Build tree configuration command ``CMAKE_COMMAND /.../cmake`` @@ -236,6 +238,11 @@ Create custom targets to build projects in external trees interpreted with respect to the build directory corresponding to the source directory in which ``ExternalProject_Add`` is invoked. + If ``SOURCE_SUBDIR`` is set and no ``CONFIGURE_COMMAND`` is specified, the + configure command will run CMake using the ``CMakeLists.txt`` located in the + relative path specified by ``SOURCE_SUBDIR``, relative to the ``SOURCE_DIR``. + If no ``SOURCE_SUBDIR`` is given, ``SOURCE_DIR`` is used. + If ``SOURCE_DIR`` is explicitly set to an existing directory the project will be built from it. Otherwise a download step must be specified using one of the ``DOWNLOAD_COMMAND``, ``CVS_*``, ``SVN_*``, or ``URL`` @@ -287,8 +294,8 @@ Create custom targets to build projects in external trees The command line, comment, working directory, and byproducts of every standard and custom step are processed to replace tokens ````, - ````, ````, and ```` with - corresponding property values. + ````, ````, ````, and ```` + with corresponding property values. Any builtin step that specifies a ``_COMMAND cmd...`` or custom step that specifies a ``COMMAND cmd...`` may specify additional command @@ -1064,6 +1071,13 @@ function(_ep_set_directories name) endif() set_property(TARGET ${name} PROPERTY _EP_${VAR}_DIR "${${var}_dir}") endforeach() + get_property(source_subdir TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR) + if(NOT source_subdir) + set_property(TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR ".") + elseif(IS_ABSOLUTE "${source_subdir}") + message(FATAL_ERROR + "External project ${name} has non-relative SOURCE_SUBDIR!") + endif() if(build_in_source) get_property(source_dir TARGET ${name} PROPERTY _EP_SOURCE_DIR) set_property(TARGET ${name} PROPERTY _EP_BINARY_DIR "${source_dir}") @@ -1095,7 +1109,7 @@ macro(_ep_replace_location_tags target_name) set(vars ${ARGN}) foreach(var ${vars}) if(${var}) - foreach(dir SOURCE_DIR BINARY_DIR INSTALL_DIR TMP_DIR DOWNLOADED_FILE) + foreach(dir SOURCE_DIR SOURCE_SUBDIR BINARY_DIR INSTALL_DIR TMP_DIR DOWNLOADED_FILE) get_property(val TARGET ${target_name} PROPERTY _EP_${dir}) string(REPLACE "<${dir}>" "${val}" ${var} "${${var}}") endforeach() @@ -2131,7 +2145,7 @@ endfunction() # TODO: Make sure external projects use the proper compiler function(_ep_add_configure_command name) - ExternalProject_Get_Property(${name} source_dir binary_dir tmp_dir) + ExternalProject_Get_Property(${name} source_dir source_subdir binary_dir tmp_dir) # Depend on other external projects (file-level). set(file_deps) @@ -2209,7 +2223,11 @@ function(_ep_add_configure_command name) endif() endif() - list(APPEND cmd "${source_dir}") + if(source_subdir STREQUAL ".") + list(APPEND cmd "${source_dir}") + else() + list(APPEND cmd "${source_dir}/${source_subdir}") + endif() endif() # If anything about the configure command changes, (command itself, cmake diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index f21e430..071da41 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1441,6 +1441,18 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release ) list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectSubdir") + add_test(NAME ExternalProjectSourceSubdir + COMMAND ${CMAKE_CTEST_COMMAND} -C $ + --build-and-test + "${CMake_SOURCE_DIR}/Tests/ExternalProjectSourceSubdir" + "${CMake_BINARY_DIR}/Tests/ExternalProjectSourceSubdir" + ${build_generator_args} + --build-project ExternalProjectSourceSubdir + --force-new-ctest-process + --build-options ${build_options} + ) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectSourceSubdir") + add_test(ExternalProjectLocal ${CMAKE_CTEST_COMMAND} --build-and-test "${CMake_SOURCE_DIR}/Tests/ExternalProjectLocal" diff --git a/Tests/ExternalProjectSourceSubdir/CMakeLists.txt b/Tests/ExternalProjectSourceSubdir/CMakeLists.txt new file mode 100644 index 0000000..4688acf --- /dev/null +++ b/Tests/ExternalProjectSourceSubdir/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.6) +project(ExternalProjectSourceSubdir NONE) +include(ExternalProject) + +ExternalProject_Add(Example + SOURCE_SUBDIR subdir + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Example + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/Example + INSTALL_COMMAND "" + ) diff --git a/Tests/ExternalProjectSourceSubdir/Example/subdir/CMakeLists.txt b/Tests/ExternalProjectSourceSubdir/Example/subdir/CMakeLists.txt new file mode 100644 index 0000000..bbc3ca0 --- /dev/null +++ b/Tests/ExternalProjectSourceSubdir/Example/subdir/CMakeLists.txt @@ -0,0 +1,2 @@ +cmake_minimum_required(VERSION 3.0) +project(empty) ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 16 13:26:17 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 16 Aug 2016 13:26:17 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-632-g447b142 Message-ID: <20160816172618.D637DF580A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 447b142b6a5ae8ee1669cb1a424619af808f1c17 (commit) via 2bdba83e4bbd5435ee6faf5a2eedec4f0d0dfb0a (commit) from 6b07972fbdf7e8687577a430597e40e7e0b4831d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=447b142b6a5ae8ee1669cb1a424619af808f1c17 commit 447b142b6a5ae8ee1669cb1a424619af808f1c17 Merge: 6b07972 2bdba83 Author: Brad King AuthorDate: Tue Aug 16 13:26:15 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 16 13:26:15 2016 -0400 Merge topic 'issue-tracker-urls' 2bdba83e issues: update references to the CMake issue tracker ----------------------------------------------------------------------- Summary of changes: Modules/CMakeDetermineCCompiler.cmake | 2 +- Modules/CMakeDetermineCXXCompiler.cmake | 2 +- Modules/CMakeFindEclipseCDT4.cmake | 2 +- Modules/Compiler/IAR.cmake | 5 +++-- Modules/ExternalProject.cmake | 2 +- Modules/FindHDF5.cmake | 4 ++-- Source/cmExtraCodeBlocksGenerator.cxx | 4 ++-- Source/cmExtraEclipseCDT4Generator.cxx | 4 ++-- Source/cmExtraSublimeTextGenerator.cxx | 2 +- Source/cmQtAutoGeneratorInitializer.cxx | 2 +- Tests/CPackComponents/Issue 7470.html | 4 ++-- Tests/CTestLimitDashJ/CMakeLists.txt | 2 +- 12 files changed, 18 insertions(+), 17 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 16 13:26:21 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 16 Aug 2016 13:26:21 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-634-g074d098 Message-ID: <20160816172621.D8480F580F@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 074d098ffb001c6e6c03483746c7bb6e02ab4484 (commit) via 8ba204a69602ca8744aeec4ca3d808c964715ed5 (commit) from 447b142b6a5ae8ee1669cb1a424619af808f1c17 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=074d098ffb001c6e6c03483746c7bb6e02ab4484 commit 074d098ffb001c6e6c03483746c7bb6e02ab4484 Merge: 447b142 8ba204a Author: Brad King AuthorDate: Tue Aug 16 13:26:19 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 16 13:26:19 2016 -0400 Merge topic 'FindMatlab-mingw' 8ba204a6 FindMatlab: Use pre-built libraries for MinGW if needed ----------------------------------------------------------------------- Summary of changes: Modules/FindMatlab.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 16 13:26:25 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 16 Aug 2016 13:26:25 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-636-ge240a7c Message-ID: <20160816172625.77590F5812@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via e240a7c0176450e092e2398148c1e13f8940c239 (commit) via a8345d65f359d75efb057d22976cfb92b4d477cf (commit) from 074d098ffb001c6e6c03483746c7bb6e02ab4484 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e240a7c0176450e092e2398148c1e13f8940c239 commit e240a7c0176450e092e2398148c1e13f8940c239 Merge: 074d098 a8345d6 Author: Brad King AuthorDate: Tue Aug 16 13:26:22 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 16 13:26:22 2016 -0400 Merge topic 'ExternalProject-SOURCE_SUBDIR' a8345d65 ExternalProject: Add SOURCE_SUBDIR option ----------------------------------------------------------------------- Summary of changes: Modules/ExternalProject.cmake | 28 ++++++++++++++++---- Tests/CMakeLists.txt | 12 +++++++++ Tests/ExternalProjectSourceSubdir/CMakeLists.txt | 10 +++++++ .../Example/subdir/CMakeLists.txt} | 2 +- 4 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 Tests/ExternalProjectSourceSubdir/CMakeLists.txt copy Tests/{RunCMake/Syntax/UnterminatedBrace0.cmake => ExternalProjectSourceSubdir/Example/subdir/CMakeLists.txt} (70%) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 16 13:26:41 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 16 Aug 2016 13:26:41 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1264-g1b6398f Message-ID: <20160816172641.4DC85F5815@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 1b6398fea8e3606984decc76dc0d38092985fbd7 (commit) via e240a7c0176450e092e2398148c1e13f8940c239 (commit) via 074d098ffb001c6e6c03483746c7bb6e02ab4484 (commit) via 447b142b6a5ae8ee1669cb1a424619af808f1c17 (commit) via 6b07972fbdf7e8687577a430597e40e7e0b4831d (commit) from cac8c6542a38c2a234e39af7a99e46e8ad5ab336 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1b6398fea8e3606984decc76dc0d38092985fbd7 commit 1b6398fea8e3606984decc76dc0d38092985fbd7 Merge: cac8c65 e240a7c Author: Brad King AuthorDate: Tue Aug 16 13:26:32 2016 -0400 Commit: Brad King CommitDate: Tue Aug 16 13:26:32 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 16 13:50:29 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 16 Aug 2016 13:50:29 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1267-gbf26fa0 Message-ID: <20160816175029.95823F4EEF@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via bf26fa0d1e1eea567b656366e0510e9018b530cd (commit) via 49ad7f9af84dd46e5527e6fefaa47d8bde748bca (commit) via 1d408dc10f492d060b8b9546c3ed3521d7051fd8 (commit) from 1b6398fea8e3606984decc76dc0d38092985fbd7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bf26fa0d1e1eea567b656366e0510e9018b530cd commit bf26fa0d1e1eea567b656366e0510e9018b530cd Merge: 1b6398f 49ad7f9 Author: Brad King AuthorDate: Tue Aug 16 13:50:28 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 16 13:50:28 2016 -0400 Merge topic 'cmake-capabilities' into next 49ad7f9a cmake: Add `cmake -E capabilities` mode 1d408dc1 cmake: Constify cmake::GetRegisteredGenerators https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=49ad7f9af84dd46e5527e6fefaa47d8bde748bca commit 49ad7f9af84dd46e5527e6fefaa47d8bde748bca Author: Tobias Hunger AuthorDate: Thu Jun 30 15:38:44 2016 +0200 Commit: Brad King CommitDate: Tue Aug 16 13:45:05 2016 -0400 cmake: Add `cmake -E capabilities` mode Add `cmake -E capabilities` to report on generators, cmake version and possibly other static capabilities of cmake. Closes: #15462 diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index 8f7c336..2ccc6be 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -180,6 +180,43 @@ CMake provides builtin command-line tools through the signature:: Run ``cmake -E`` or ``cmake -E help`` for a summary of commands. Available commands are: +``capabilities`` + Report cmake capabilities in JSON format. The output is a JSON object + with the following keys: + + ``version`` + A JSON object with version information. Keys are: + + ``string`` + The full version string as displayed by cmake ``--version``. + ``major`` + The major version number in integer form. + ``minor`` + The minor version number in integer form. + ``patch`` + The patch level in integer form. + ``suffix`` + The cmake version suffix string. + ``isDirty`` + A bool that is set if the cmake build is from a dirty tree. + + ``generators`` + A list available generators. Each generator is a JSON object with the + following keys: + + ``name`` + A string containing the name of the generator. + ``toolsetSupport`` + ``true`` if the generator supports toolsets and ``false`` otherwise. + ``platformSupport`` + ``true`` if the generator supports platforms and ``false`` otherwise. + ``extraGenerators`` + A list of strings with all the extra generators compatible with + the generator. + + ``serverMode`` + ``true`` if cmake supports server-mode and ``false`` otherwise. + ``chdir [...]`` Change the current working directory and run a command. diff --git a/Help/release/dev/cmake-capabilities.rst b/Help/release/dev/cmake-capabilities.rst new file mode 100644 index 0000000..7abb973 --- /dev/null +++ b/Help/release/dev/cmake-capabilities.rst @@ -0,0 +1,6 @@ +cmake-capabilities +------------------ + +* :manual:`cmake(1)` gained a ``-E capabilities`` option to provide a + machine-readable (JSON) description of the capabilities of the + cmake tool (available generators, etc.). diff --git a/Source/cmake.cxx b/Source/cmake.cxx index a265ead..4313d83 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -23,11 +23,15 @@ #include "cmState.h" #include "cmTest.h" #include "cmUtils.hxx" +#include "cmVersionMacros.h" #if defined(CMAKE_BUILD_WITH_CMAKE) #include "cmGraphVizWriter.h" #include "cmVariableWatch.h" #include + +#include "cm_jsoncpp_value.h" +#include "cm_jsoncpp_writer.h" #endif #include @@ -110,6 +114,18 @@ #include +namespace { + +#if defined(CMAKE_BUILD_WITH_CMAKE) +#ifdef CMake_HAVE_CXX_UNORDERED_MAP +typedef std::unordered_map JsonValueMapType; +#else +typedef cmsys::hash_map JsonValueMapType; +#endif +#endif + +} // namespace + static bool cmakeCheckStampFile(const char* stampName); static bool cmakeCheckStampList(const char* stampName); @@ -201,6 +217,68 @@ cmake::~cmake() delete this->FileComparison; } +std::string cmake::ReportCapabilities() const +{ + std::string result; +#if defined(CMAKE_BUILD_WITH_CMAKE) + Json::Value obj = Json::objectValue; + // Version information: + Json::Value version = Json::objectValue; + version["string"] = CMake_VERSION; + version["major"] = CMake_VERSION_MAJOR; + version["minor"] = CMake_VERSION_MINOR; + version["suffix"] = CMake_VERSION_SUFFIX; + version["isDirty"] = (CMake_VERSION_IS_DIRTY == 1); + version["patch"] = CMake_VERSION_PATCH; + + obj["version"] = version; + + // Generators: + std::vector generatorInfoList; + this->GetRegisteredGenerators(generatorInfoList); + + JsonValueMapType generatorMap; + for (std::vector::const_iterator i = + generatorInfoList.begin(); + i != generatorInfoList.end(); ++i) { + if (i->isAlias) { // skip aliases, they are there for compatibility reasons + // only + continue; + } + + if (i->extraName.empty()) { + Json::Value gen = Json::objectValue; + gen["name"] = i->name; + gen["toolsetSupport"] = i->supportsToolset; + gen["platformSupport"] = i->supportsPlatform; + gen["extraGenerators"] = Json::arrayValue; + generatorMap[i->name] = gen; + } else { + Json::Value& gen = generatorMap[i->baseName]; + gen["extraGenerators"].append(i->extraName); + } + } + + Json::Value generators = Json::arrayValue; + for (JsonValueMapType::const_iterator i = generatorMap.begin(); + i != generatorMap.end(); ++i) { + generators.append(i->second); + } + obj["generators"] = generators; + +#if defined(HAVE_SERVER_MODE) && HAVE_SERVER_MODE + obj["serverMode"] = true; +#else + obj["serverMode"] = false; +#endif + Json::FastWriter writer; + result = writer.write(obj); +#else + result = "Not supported"; +#endif + return result; +} + void cmake::CleanupCommandsAndMacros() { this->CurrentSnapshot = this->State->Reset(); diff --git a/Source/cmake.h b/Source/cmake.h index 5b7c54a..343d371 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -117,6 +117,8 @@ public: /// Destructor ~cmake(); + std::string ReportCapabilities() const; + static const char* GetCMakeFilesDirectory() { return "/CMakeFiles"; } static const char* GetCMakeFilesDirectoryPostSlash() { diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 9d0337a..be023b1 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -60,6 +60,8 @@ void CMakeCommandUsage(const char* program) errorStream << "Usage: " << program << " -E [arguments...]\n" << "Available commands: \n" + << " capabilities - Report capabilities built into cmake " + "in JSON format\n" << " chdir dir cmd [args...] - run command in a given directory\n" << " compare_files file1 file2 - check if file1 is same as file2\n" << " copy ... destination - copy files to destination " @@ -510,6 +512,16 @@ int cmcmd::ExecuteCMakeCommand(std::vector& args) } return 0; } + // capabilities + else if (args[1] == "capabilities") { + if (args.size() > 2) { + std::cerr << "-E capabilities accepts no additional arguments\n"; + return 1; + } + cmake cm; + std::cout << cm.ReportCapabilities(); + return 0; + } // Sleep command else if (args[1] == "sleep" && args.size() > 2) { diff --git a/Tests/RunCMake/CommandLine/E_capabilities-arg-result.txt b/Tests/RunCMake/CommandLine/E_capabilities-arg-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_capabilities-arg-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_capabilities-arg-stderr.txt b/Tests/RunCMake/CommandLine/E_capabilities-arg-stderr.txt new file mode 100644 index 0000000..f74cebe --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_capabilities-arg-stderr.txt @@ -0,0 +1 @@ +^-E capabilities accepts no additional arguments$ diff --git a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt new file mode 100644 index 0000000..6c5ea44 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt @@ -0,0 +1 @@ +^{.*}$ diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 077a19d..6ae47a8 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -8,6 +8,8 @@ run_cmake_command(lists-no-file ${CMAKE_COMMAND} nosuchsubdir/CMakeLists.txt) run_cmake_command(D-no-arg ${CMAKE_COMMAND} -D) run_cmake_command(U-no-arg ${CMAKE_COMMAND} -U) run_cmake_command(E-no-arg ${CMAKE_COMMAND} -E) +run_cmake_command(E_capabilities ${CMAKE_COMMAND} -E capabilities) +run_cmake_command(E_capabilities-arg ${CMAKE_COMMAND} -E capabilities --extra-arg) run_cmake_command(E_echo_append ${CMAKE_COMMAND} -E echo_append) run_cmake_command(E_rename-no-arg ${CMAKE_COMMAND} -E rename) run_cmake_command(E_touch_nocreate-no-arg ${CMAKE_COMMAND} -E touch_nocreate) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1d408dc10f492d060b8b9546c3ed3521d7051fd8 commit 1d408dc10f492d060b8b9546c3ed3521d7051fd8 Author: Brad King AuthorDate: Tue Aug 16 13:36:54 2016 -0400 Commit: Brad King CommitDate: Tue Aug 16 13:40:06 2016 -0400 cmake: Constify cmake::GetRegisteredGenerators diff --git a/Source/cmake.cxx b/Source/cmake.cxx index b11f4f6..a265ead 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -811,7 +811,8 @@ void cmake::AddDefaultExtraGenerators() #endif } -void cmake::GetRegisteredGenerators(std::vector& generators) +void cmake::GetRegisteredGenerators( + std::vector& generators) const { for (RegisteredGeneratorsVector::const_iterator i = this->Generators.begin(), e = this->Generators.end(); diff --git a/Source/cmake.h b/Source/cmake.h index 304a15d..5b7c54a 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -187,7 +187,7 @@ public: void SetGlobalGenerator(cmGlobalGenerator*); ///! Get the names of the current registered generators - void GetRegisteredGenerators(std::vector& generators); + void GetRegisteredGenerators(std::vector& generators) const; ///! Set the name of the selected generator-specific platform. void SetGeneratorPlatform(std::string const& ts) ----------------------------------------------------------------------- Summary of changes: Help/manual/cmake.1.rst | 37 +++++++++ Help/release/dev/cmake-capabilities.rst | 6 ++ Source/cmake.cxx | 81 +++++++++++++++++++- Source/cmake.h | 4 +- Source/cmcmd.cxx | 12 +++ .../E_capabilities-arg-result.txt} | 0 .../CommandLine/E_capabilities-arg-stderr.txt | 1 + .../RunCMake/CommandLine/E_capabilities-stdout.txt | 1 + Tests/RunCMake/CommandLine/RunCMakeTest.cmake | 2 + 9 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 Help/release/dev/cmake-capabilities.rst copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => CommandLine/E_capabilities-arg-result.txt} (100%) create mode 100644 Tests/RunCMake/CommandLine/E_capabilities-arg-stderr.txt create mode 100644 Tests/RunCMake/CommandLine/E_capabilities-stdout.txt hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 16 14:08:30 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 16 Aug 2016 14:08:30 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1269-g8bc1788 Message-ID: <20160816180830.CABABF5AA5@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 8bc1788a12d60261a957b98254694c4a776ce62a (commit) via 0a8182399db73fc85a98802faae8e534e4d22767 (commit) from bf26fa0d1e1eea567b656366e0510e9018b530cd (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8bc1788a12d60261a957b98254694c4a776ce62a commit 8bc1788a12d60261a957b98254694c4a776ce62a Merge: bf26fa0 0a81823 Author: Brad King AuthorDate: Tue Aug 16 14:08:29 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 16 14:08:29 2016 -0400 Merge topic 'process-output-encoding' into next 0a818239 Windows: Encode child process output to internally-used encoding https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0a8182399db73fc85a98802faae8e534e4d22767 commit 0a8182399db73fc85a98802faae8e534e4d22767 Author: D?vis Mos?ns AuthorDate: Mon Aug 15 23:34:21 2016 +0300 Commit: Brad King CommitDate: Tue Aug 16 13:59:17 2016 -0400 Windows: Encode child process output to internally-used encoding Typically Windows applications (eg. MSVC compiler) use current console's codepage for output to pipes so we need to encode that to our internally-used encoding (`KWSYS_ENCODING_DEFAULT_CODEPAGE`). diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index cdc8fb1..580c3eb 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -317,6 +317,8 @@ set(SRCS cmOrderDirectories.h cmPolicies.h cmPolicies.cxx + cmProcessOutput.cxx + cmProcessOutput.hxx cmProcessTools.cxx cmProcessTools.h cmProperty.cxx @@ -375,6 +377,9 @@ set(SRCS cm_utf8.c ) +SET_PROPERTY(SOURCE cmProcessOutput.cxx APPEND PROPERTY COMPILE_DEFINITIONS + KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) + set(COMMAND_INCLUDES "#include \"cmTargetPropCommandBase.cxx\"\n") list(APPEND SRCS cmTargetPropCommandBase.cxx) set_property(SOURCE cmTargetPropCommandBase.cxx PROPERTY HEADER_FILE_ONLY ON) diff --git a/Source/cmExecProgramCommand.cxx b/Source/cmExecProgramCommand.cxx index 58bbc31..4391a19 100644 --- a/Source/cmExecProgramCommand.cxx +++ b/Source/cmExecProgramCommand.cxx @@ -11,6 +11,7 @@ ============================================================================*/ #include "cmExecProgramCommand.h" +#include "cmProcessOutput.hxx" #include "cmSystemTools.h" #include @@ -219,6 +220,7 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output, int length; char* data; int p; + cmProcessOutput processOutput; while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) { if (p == cmsysProcess_Pipe_STDOUT || p == cmsysProcess_Pipe_STDERR) { if (verbose) { @@ -230,6 +232,7 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output, // All output has been read. Wait for the process to exit. cmsysProcess_WaitForExit(cp, CM_NULLPTR); + processOutput.DecodeText(output, output); // Check the result of running the process. std::string msg; diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index d97b25f..1ffb163 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -11,6 +11,7 @@ ============================================================================*/ #include "cmExecuteProcessCommand.h" +#include "cmProcessOutput.hxx" #include "cmSystemTools.h" #include @@ -228,17 +229,21 @@ bool cmExecuteProcessCommand::InitialPass(std::vector const& args, int length; char* data; int p; + cmProcessOutput processOutput; + std::string strdata; while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) { // Put the output in the right place. if (p == cmsysProcess_Pipe_STDOUT && !output_quiet) { if (output_variable.empty()) { - cmSystemTools::Stdout(data, length); + processOutput.DecodeText(data, length, strdata, 1); + cmSystemTools::Stdout(strdata.c_str(), strdata.size()); } else { cmExecuteProcessCommandAppend(tempOutput, data, length); } } else if (p == cmsysProcess_Pipe_STDERR && !error_quiet) { if (error_variable.empty()) { - cmSystemTools::Stderr(data, length); + processOutput.DecodeText(data, length, strdata, 2); + cmSystemTools::Stderr(strdata.c_str(), strdata.size()); } else { cmExecuteProcessCommandAppend(tempError, data, length); } @@ -247,6 +252,8 @@ bool cmExecuteProcessCommand::InitialPass(std::vector const& args, // All output has been read. Wait for the process to exit. cmsysProcess_WaitForExit(cp, CM_NULLPTR); + processOutput.DecodeText(tempOutput, tempOutput); + processOutput.DecodeText(tempError, tempError); // Fix the text in the output strings. cmExecuteProcessCommandFixText(tempOutput, output_strip_trailing_whitespace); diff --git a/Source/cmProcessOutput.cxx b/Source/cmProcessOutput.cxx new file mode 100644 index 0000000..59101dd --- /dev/null +++ b/Source/cmProcessOutput.cxx @@ -0,0 +1,155 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2016 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmProcessOutput.hxx" + +#if defined(_WIN32) +#include +unsigned int cmProcessOutput::defaultCodepage = + KWSYS_ENCODING_DEFAULT_CODEPAGE; +#endif + +cmProcessOutput::cmProcessOutput(unsigned int maxSize) +{ +#if defined(_WIN32) + bufferSize = maxSize; + codepage = GetConsoleCP(); + if (!codepage) { + codepage = GetACP(); + } +#else + static_cast(maxSize); +#endif +} + +cmProcessOutput::~cmProcessOutput() +{ +} + +bool cmProcessOutput::DecodeText(std::string raw, std::string& decoded, + size_t id) +{ + bool success = true; + decoded = raw; +#if defined(_WIN32) + if (id > 0) { + if (rawparts.size() < id) { + rawparts.reserve(id); + while (rawparts.size() < id) + rawparts.push_back(std::string()); + } + raw = rawparts[id - 1] + raw; + rawparts[id - 1].clear(); + decoded = raw; + } + if (raw.size() > 0 && codepage != defaultCodepage) { + success = false; + CPINFOEXW cpinfo; + if (id > 0 && raw.size() == bufferSize && + GetCPInfoExW(codepage, 0, &cpinfo) == 1 && cpinfo.MaxCharSize > 1) { + if (cpinfo.MaxCharSize == 2 && cpinfo.LeadByte[0] != 0) { + LPSTR prevChar = + CharPrevExA(codepage, raw.c_str(), raw.c_str() + raw.size(), 0); + bool isLeadByte = + (*(prevChar + 1) == 0) && IsDBCSLeadByteEx(codepage, *prevChar); + if (isLeadByte) { + rawparts[id - 1] += *(raw.end() - 1); + raw.resize(raw.size() - 1); + } + success = DoDecodeText(raw, decoded, NULL); + } else { + bool restoreDecoded = false; + std::string firstDecoded = decoded; + wchar_t lastChar = 0; + for (UINT i = 0; i < cpinfo.MaxCharSize; i++) { + success = DoDecodeText(raw, decoded, &lastChar); + if (success && lastChar != 0) { + if (i == 0) { + firstDecoded = decoded; + } + if (lastChar == cpinfo.UnicodeDefaultChar) { + restoreDecoded = true; + rawparts[id - 1] = *(raw.end() - 1) + rawparts[id - 1]; + raw.resize(raw.size() - 1); + } else { + restoreDecoded = false; + break; + } + } else { + break; + } + } + if (restoreDecoded) { + decoded = firstDecoded; + rawparts[id - 1].clear(); + } + } + } else { + success = DoDecodeText(raw, decoded, NULL); + } + } +#else + static_cast(id); +#endif + return success; +} + +bool cmProcessOutput::DecodeText(const char* data, size_t length, + std::string& decoded, size_t id) +{ + return DecodeText(std::string(data, length), decoded, id); +} + +bool cmProcessOutput::DecodeText(std::vector raw, + std::vector& decoded, size_t id) +{ + std::string str; + const bool success = + DecodeText(std::string(raw.begin(), raw.end()), str, id); + decoded.assign(str.begin(), str.end()); + return success; +} + +#if defined(_WIN32) +bool cmProcessOutput::DoDecodeText(std::string raw, std::string& decoded, + wchar_t* lastChar) +{ + bool success = false; + const int wlength = + MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()), NULL, 0); + wchar_t* wdata = new wchar_t[wlength]; + int r = MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()), wdata, + wlength); + if (r > 0) { + if (lastChar) { + *lastChar = 0; + if ((wlength >= 2 && wdata[wlength - 2] != wdata[wlength - 1]) || + wlength >= 1) { + *lastChar = wdata[wlength - 1]; + } + } + int length = WideCharToMultiByte(defaultCodepage, 0, wdata, wlength, NULL, + 0, NULL, NULL); + char* data = new char[length + 1]; + r = WideCharToMultiByte(defaultCodepage, 0, wdata, wlength, data, length, + NULL, NULL); + if (r > 0) { + data[length] = '\0'; + decoded = data; + success = true; + } + delete[] data; + } + delete[] wdata; + return success; +} +#endif diff --git a/Source/cmProcessOutput.hxx b/Source/cmProcessOutput.hxx new file mode 100644 index 0000000..c896720 --- /dev/null +++ b/Source/cmProcessOutput.hxx @@ -0,0 +1,42 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2016 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmProcessOutput_hxx +#define cmProcessOutput_hxx + +#include "cmStandardIncludes.h" + +#include +#include + +class cmProcessOutput +{ +public: + static unsigned int defaultCodepage; + // must match to KWSYSPE_PIPE_BUFFER_SIZE + cmProcessOutput(unsigned int maxSize = 1024); + ~cmProcessOutput(); + bool DecodeText(std::string raw, std::string& decoded, size_t id = 0); + bool DecodeText(const char* data, size_t length, std::string& decoded, + size_t id = 0); + bool DecodeText(std::vector raw, std::vector& decoded, + size_t id = 0); + +private: + unsigned int codepage; + unsigned int bufferSize; + std::vector rawparts; +#if defined(_WIN32) + bool DoDecodeText(std::string raw, std::string& decoded, wchar_t* lastChar); +#endif +}; + +#endif diff --git a/Source/cmProcessTools.cxx b/Source/cmProcessTools.cxx index 34b8df2..396d4b9 100644 --- a/Source/cmProcessTools.cxx +++ b/Source/cmProcessTools.cxx @@ -10,6 +10,7 @@ See the License for more information. ============================================================================*/ #include "cmProcessTools.h" +#include "cmProcessOutput.hxx" #include @@ -20,14 +21,18 @@ void cmProcessTools::RunProcess(struct cmsysProcess_s* cp, OutputParser* out, char* data = CM_NULLPTR; int length = 0; int p; + cmProcessOutput processOutput; + std::string strdata; while ((out || err) && (p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) { if (out && p == cmsysProcess_Pipe_STDOUT) { - if (!out->Process(data, length)) { + processOutput.DecodeText(data, length, strdata, 1); + if (!out->Process(strdata.c_str(), int(strdata.size()))) { out = CM_NULLPTR; } } else if (err && p == cmsysProcess_Pipe_STDERR) { - if (!err->Process(data, length)) { + processOutput.DecodeText(data, length, strdata, 2); + if (!err->Process(strdata.c_str(), int(strdata.size()))) { err = CM_NULLPTR; } } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 5745a01..fcf0945 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -21,6 +21,7 @@ #ifdef __QNX__ #include /* for malloc/free on QNX */ #endif +#include "cmProcessOutput.hxx" #include #include #include @@ -612,6 +613,8 @@ bool cmSystemTools::RunSingleCommand(std::vector const& command, char* data; int length; int pipe; + cmProcessOutput processOutput; + std::string strdata; if (outputflag != OUTPUT_PASSTHROUGH && (captureStdOut || captureStdErr || outputflag != OUTPUT_NONE)) { while ((pipe = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR)) > @@ -627,14 +630,16 @@ bool cmSystemTools::RunSingleCommand(std::vector const& command, if (pipe == cmsysProcess_Pipe_STDOUT) { if (outputflag != OUTPUT_NONE) { - cmSystemTools::Stdout(data, length); + processOutput.DecodeText(data, length, strdata, 1); + cmSystemTools::Stdout(strdata.c_str(), strdata.size()); } if (captureStdOut) { tempStdOut.insert(tempStdOut.end(), data, data + length); } } else if (pipe == cmsysProcess_Pipe_STDERR) { if (outputflag != OUTPUT_NONE) { - cmSystemTools::Stderr(data, length); + processOutput.DecodeText(data, length, strdata, 2); + cmSystemTools::Stderr(strdata.c_str(), strdata.size()); } if (captureStdErr) { tempStdErr.insert(tempStdErr.end(), data, data + length); @@ -646,9 +651,11 @@ bool cmSystemTools::RunSingleCommand(std::vector const& command, cmsysProcess_WaitForExit(cp, CM_NULLPTR); if (captureStdOut) { captureStdOut->assign(tempStdOut.begin(), tempStdOut.end()); + processOutput.DecodeText(*captureStdOut, *captureStdOut); } if (captureStdErr) { captureStdErr->assign(tempStdErr.begin(), tempStdErr.end()); + processOutput.DecodeText(*captureStdErr, *captureStdErr); } bool result = true; diff --git a/bootstrap b/bootstrap index 742fa2b..3402c9d 100755 --- a/bootstrap +++ b/bootstrap @@ -328,6 +328,7 @@ CMAKE_CXX_SOURCES="\ cmExprLexer \ cmExprParser \ cmExprParserHelper \ + cmProcessOutput \ " if ${cmake_system_mingw}; then @@ -1343,6 +1344,7 @@ fi cmake_c_flags_String="-DKWSYS_STRING_C" if ${cmake_system_mingw}; then cmake_c_flags_EncodingC="-DKWSYS_ENCODING_DEFAULT_CODEPAGE=CP_ACP" + cmake_cxx_flags_cmProcessOutput="${cmake_c_flags_EncodingC}" fi cmake_cxx_flags_SystemTools=" -DKWSYS_CXX_HAS_SETENV=${KWSYS_CXX_HAS_SETENV} @@ -1359,8 +1361,9 @@ echo "cmake: ${objs}" > "${cmake_bootstrap_dir}/Makefile" echo " ${cmake_cxx_compiler} ${cmake_ld_flags} ${cmake_cxx_flags} ${objs} -o cmake" >> "${cmake_bootstrap_dir}/Makefile" for a in ${CMAKE_CXX_SOURCES}; do src=`cmake_escape "${cmake_source_dir}/Source/${a}.cxx"` + src_flags=`eval echo \\${cmake_cxx_flags_\${a}}` echo "${a}.o : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile" - echo " ${cmake_cxx_compiler} ${cmake_cxx_flags} -c ${src} -o ${a}.o" >> "${cmake_bootstrap_dir}/Makefile" + echo " ${cmake_cxx_compiler} ${cmake_cxx_flags} ${src_flags} -c ${src} -o ${a}.o" >> "${cmake_bootstrap_dir}/Makefile" done echo "cmBootstrapCommands1.o : $cmBootstrapCommands1Deps" >> "${cmake_bootstrap_dir}/Makefile" echo "cmBootstrapCommands2.o : $cmBootstrapCommands2Deps" >> "${cmake_bootstrap_dir}/Makefile" ----------------------------------------------------------------------- Summary of changes: Source/CMakeLists.txt | 5 ++ Source/cmExecProgramCommand.cxx | 3 + Source/cmExecuteProcessCommand.cxx | 11 ++- Source/cmProcessOutput.cxx | 155 ++++++++++++++++++++++++++++++++++++ Source/cmProcessOutput.hxx | 42 ++++++++++ Source/cmProcessTools.cxx | 9 ++- Source/cmSystemTools.cxx | 11 ++- bootstrap | 5 +- 8 files changed, 234 insertions(+), 7 deletions(-) create mode 100644 Source/cmProcessOutput.cxx create mode 100644 Source/cmProcessOutput.hxx hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 16 14:20:10 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 16 Aug 2016 14:20:10 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1271-g1dde35c Message-ID: <20160816182010.369B0F4791@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 1dde35c113c24ec4d47e1a624ee68ae797e6a2c6 (commit) via 7ded655f7ba82ea72a82d0555449f2df5ef38594 (commit) from 8bc1788a12d60261a957b98254694c4a776ce62a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1dde35c113c24ec4d47e1a624ee68ae797e6a2c6 commit 1dde35c113c24ec4d47e1a624ee68ae797e6a2c6 Merge: 8bc1788 7ded655 Author: Brad King AuthorDate: Tue Aug 16 14:20:09 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 16 14:20:09 2016 -0400 Merge topic 'FindCUDA-target-include-dirs' into next 7ded655f FindCUDA: Take NVCC include directories from target properties https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7ded655f7ba82ea72a82d0555449f2df5ef38594 commit 7ded655f7ba82ea72a82d0555449f2df5ef38594 Author: Peter Boettcher AuthorDate: Tue Aug 16 13:22:06 2016 -0400 Commit: Brad King CommitDate: Tue Aug 16 14:16:35 2016 -0400 FindCUDA: Take NVCC include directories from target properties Fixes issue where include directories specified on the target are not passed on to NVCC. This includes both target_include_directories() as well as include directories added by dependency chaining. Closes: #14201 diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake index 78b716d..317a9cd 100644 --- a/Modules/FindCUDA.cmake +++ b/Modules/FindCUDA.cmake @@ -730,7 +730,7 @@ else() endif() # Set the user list of include dir to nothing to initialize it. -set (CUDA_NVCC_INCLUDE_ARGS_USER "") +set (CUDA_NVCC_INCLUDE_DIRS_USER "") set (CUDA_INCLUDE_DIRS ${CUDA_TOOLKIT_INCLUDE}) macro(cuda_find_library_local_first_with_path_ext _var _names _doc _path_ext ) @@ -1025,7 +1025,7 @@ find_package_handle_standard_args(CUDA # Add include directories to pass to the nvcc command. macro(CUDA_INCLUDE_DIRECTORIES) foreach(dir ${ARGN}) - list(APPEND CUDA_NVCC_INCLUDE_ARGS_USER -I${dir}) + list(APPEND CUDA_NVCC_INCLUDE_DIRS_USER ${dir}) endforeach() endmacro() @@ -1249,17 +1249,15 @@ macro(CUDA_WRAP_SRCS cuda_target format generated_files) endif() # Initialize our list of includes with the user ones followed by the CUDA system ones. - set(CUDA_NVCC_INCLUDE_ARGS ${CUDA_NVCC_INCLUDE_ARGS_USER} "-I${CUDA_INCLUDE_DIRS}") - # Get the include directories for this directory and use them for our nvcc command. - # Remove duplicate entries which may be present since include_directories - # in CMake >= 2.8.8 does not remove them. - get_directory_property(CUDA_NVCC_INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES) - list(REMOVE_DUPLICATES CUDA_NVCC_INCLUDE_DIRECTORIES) - if(CUDA_NVCC_INCLUDE_DIRECTORIES) - foreach(dir ${CUDA_NVCC_INCLUDE_DIRECTORIES}) - list(APPEND CUDA_NVCC_INCLUDE_ARGS -I${dir}) - endforeach() - endif() + set(CUDA_NVCC_INCLUDE_DIRS ${CUDA_NVCC_INCLUDE_DIRS_USER} "${CUDA_INCLUDE_DIRS}") + # Append the include directories for this target via generator expression, which is + # expanded by the FILE(GENERATE) call below. This generator expression captures all + # include dirs set by the user, whether via directory properties or target properties + list(APPEND CUDA_NVCC_INCLUDE_DIRS "$") + + # Do the same thing with compile definitions + set(CUDA_NVCC_COMPILE_DEFINITIONS "$") + # Reset these variables set(CUDA_WRAP_OPTION_NVCC_FLAGS) @@ -1349,14 +1347,6 @@ macro(CUDA_WRAP_SRCS cuda_target format generated_files) string(REGEX REPLACE "[-]+std=c\\+\\+11" "" _cuda_host_flags "${_cuda_host_flags}") endif() - # Get the list of definitions from the directory property - get_directory_property(CUDA_NVCC_DEFINITIONS COMPILE_DEFINITIONS) - if(CUDA_NVCC_DEFINITIONS) - foreach(_definition ${CUDA_NVCC_DEFINITIONS}) - list(APPEND nvcc_flags "-D${_definition}") - endforeach() - endif() - if(_cuda_build_shared_libs) list(APPEND nvcc_flags "-D${cuda_target}_EXPORTS") endif() diff --git a/Modules/FindCUDA/run_nvcc.cmake b/Modules/FindCUDA/run_nvcc.cmake index ff1f515..28cc1e9 100644 --- a/Modules/FindCUDA/run_nvcc.cmake +++ b/Modules/FindCUDA/run_nvcc.cmake @@ -73,10 +73,25 @@ set(CUDA_NVCC_EXECUTABLE "@CUDA_NVCC_EXECUTABLE@") # path set(CUDA_NVCC_FLAGS @CUDA_NVCC_FLAGS@ ;; @CUDA_WRAP_OPTION_NVCC_FLAGS@) # list @CUDA_NVCC_FLAGS_CONFIG@ set(nvcc_flags @nvcc_flags@) # list -set(CUDA_NVCC_INCLUDE_ARGS "@CUDA_NVCC_INCLUDE_ARGS@") # list (needs to be in quotes to handle spaces properly). +set(CUDA_NVCC_INCLUDE_DIRS "@CUDA_NVCC_INCLUDE_DIRS@") # list (needs to be in quotes to handle spaces properly). +set(CUDA_NVCC_COMPILE_DEFINITIONS "@CUDA_NVCC_COMPILE_DEFINITIONS@") # list (needs to be in quotes to handle spaces properly). set(format_flag "@format_flag@") # string set(cuda_language_flag @cuda_language_flag@) # list +# Clean up list of include directories and add -I flags +list(REMOVE_DUPLICATES CUDA_NVCC_INCLUDE_DIRS) +set(CUDA_NVCC_INCLUDE_ARGS) +foreach(dir ${CUDA_NVCC_INCLUDE_DIRS}) + # Extra quotes are added around each flag to help nvcc parse out flags with spaces. + list(APPEND CUDA_NVCC_INCLUDE_ARGS "-I${dir}") +endforeach() + +# Clean up list of compile definitions, add -D flags, and append to nvcc_flags +list(REMOVE_DUPLICATES CUDA_NVCC_COMPILE_DEFINITIONS) +foreach(def ${CUDA_NVCC_COMPILE_DEFINITIONS}) + list(APPEND nvcc_flags "-D${def}") +endforeach() + if(build_cubin AND NOT generated_cubin_file) message(FATAL_ERROR "You must specify generated_cubin_file on the command line") endif() ----------------------------------------------------------------------- Summary of changes: Modules/FindCUDA.cmake | 32 +++++++++++--------------------- Modules/FindCUDA/run_nvcc.cmake | 17 ++++++++++++++++- 2 files changed, 27 insertions(+), 22 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 16 14:27:16 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 16 Aug 2016 14:27:16 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1274-gbbafe31 Message-ID: <20160816182716.C6E0BF5667@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via bbafe31c4f905a77622f6da7307c05dba838ac80 (commit) via ea51b71a4f76597ada400d8bdea75cc9548530a3 (commit) via c18dc6fbe5b68312be52353aa0a493106584ffe7 (commit) from 1dde35c113c24ec4d47e1a624ee68ae797e6a2c6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bbafe31c4f905a77622f6da7307c05dba838ac80 commit bbafe31c4f905a77622f6da7307c05dba838ac80 Merge: 1dde35c ea51b71 Author: Brad King AuthorDate: Tue Aug 16 14:27:14 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 16 14:27:14 2016 -0400 Merge topic 'cmake-developer-reference' into next ea51b71a QtIFW: Developer Reference installation c18dc6fb Added CMake_BUILD_DEVELOPER_REFERENCE option https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ea51b71a4f76597ada400d8bdea75cc9548530a3 commit ea51b71a4f76597ada400d8bdea75cc9548530a3 Author: Konstantin Podsvirov AuthorDate: Thu Aug 4 13:02:39 2016 +0300 Commit: Konstantin Podsvirov CommitDate: Tue Aug 16 19:02:35 2016 +0300 QtIFW: Developer Reference installation diff --git a/CMakeCPack.cmake b/CMakeCPack.cmake index 34bb6bb..4d7c6fd 100644 --- a/CMakeCPack.cmake +++ b/CMakeCPack.cmake @@ -107,6 +107,14 @@ if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") if(SPHINX_QTHELP) list(APPEND _CPACK_IFW_COMPONENTS_ALL sphinx-qthelp) endif() + if(CMake_BUILD_DEVELOPER_REFERENCE) + if(CMake_BUILD_DEVELOPER_REFERENCE_HTML) + list(APPEND _CPACK_IFW_COMPONENTS_ALL cmake-developer-reference-html) + endif() + if(CMake_BUILD_DEVELOPER_REFERENCE_QTHELP) + list(APPEND _CPACK_IFW_COMPONENTS_ALL cmake-developer-reference-qthelp) + endif() + endif() set(_CPACK_IFW_COMPONENTS_CONFIGURATION " # Components set(CPACK_COMPONENTS_ALL \"${_CPACK_IFW_COMPONENTS_ALL}\") @@ -122,7 +130,8 @@ if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") # Components scripts configuration foreach(_script CMake - CMake.Documentation.SphinxHTML) + CMake.Documentation.SphinxHTML + CMake.DeveloperReference.HTML) configure_file("${CMake_SOURCE_DIR}/Source/QtIFW/${_script}.qs.in" "${CMake_BINARY_DIR}/${_script}.qs" @ONLY) endforeach() @@ -136,6 +145,11 @@ if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") if(SPHINX_HTML) set(_CPACK_IFW_SHORTCUT_OPTIONAL "${_CPACK_IFW_SHORTCUT_OPTIONAL}component.addOperation(\"CreateShortcut\", \"@TargetDir@/doc/cmake-${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}/html/index.html\", \"@StartMenuDir@/CMake Documentation.lnk\");\n") endif() + if(CMake_BUILD_DEVELOPER_REFERENCE) + if(CMake_BUILD_DEVELOPER_REFERENCE_HTML) + set(_CPACK_IFW_SHORTCUT_OPTIONAL "${_CPACK_IFW_SHORTCUT_OPTIONAL}component.addOperation(\"CreateShortcut\", \"@TargetDir@/doc/cmake-${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}/developer-reference/html/index.html\", \"@StartMenuDir@/CMake Developer Reference.lnk\");\n") + endif() + endif() configure_file("${CMake_SOURCE_DIR}/Source/QtIFW/installscript.qs.in" "${CMake_BINARY_DIR}/installscript.qs" @ONLY ) diff --git a/CMakeCPackOptions.cmake.in b/CMakeCPackOptions.cmake.in index 1d61613..d7a33bc 100644 --- a/CMakeCPackOptions.cmake.in +++ b/CMakeCPackOptions.cmake.in @@ -175,6 +175,29 @@ if(CPACK_GENERATOR MATCHES "IFW") set(CPACK_IFW_COMPONENT_SPHINX-QTHELP_NAME "SphinxQtHelp") set(CPACK_IFW_COMPONENT_SPHINX-QTHELP_VERSION "@_CPACK_IFW_PACKAGE_VERSION@") + # Developer Reference + set(CPACK_COMPONENT_GROUP_DEVELOPERREFERENCE_DISPLAY_NAME "Developer Reference") + set(CPACK_COMPONENT_GROUP_DEVELOPERREFERENCE_DESCRIPTION + "CMake Reference in different formats (html, qch)") + set(CPACK_COMPONENT_GROUP_DEVELOPERREFERENCE_PARENT_GROUP CMake) + set(CPACK_IFW_COMPONENT_GROUP_DEVELOPERREFERENCE_PRIORITY 50) + set(CPACK_IFW_COMPONENT_GROUP_DEVELOPERREFERENCE_VERSION + "@_CPACK_IFW_PACKAGE_VERSION@") + + set(CPACK_COMPONENT_CMAKE-DEVELOPER-REFERENCE-HTML_DISPLAY_NAME "HTML") + set(CPACK_COMPONENT_CMAKE-DEVELOPER-REFERENCE-HTML_GROUP DeveloperReference) + set(CPACK_COMPONENT_CMAKE-DEVELOPER-REFERENCE-HTML_DISABLED TRUE) + set(CPACK_IFW_COMPONENT_CMAKE-DEVELOPER-REFERENCE-HTML_NAME "HTML") + set(CPACK_IFW_COMPONENT_CMAKE-DEVELOPER-REFERENCE-HTML_SCRIPT + "@CMake_BINARY_DIR@/CMake.DeveloperReference.HTML.qs") + set(CPACK_IFW_COMPONENT_CMAKE-DEVELOPER-REFERENCE-HTML_VERSION "@_CPACK_IFW_PACKAGE_VERSION@") + + set(CPACK_COMPONENT_CMAKE-DEVELOPER-REFERENCE-QTHELP_DISPLAY_NAME "Qt Compressed Help") + set(CPACK_COMPONENT_CMAKE-DEVELOPER-REFERENCE-QTHELP_GROUP DeveloperReference) + set(CPACK_COMPONENT_CMAKE-DEVELOPER-REFERENCE-QTHELP_DISABLED TRUE) + set(CPACK_IFW_COMPONENT_CMAKE-DEVELOPER-REFERENCE-QTHELP_NAME "QtHelp") + set(CPACK_IFW_COMPONENT_CMAKE-DEVELOPER-REFERENCE-QTHELP_VERSION "@_CPACK_IFW_PACKAGE_VERSION@") + endif() if(CPACK_GENERATOR MATCHES "CygwinSource") diff --git a/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in b/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in new file mode 100644 index 0000000..e3d8554 --- /dev/null +++ b/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in @@ -0,0 +1,21 @@ +// Component: CMake.Reference.DoxygenHTML + +function Component() +{ + // Default constructor +} + +Component.prototype.createOperations = function() +{ + // Create shortcut + if (installer.value("os") === "win") { + + component.addOperation("CreateShortcut", + installer.value("TargetDir") + "/@CMAKE_DOC_DIR@/developer-reference/html/index.html", + installer.value("StartMenuDir") + "/CMake Developer Reference.lnk"); + + } + + // Call default implementation + component.createOperations(); +} https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c18dc6fbe5b68312be52353aa0a493106584ffe7 commit c18dc6fbe5b68312be52353aa0a493106584ffe7 Author: Konstantin Podsvirov AuthorDate: Thu Aug 4 13:01:42 2016 +0300 Commit: Konstantin Podsvirov CommitDate: Tue Aug 16 19:02:35 2016 +0300 Added CMake_BUILD_DEVELOPER_REFERENCE option By default is OFF and marked as advanced. It's also add custom cmake-developer-reference (ALL) target Generated output will be installed to ${CMAKE_DOC_DIR}/developer-reference. diff --git a/CMakeLists.txt b/CMakeLists.txt index ae5990e..3aef619 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,6 +93,11 @@ option(CMake_INSTALL_DEPENDENCIES "Whether to install 3rd-party runtime dependencies" OFF) mark_as_advanced(CMake_INSTALL_DEPENDENCIES) +# option to build reference for CMake developers +option(CMake_BUILD_DEVELOPER_REFERENCE + "Build CMake Developer Reference" OFF) +mark_as_advanced(CMake_BUILD_DEVELOPER_REFERENCE) + #----------------------------------------------------------------------- # a macro to deal with system libraries, implemented as a macro # simply to improve readability of the main script diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index cdc8fb1..b68675d 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -50,6 +50,15 @@ if(WIN32) add_definitions(-DUNICODE -D_UNICODE) endif() +# configure the .dox.in file +if(CMake_BUILD_DEVELOPER_REFERENCE) + configure_file( + "${CMake_SOURCE_DIR}/Source/dir.dox.in" + "${CMake_BINARY_DIR}/Source/dir.dox" + @ONLY + ) +endif() + # configure the .h file configure_file( "${CMake_SOURCE_DIR}/Source/cmConfigure.cmake.h.in" diff --git a/Source/QtDialog/CMakeSetup64.png b/Source/QtDialog/CMakeSetup64.png new file mode 100644 index 0000000..43a8cc6 Binary files /dev/null and b/Source/QtDialog/CMakeSetup64.png differ diff --git a/Source/dir.dox b/Source/dir.dox new file mode 100644 index 0000000..66e3de7 --- /dev/null +++ b/Source/dir.dox @@ -0,0 +1,7 @@ +/*! + +\dir + +\brief Root \c ${CMake_SOURCE_DIR}/Source directory + +*/ diff --git a/Source/dir.dox.in b/Source/dir.dox.in new file mode 100644 index 0000000..78cf58d --- /dev/null +++ b/Source/dir.dox.in @@ -0,0 +1,7 @@ +/*! + +\dir + +\brief Generated \c ${CMake_BINARY_DIR}/Source directory + +*/ diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt index 813e34d..6ebf2b4 100644 --- a/Utilities/Doxygen/CMakeLists.txt +++ b/Utilities/Doxygen/CMakeLists.txt @@ -10,30 +10,96 @@ # See the License for more information. #============================================================================= +if(NOT CMake_SOURCE_DIR) + set(CMakeDeveloperReference_STANDALONE 1) + cmake_minimum_required(VERSION 2.8.4 FATAL_ERROR) + get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH) + get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH) + include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake) + include(${CMake_SOURCE_DIR}/Source/CMakeVersionCompute.cmake) + include(${CMake_SOURCE_DIR}/Source/CMakeInstallDestinations.cmake) + unset(CMAKE_DATA_DIR) + unset(CMAKE_DATA_DIR CACHE) + macro(CMake_OPTIONAL_COMPONENT) + set(COMPONENT "") + endmacro() +endif() + +project(CMakeDeveloperReference NONE) + # -# Build the documentation +# Build the reference # -include (${CMAKE_ROOT}/Modules/Documentation.cmake OPTIONAL) -if (BUILD_DOCUMENTATION) +if (CMake_BUILD_DEVELOPER_REFERENCE OR CMakeDeveloperReference_STANDALONE) + + find_package(Doxygen REQUIRED) + + # + ## Output formats + # + + option(CMake_BUILD_DEVELOPER_REFERENCE_HTML "Build CMake Developer Reference - HTML format" ON) + mark_as_advanced(CMake_BUILD_DEVELOPER_REFERENCE_HTML) + if(CMake_BUILD_DEVELOPER_REFERENCE_HTML) + set(GENERATE_HTML YES) + else() + set(GENERATE_HTML NO) + endif() + + option(CMake_BUILD_DEVELOPER_REFERENCE_QTHELP "Build CMake Developer Reference - QtHelp format" OFF) + mark_as_advanced(CMake_BUILD_DEVELOPER_REFERENCE_QTHELP) + if(CMake_BUILD_DEVELOPER_REFERENCE_QTHELP) + set(GENERATE_QHP YES) + find_program(QHELPGENERATOR_EXECUTABLE + NAMES qhelpgenerator + DOC "qhelpgenerator tool" + ) + if(NOT QHELPGENERATOR_EXECUTABLE) + message(FATAL_ERROR "QHELPGENERATOR_EXECUTABLE (qhelpgenerator) not found!") + endif() + else() + set(GENERATE_QHP NO) + endif() # # Configure the script and the doxyfile, then add target # + + if(DOXYGEN_DOT_FOUND) + set(HAVE_DOT YES) + else() + set(HAVE_DOT NO) + endif() + if(NOT DOT_PATH) - get_filename_component(DOT_PATH ${DOT} PATH) + get_filename_component(DOT_PATH ${DOXYGEN_DOT_EXECUTABLE} PATH) endif() - configure_file( - ${CMake_SOURCE_DIR}/Utilities/Doxygen/doxyfile.in - ${CMake_BINARY_DIR}/Utilities/Doxygen/doxyfile) + configure_file(doxyfile.in doxyfile @ONLY) + + add_custom_target(cmake-developer-reference-all + ${DOXYGEN_EXECUTABLE} doxyfile + WORKING_DIRECTORY ${CMakeDeveloperReference_BINARY_DIR}) + + add_custom_target(cmake-developer-reference ALL DEPENDS cmake-developer-reference-all) - configure_file( - ${CMake_SOURCE_DIR}/Utilities/Doxygen/doc_makeall.sh.in - ${CMake_BINARY_DIR}/Utilities/Doxygen/doc_makeall.sh) + # + # Installation + # - add_custom_target(DoxygenDoc - ${BASH} - ${CMake_BINARY_DIR}/Utilities/Doxygen/doc_makeall.sh) + if(CMake_BUILD_DEVELOPER_REFERENCE_HTML) + CMake_OPTIONAL_COMPONENT(cmake-developer-reference-html) + install(DIRECTORY "${CMakeDeveloperReference_BINARY_DIR}/developer-reference/html" + DESTINATION ${CMAKE_DOC_DIR}/developer-reference + ${COMPONENT}) + endif() + + if(CMake_BUILD_DEVELOPER_REFERENCE_QTHELP) + CMake_OPTIONAL_COMPONENT(cmake-developer-reference-qthelp) + install(FILES "${CMakeDeveloperReference_BINARY_DIR}/developer-reference/CMakeDeveloperReference-${CMake_VERSION_MAJOR}${CMake_VERSION_MINOR}${CMake_VERSION_PATCH}.qch" + DESTINATION ${CMAKE_DOC_DIR}/developer-reference + ${COMPONENT}) + endif() endif () diff --git a/Utilities/Doxygen/DeveloperReference/mainpage.dox b/Utilities/Doxygen/DeveloperReference/mainpage.dox new file mode 100644 index 0000000..a37927f --- /dev/null +++ b/Utilities/Doxygen/DeveloperReference/mainpage.dox @@ -0,0 +1,8 @@ +/*! + +\mainpage CMake Developer Reference + +This manual is intended for reference by developers modifying the CMake +source tree itself. + +*/ diff --git a/Utilities/Doxygen/authors.txt b/Utilities/Doxygen/authors.txt deleted file mode 100644 index 9ba6cca..0000000 --- a/Utilities/Doxygen/authors.txt +++ /dev/null @@ -1,17 +0,0 @@ -andy: Cedilnik, Andy (andy.cedilnik at kitware.com) -barre: Barre, Sebastien (sebastien.barre at kitware.com) -berk: Geveci, Berk (berk.geveci at kitware.com) -bettingf: Bettinger, Franck (bettingf at cs.man.ac.uk) -biddi: Biddiscombe, John (jbiddiscombe at skippingmouse.co.uk) -blezek: Blezek, Dan (blezek at crd.ge.com) -geoff: Cross, Geoffrey (geoff at robots.ox.ac.uk) -hoffman: Hoffman, Bill (bill.hoffman at kitware.com) -ibanez: Ibanez, Luis (luis.ibanez at kitware.com) -iscott: Scott, Ian (ian.m.scott at stud.man.ac.uk) -king: King, Brad (brad.king at kitware.com) -lorensen: Lorensen, Bill (lorensen at crd.ge.com) -martink, lymbdemo: Martin, Ken (ken.martin at kitware.com) -millerjv: Miller, Jim (millerjv at crd.ge.com) -perera: Perera, Amitha (perera at cs.rpi.edu) -starreveld: Starreveld, Yves (ystarrev at julian.uwo.ca) -will, schroede: Schroeder, Will (will.schroeder at kitware.com) diff --git a/Utilities/Doxygen/doc_makeall.sh.in b/Utilities/Doxygen/doc_makeall.sh.in deleted file mode 100755 index fceafdd..0000000 --- a/Utilities/Doxygen/doc_makeall.sh.in +++ /dev/null @@ -1,248 +0,0 @@ -# ------------------------------------------------------------------------- -# Doxygen documentation batch -# modified by S. Barre (Time-stamp: <2003-01-16 14:04:41 barre> -# ------------------------------------------------------------------------- - -# Path to several tools (_PROG to avoid the typical GZIP env var pb) -# Example: -# DOXYGEN_PROG=@DOXYGEN@ (INCLUDE(${CMAKE_ROOT}/Modules/FindDoxygen.cmake)) -# GZIP_PROG=@GZIP@ (INCLUDE(${CMAKE_ROOT}/Modules/FindCygwin.cmake)) -# HHC_PROG=@HHC@ (INCLUDE(${CMAKE_ROOT}/Modules/FindHhc.cmake)) -# MV_PROG=@MV@ (INCLUDE(${CMAKE_ROOT}/Modules/FindCygwin.cmake)) -# PERL_PROG=@PERL@ (INCLUDE(${CMAKE_ROOT}/Modules/FindPerl.cmake)) -# RM_PROG=@RM@ (INCLUDE(${CMAKE_ROOT}/Modules/FindCygwin.cmake)) -# TAR_PROG=@TAR@ (INCLUDE(${CMAKE_ROOT}/Modules/FindCygwin.cmake)) -# WGET_PROG=@WGET@ (INCLUDE(${CMAKE_ROOT}/Modules/FindWget.cmake)) -# -export DOXYGEN_PROG="@DOXYGEN@" # Doxygen -export GZIP_PROG="@GZIP@" # gzip (Unix-like 'gzip compressor') -export GNUPLOT_PROG="@GNUPLOT@" # gnuplot (data plotting program) -export HHC_PROG="@HTML_HELP_COMPILER@" # HTML Help Compiler -export MV_PROG="@MV@" # mv (Unix-like 'move/rename files') -export PERL_PROG="@PERL@" # Perl -export RM_PROG="@RM@" # rm (Unix-like 'remove files') -export TAR_PROG="@TAR@" # tar (Unix-like 'archiver') -export WGET_PROG="@WGET@" # wget (remote file retrieval) - -# PROJECT_NAME: -# Documentation/project name. Used in some of the resulting file names and -# xrefs to uniquify two or more projects linked together through their -# Doxygen's tag files. Mandatory for each documentation set. -# Note: might be the same as the doxyfile's PROJECT_NAME -# Example: -# PROJECT_NAME=VTK -# -export PROJECT_NAME=CMake - -# PATH_TO_VTK_DOX_SCRIPTS: -# Path to the directory holding the Perl scripts used to produce the VTK doc -# in Doxygen format. You need the VTK source files or a local copy of -# these scripts. -# Example: -# PATH_TO_VTK_DOX_SCRIPTS=@VTK_SOURCE_DIR@/Utilities/Doxygen -# -export PATH_TO_VTK_DOX_SCRIPTS="@VTK_SOURCE_DIR@/Utilities/Doxygen" - -# SOURCE_DIR: -# Source directory. The top directory of the source files. -# Example: -# SOURCE_DIR=@VTK_SOURCE_DIR@ -# -export SOURCE_DIR="@CMake_SOURCE_DIR@" - -# REL_PATH_TO_TOP: -# Relative path from the top directory of the source files to the directory -# (or top directory) holding the files to document. Useful if several parts -# of the same source directory should be documented separately. -# Example: -# REL_PATH_TO_TOP=. -# REL_PATH_TO_TOP=framework/src -# -# export REL_PATH_TO_TOP=Source -export REL_PATH_TO_TOP=. - -# INTERMEDIATE_DOX_DIR: -# Directory where the intermediate Doxygen files should be stored (mainly -# these headers files converted from the VTK format to the Doxygen format). -# This directory is erased at the end of this script, unless you comment -# the corresponding line. -# DOXTEMP might be used to simplify the syntax. -# Example: -# DOXTEMP=DOXTEMP=@VTK_BINARY_DIR@/Utilities/Doxygen -# INTERMEDIATE_DOX_DIR=$DOXTEMP/dox -# -export DOXTEMP="@CMake_BINARY_DIR@/Utilities/Doxygen" -export INTERMEDIATE_DOX_DIR="$DOXTEMP/dox" - -# DOXYFILE: -# Path to the Doxygen configuration file (i.e. doxyfile). -# Example: -# DOXYFILE=$DOXTEMP/doxyfile -# -export DOXYFILE="$DOXTEMP/doxyfile" - -# OUTPUT_DIRECTORY ALLOW_ERASE_OUTPUT_DIRECTORY: -# Path to the Doxygen output directory (where the resulting doc is stored). -# Note: should be the same as your doxyfile's OUTPUT_DIRECTORY -# If ON, allows the output directory to be erased when some advanced output -# file have been produced (HTML Help, or TAR archive for example). -# Example: -# OUTPUT_DIRECTORY=$DOXTEMP/doc -# ALLOW_ERASE_OUTPUT_DIRECTORY=ON -# -export OUTPUT_DIRECTORY="$DOXTEMP/doc" -export ALLOW_ERASE_OUTPUT_DIRECTORY=ON - -# COMPILE_HTML_HELP RESULTING_HTML_HELP_FILE: -# Compile the CHM (Compressed HTML) HTML Help file, name of the resulting -# file. If set to ON and name is non-empty these options will actually -# trigger the HTML-Help compiler to create the CHM. The resulting -# file (usually index.chm) will be renamed to this name. -# Note: if ON, the whole $OUTPUT_DIRECTORY will be erased at the end of -# this script, since this file is considered to be one of the -# advanced final output, unless ALLOW_ERASE_OUTPUT_DIRECTORY is OFF -# Note: your doxyfile should be configured to enable HTML Help creation -# (using GENERATE_HTML = YES, GENERATE_HTMLHELP = YES) -# Example: -# COMPILE_HTML_HELP=ON -# COMPILE_HTML_HELP=@DOCUMENTATION_HTML_HELP@ -# RESULTING_HTML_HELP_FILE=$DOXTEMP/vtk4.chm -# -export COMPILE_HTML_HELP=@DOCUMENTATION_HTML_HELP@ -export RESULTING_HTML_HELP_FILE="$DOXTEMP/$PROJECT_NAME.chm" - -# CREATE_HTML_TARZ_ARCHIVE RESULTING_HTML_TARZ_ARCHIVE_FILE: -# Create a compressed (gzip) tar archive of the html directory (located -# under the OUTPUT_DIRECTORY), and name of the resulting archive file. -# Note: your doxyfile should be configured to enable HTML creation -# (using GENERATE_HTML = YES) -# Example: -# CREATE_HTML_TARZ_ARCHIVE=ON -# CREATE_HTML_TARZ_ARCHIVE=@DOCUMENTATION_HTML_TARZ@ -# RESULTING_HTML_TARZ_ARCHIVE_FILE=$DOXTEMP/vtk4-html.tar.gz -# RESULTING_HTML_TARZ_ARCHIVE_FILE=$DOXTEMP/$PROJECT_NAME-html.tar.gz -# -export CREATE_HTML_TARZ_ARCHIVE=@DOCUMENTATION_HTML_TARZ@ -export RESULTING_HTML_TARZ_ARCHIVE_FILE="$DOXTEMP/$PROJECT_NAME-html.tar.gz" - -# ---------------------------------------------------------------------------- -# Build the contributors list. - -if test "x at VTK_SOURCE_DIR@" != "x" ; then - if test "x$PERL_PROG" != "xNOTFOUND" ; then - "$PERL_PROG" "$PATH_TO_VTK_DOX_SCRIPTS/doc_contributors.pl" \ - --authors "$SOURCE_DIR/Utilities/Doxygen/authors.txt" \ - --cachedir "$DOXTEMP/cache" \ - --class_group '^(cm[A-Z0-9][A-Za-z0-9]+)\.(?:c|cpp|cxx|h|fl)$' \ - --files_in '(?:^hints|dummy|README|^Makefile\.borland|\.(?:c|cmake|cpp|cxx|h|html|in|java|fl|pl|py|tcl|txt))$' \ - --files_out '(?:^ChangeLog\.txt)$' \ - --gnuplot_file "$DOXTEMP/contrib/history.plt" \ - --history_img "|lines|$DOXTEMP/contrib/history.png" \ - --history_img "365|lines|$DOXTEMP/contrib/history2y.png" \ - --history_img "180|linespoints|$DOXTEMP/contrib/history6m.png" \ - --history_dir "$DOXTEMP/contrib" \ - --history_max_nb 10 \ - --lines_add 1.0 \ - --lines_rem 0.5 \ - --massive 50 \ - --max_class_nb 10 \ - --max_file_nb 5 \ - --min_class 0.02 \ - --min_file 0.01 \ - --min_contrib 0.05 \ - --min_gcontrib 0.0001 \ - --store "doc_""$PROJECT_NAME""_contributors.dox" \ - --relativeto "$SOURCE_DIR/$REL_PATH_TO_TOP" \ - --to "$INTERMEDIATE_DOX_DIR" \ - "$SOURCE_DIR/$REL_PATH_TO_TOP" - fi - - if test "x$GNUPLOT_PROG" != "xNOTFOUND" ; then - "$GNUPLOT_PROG" "$DOXTEMP/contrib/history.plt" - fi -fi - -# ---------------------------------------------------------------------------- -# Create the Doxygen doc. - -if test "x$DOXYGEN_PROG" != "xNOTFOUND" ; then - - if test "x$RM_PROG" != "xNOTFOUND" ; then - "$RM_PROG" -fr "$OUTPUT_DIRECTORY" - fi - - "$DOXYGEN_PROG" "$DOXYFILE" - - # yes, a second time, to get the contrib, I don't know why - "$DOXYGEN_PROG" "$DOXYFILE" -fi - -# ---------------------------------------------------------------------------- -# Clean the HTML pages to remove the path to the intermediate Doxygen dir. - -if test "x at VTK_SOURCE_DIR@" != "x" ; then - if test "x$PERL_PROG" != "xNOTFOUND" ; then - "$PERL_PROG" "$PATH_TO_VTK_DOX_SCRIPTS/doc_rmpath.pl" \ - --verbose \ - --to "$INTERMEDIATE_DOX_DIR" \ - --html "$OUTPUT_DIRECTORY/html" - fi -fi - -# ---------------------------------------------------------------------------- -# Create the CHM HTML HELP doc. - -if test "x$COMPILE_HTML_HELP" == "xON" ; then - if test "x$RESULTING_HTML_HELP_FILE" != "x" ; then - cd $OUTPUT_DIRECTORY/html - if test "x$HHC_PROG" != "xNOTFOUND" ; then - "$HHC_PROG" index.hhp - if test "x$MV_PROG" != "xNOTFOUND" ; then - "$MV_PROG" -f index.chm "$RESULTING_HTML_HELP_FILE" - fi - fi - fi -fi - -# ---------------------------------------------------------------------------- -# Create the compressed tar archive. - -if test "x$CREATE_HTML_TARZ_ARCHIVE" == "xON" ; then - if test "x$RESULTING_HTML_TARZ_ARCHIVE_FILE" != "x" ; then - cd "$OUTPUT_DIRECTORY" - if test "x$TAR_PROG" != "xNOTFOUND" ; then - if test "x$RM_PROG" != "xNOTFOUND" ; then - "$RM_PROG" -f html.tar - fi - "$TAR_PROG" -cf html.tar html - if test "x$GZIP_PROG" != "xNOTFOUND" ; then - if test "x$RM_PROG" != "xNOTFOUND" ; then - "$RM_PROG" -f html.tar.gz - fi - "$GZIP_PROG" html.tar - "$MV_PROG" -f html.tar.gz "$RESULTING_HTML_TARZ_ARCHIVE_FILE" - fi - fi - fi -fi - -# ---------------------------------------------------------------------------- -# Clean-up. - -if test "x$RM_PROG" != "xNOTFOUND" ; then - "$RM_PROG" -fr "$INTERMEDIATE_DOX_DIR" - - if test "x$DOWNLOAD_VTK_TAGFILE" == "xON" ; then - if test "x$VTK_TAGFILE" != "x" ; then - "$RM_PROG" -f "$VTK_TAGFILE_DEST_DIR/$VTK_TAGFILE" - fi - fi - - if test "x$COMPILE_HTML_HELP" == "xON" ; then - if test "x$RESULTING_HTML_HELP_FILE" != "x" ; then - if test "x$ALLOW_ERASE_OUTPUT_DIRECTORY" == "xON" ; then - "$RM_PROG" -fr "$OUTPUT_DIRECTORY" - fi - fi - fi -fi diff --git a/Utilities/Doxygen/doxyfile.in b/Utilities/Doxygen/doxyfile.in index 2c131f5..7333340 100644 --- a/Utilities/Doxygen/doxyfile.in +++ b/Utilities/Doxygen/doxyfile.in @@ -1,28 +1,30 @@ # ------------------------------------------------------------------------- -# doxyfile for CMake -# modified by S. Barre (Time-stamp: <2002-02-13 18:24:35 barre> +# doxyfile for CMakeReference # ------------------------------------------------------------------------- PROJECT_NAME = CMake +PROJECT_BRIEF = "Cross-platform Make" +PROJECT_NUMBER = "@CMake_VERSION@" +PROJECT_LOGO = "@CMake_SOURCE_DIR@/Source/QtDialog/CMakeSetup64.png" FULL_PATH_NAMES = YES STRIP_FROM_PATH = \ - "@CMake_SOURCE_DIR@/Source/" \ - "@CMake_BINARY_DIR@/Source/" + "@CMake_SOURCE_DIR@/" \ + "@CMake_BINARY_DIR@/" WARN_IF_UNDOCUMENTED = NO GENERATE_TREEVIEW = NO GENERATE_TODOLIST = YES GENERATE_BUGLIST = YES -GENERATE_HTML = YES +GENERATE_HTML = @GENERATE_HTML@ GENERATE_HTMLHELP = YES +GENERATE_QHP = @GENERATE_QHP@ GENERATE_LATEX = NO GENERATE_MAN = NO GENERATE_RTF = NO -HAVE_DOT = YES -#HAVE_DOT = NO +HAVE_DOT = @HAVE_DOT@ DOT_PATH = "@DOT_PATH@" CLASS_GRAPH = YES COLLABORATION_GRAPH = YES @@ -37,20 +39,21 @@ REFERENCES_RELATION = YES ALLEXTERNALS = NO -IMAGE_PATH = "@CMake_BINARY_DIR@/Utilities/Doxygen/contrib" - -OUTPUT_DIRECTORY = "@CMake_BINARY_DIR@/Utilities/Doxygen/doc" +OUTPUT_DIRECTORY = "@CMakeDeveloperReference_BINARY_DIR@/developer-reference" INPUT = \ + "@CMake_SOURCE_DIR@/Utilities/Doxygen/DeveloperReference" \ "@CMake_SOURCE_DIR@/Source" \ "@CMake_SOURCE_DIR@/Source/CPack" \ "@CMake_SOURCE_DIR@/Source/CPack/IFW" \ + "@CMake_SOURCE_DIR@/Source/CPack/WiX" \ "@CMake_SOURCE_DIR@/Source/CTest" \ "@CMake_SOURCE_DIR@/Source/CursesDialog" \ - "@CMake_SOURCE_DIR@/Source/MFCDialog" \ + "@CMake_SOURCE_DIR@/Source/kwsys" \ + "@CMake_SOURCE_DIR@/Source/QtDialog" \ + "@CMake_BINARY_DIR@/Source" \ "@CMake_BINARY_DIR@/Source/kwsys" \ - "@CMake_BINARY_DIR@/Source/cmsys" \ - "@CMake_BINARY_DIR@/Utilities/Doxygen/dox/doc_CMake_contributors.dox" \ + "@CMake_BINARY_DIR@/Source/cmsys" EXTRACT_ALL = YES EXTRACT_PRIVATE = NO @@ -68,7 +71,7 @@ SORT_MEMBER_DOCS = NO DISTRIBUTE_GROUP_DOC = YES TAB_SIZE = 3 -FILE_PATTERNS = *.h *.hxx *.cxx +FILE_PATTERNS = *.h *.hxx *.cxx *.dox RECURSIVE = NO EXCLUDE_PATTERNS = @@ -82,3 +85,7 @@ MACRO_EXPANSION = YES SEARCH_INCLUDES = YES INCLUDE_PATH = EXPAND_ONLY_PREDEF = YES + +QHP_NAMESPACE = org.cmake.developer-reference. at CMake_VERSION_MAJOR@@CMake_VERSION_MINOR@@CMake_VERSION_PATCH@ +QCH_FILE = ../CMakeDeveloperReference- at CMake_VERSION_MAJOR@@CMake_VERSION_MINOR@@CMake_VERSION_PATCH at .qch +QHG_LOCATION = "@QHELPGENERATOR_EXECUTABLE@" ----------------------------------------------------------------------- Summary of changes: CMakeCPack.cmake | 16 +- CMakeCPackOptions.cmake.in | 23 ++ CMakeLists.txt | 5 + Source/CMakeLists.txt | 9 + Source/QtDialog/CMakeSetup64.png | Bin 0 -> 7213 bytes ...tGUI.qs => CMake.DeveloperReference.HTML.qs.in} | 6 +- Source/dir.dox | 7 + Source/dir.dox.in | 7 + Utilities/Doxygen/CMakeLists.txt | 92 +++++++- Utilities/Doxygen/DeveloperReference/mainpage.dox | 8 + Utilities/Doxygen/authors.txt | 17 -- Utilities/Doxygen/doc_makeall.sh.in | 248 -------------------- Utilities/Doxygen/doxyfile.in | 35 +-- 13 files changed, 177 insertions(+), 296 deletions(-) create mode 100644 Source/QtDialog/CMakeSetup64.png copy Source/QtIFW/{CMake.Dialogs.QtGUI.qs => CMake.DeveloperReference.HTML.qs.in} (76%) create mode 100644 Source/dir.dox create mode 100644 Source/dir.dox.in create mode 100644 Utilities/Doxygen/DeveloperReference/mainpage.dox delete mode 100644 Utilities/Doxygen/authors.txt delete mode 100755 Utilities/Doxygen/doc_makeall.sh.in hooks/post-receive -- CMake From daniel at pfeifer-mail.de Tue Aug 16 19:09:25 2016 From: daniel at pfeifer-mail.de (Daniel Pfeifer) Date: Tue, 16 Aug 2016 19:09:25 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1276-g11d0fcf Message-ID: <20160816230926.22D44ADAA4@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 11d0fcfcfecdcef2e21a1acb550979d208e43aa0 (commit) via a2af850ba6dbee7797484ec5f6696525123023fc (commit) from bbafe31c4f905a77622f6da7307c05dba838ac80 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=11d0fcfcfecdcef2e21a1acb550979d208e43aa0 commit 11d0fcfcfecdcef2e21a1acb550979d208e43aa0 Merge: bbafe31 a2af850 Author: Daniel Pfeifer AuthorDate: Tue Aug 16 19:09:24 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 16 19:09:24 2016 -0400 Merge topic 'include-what-you-use' into next a2af850b fix a batch of include-what-you-use violations https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a2af850ba6dbee7797484ec5f6696525123023fc commit a2af850ba6dbee7797484ec5f6696525123023fc Author: Daniel Pfeifer AuthorDate: Wed Aug 17 01:08:13 2016 +0200 Commit: Daniel Pfeifer CommitDate: Wed Aug 17 01:08:13 2016 +0200 fix a batch of include-what-you-use violations diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.h b/Source/CursesDialog/cmCursesCacheEntryComposite.h index 8ed3902..c9c8238 100644 --- a/Source/CursesDialog/cmCursesCacheEntryComposite.h +++ b/Source/CursesDialog/cmCursesCacheEntryComposite.h @@ -14,6 +14,8 @@ #include "cmCursesLabelWidget.h" +class cmake; + class cmCursesCacheEntryComposite { public: diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h index 2331867..14e0f0a 100644 --- a/Source/cmCacheManager.h +++ b/Source/cmCacheManager.h @@ -17,6 +17,7 @@ #include "cmPropertyMap.h" #include "cmState.h" +class cmake; class cmMarkAsAdvancedCommand; /** \class cmCacheManager diff --git a/Source/cmGhsMultiTargetGenerator.h b/Source/cmGhsMultiTargetGenerator.h index 92a1109..118cae6 100644 --- a/Source/cmGhsMultiTargetGenerator.h +++ b/Source/cmGhsMultiTargetGenerator.h @@ -16,13 +16,13 @@ #include "cmTarget.h" +class cmCustomCommand; class cmGeneratedFileStream; +class cmGeneratorTarget; class cmGlobalGhsMultiGenerator; class cmLocalGhsMultiGenerator; class cmMakefile; class cmSourceFile; -class cmGeneratedFileStream; -class cmCustomCommand; class cmGhsMultiTargetGenerator { diff --git a/Source/cmState.cxx b/Source/cmState.cxx index 0470508..d4eb90a 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -15,10 +15,19 @@ #include "cmCacheManager.h" #include "cmCommand.h" #include "cmDefinitions.h" +#include "cmListFileCache.h" +#include "cmSystemTools.h" +#include "cmTypeMacro.h" #include "cmVersion.h" #include "cmake.h" +#include #include +#include +#include +#include +#include +#include struct cmState::SnapshotDataType { diff --git a/Source/cmState.h b/Source/cmState.h index e5f9917..9ab4213 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -12,19 +12,25 @@ #ifndef cmState_h #define cmState_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include "cmAlgorithms.h" +#include "cmDefinitions.h" #include "cmLinkedTree.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmPropertyDefinitionMap.h" #include "cmPropertyMap.h" -class cmake; +#include +#include +#include +#include + +class cmCacheManager; class cmCommand; -class cmDefinitions; class cmListFileBacktrace; -class cmCacheManager; +class cmPropertyDefinition; class cmState { diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index d0a28e1..3c1a9f4 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -12,10 +12,13 @@ #ifndef cmSystemTools_h #define cmSystemTools_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include #include +#include +#include +#include class cmSystemToolsFileTime; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 8476538..5681885 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -12,21 +12,25 @@ #include "cmTarget.h" #include "cmAlgorithms.h" -#include "cmComputeLinkInformation.h" #include "cmGeneratorExpression.h" -#include "cmGeneratorExpressionDAGChecker.h" +#include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmOutputConverter.h" +#include "cmProperty.h" #include "cmSourceFile.h" +#include "cmSourceFileLocation.h" +#include "cmSystemTools.h" #include "cmake.h" + +#include #include #include -#include #include #include -#include // required for atof +#include +#include #if defined(CMake_HAVE_CXX_UNORDERED_SET) #include diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 209a729..fc30166 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -12,14 +12,23 @@ #ifndef cmTarget_h #define cmTarget_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep +#include "cmAlgorithms.h" #include "cmCustomCommand.h" #include "cmListFileCache.h" #include "cmPolicies.h" #include "cmPropertyMap.h" +#include "cmState.h" +#include "cmTargetLinkLibraryType.h" + +#include +#include +#include +#include +#include +#include -#include #if defined(CMAKE_BUILD_WITH_CMAKE) #ifdef CMake_HAVE_CXX_UNORDERED_MAP #include @@ -28,16 +37,10 @@ #endif #endif -class cmake; class cmMakefile; class cmSourceFile; -class cmGlobalGenerator; -class cmListFileBacktrace; -class cmTarget; -class cmGeneratorTarget; -class cmTargetTraceDependencies; - class cmTargetInternals; + class cmTargetInternalPointer { public: diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx index 0658e95..790a3f8 100644 --- a/Source/cmTest.cxx +++ b/Source/cmTest.cxx @@ -11,10 +11,10 @@ ============================================================================*/ #include "cmTest.h" -#include "cmSystemTools.h" - #include "cmMakefile.h" -#include "cmake.h" +#include "cmProperty.h" +#include "cmState.h" +#include "cmSystemTools.h" cmTest::cmTest(cmMakefile* mf) : Backtrace(mf->GetBacktrace()) diff --git a/Source/cmTest.h b/Source/cmTest.h index db68008..ce3867c 100644 --- a/Source/cmTest.h +++ b/Source/cmTest.h @@ -12,11 +12,14 @@ #ifndef cmTest_h #define cmTest_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep -#include "cmCustomCommand.h" #include "cmListFileCache.h" #include "cmPropertyMap.h" + +#include +#include + class cmMakefile; /** \class cmTest diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx index 462edf9..cfc174e 100644 --- a/Source/cmTestGenerator.cxx +++ b/Source/cmTestGenerator.cxx @@ -12,11 +12,19 @@ #include "cmTestGenerator.h" #include "cmGeneratorExpression.h" +#include "cmGeneratorTarget.h" #include "cmLocalGenerator.h" #include "cmOutputConverter.h" +#include "cmProperty.h" +#include "cmPropertyMap.h" +#include "cmState.h" #include "cmSystemTools.h" #include "cmTest.h" +#include +#include +#include + cmTestGenerator::cmTestGenerator( cmTest* test, std::vector const& configurations) : cmScriptGenerator("CTEST_CONFIGURATION_TYPE", configurations) diff --git a/Source/cmTestGenerator.h b/Source/cmTestGenerator.h index 66d590e..44574e7 100644 --- a/Source/cmTestGenerator.h +++ b/Source/cmTestGenerator.h @@ -12,10 +12,16 @@ #ifndef cmTestGenerator_h #define cmTestGenerator_h +#include // IWYU pragma: keep + #include "cmScriptGenerator.h" -class cmTest; +#include +#include +#include + class cmLocalGenerator; +class cmTest; /** \class cmTestGenerator * \brief Support class for generating install scripts. diff --git a/Source/cmUuid.cxx b/Source/cmUuid.cxx index 6d09bdf..7bfc109 100644 --- a/Source/cmUuid.cxx +++ b/Source/cmUuid.cxx @@ -11,10 +11,10 @@ ============================================================================*/ #include "cmUuid.h" -#include - #include "cm_sha2.h" + #include +#include cmUuid::cmUuid() { diff --git a/Source/cmUuid.h b/Source/cmUuid.h index 2bd7ec5..f01230c 100644 --- a/Source/cmUuid.h +++ b/Source/cmUuid.h @@ -12,7 +12,10 @@ #ifndef cmUuid_h #define cmUuid_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep + +#include +#include /** \class cmUuid * \brief Utility class to generate UUIDs as defined by RFC4122 diff --git a/Source/cmVariableWatch.cxx b/Source/cmVariableWatch.cxx index 56e2770..ce700db 100644 --- a/Source/cmVariableWatch.cxx +++ b/Source/cmVariableWatch.cxx @@ -13,7 +13,9 @@ #include "cmAlgorithms.h" +#include #include +#include static const char* const cmVariableWatchAccessStrings[] = { "READ_ACCESS", "UNKNOWN_READ_ACCESS", "UNKNOWN_DEFINED_ACCESS", diff --git a/Source/cmVariableWatch.h b/Source/cmVariableWatch.h index 5ddb907..88b3d1c 100644 --- a/Source/cmVariableWatch.h +++ b/Source/cmVariableWatch.h @@ -12,7 +12,11 @@ #ifndef cmVariableWatch_h #define cmVariableWatch_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep + +#include +#include +#include class cmMakefile; diff --git a/Source/cmVersion.cxx b/Source/cmVersion.cxx index 4c2e4ce..88cae0b 100644 --- a/Source/cmVersion.cxx +++ b/Source/cmVersion.cxx @@ -11,7 +11,7 @@ ============================================================================*/ #include "cmVersion.h" -#include "cmVersionMacros.h" +#include "cmVersionConfig.h" unsigned int cmVersion::GetMajorVersion() { diff --git a/Source/cmVersion.h b/Source/cmVersion.h index 46fd5a6..20e4c8c 100644 --- a/Source/cmVersion.h +++ b/Source/cmVersion.h @@ -12,7 +12,7 @@ #ifndef cmVersion_h #define cmVersion_h -#include "cmStandardIncludes.h" +#include /** \class cmVersion * \brief Helper class for providing CMake and CTest version information. diff --git a/Source/cmXMLParser.cxx b/Source/cmXMLParser.cxx index 5e06d36..a62c36f 100644 --- a/Source/cmXMLParser.cxx +++ b/Source/cmXMLParser.cxx @@ -11,10 +11,12 @@ ============================================================================*/ #include "cmXMLParser.h" -#include - #include +#include #include +#include +#include +#include cmXMLParser::cmXMLParser() { diff --git a/Source/cmXMLParser.h b/Source/cmXMLParser.h index 6aae81d..319b295 100644 --- a/Source/cmXMLParser.h +++ b/Source/cmXMLParser.h @@ -12,7 +12,9 @@ #ifndef cmXMLParser_h #define cmXMLParser_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep + +#include extern "C" { void cmXMLParserStartElement(void*, const char*, const char**); diff --git a/Source/cmXMLSafe.cxx b/Source/cmXMLSafe.cxx index f899f57..8575181 100644 --- a/Source/cmXMLSafe.cxx +++ b/Source/cmXMLSafe.cxx @@ -13,9 +13,7 @@ #include "cm_utf8.h" -#include #include - #include #include diff --git a/Source/cmXMLSafe.h b/Source/cmXMLSafe.h index 11ced13..a187437 100644 --- a/Source/cmXMLSafe.h +++ b/Source/cmXMLSafe.h @@ -12,7 +12,7 @@ #ifndef cmXMLSafe_h #define cmXMLSafe_h -#include +#include // IWYU pragma: keep #include #include diff --git a/Source/cmXMLWriter.cxx b/Source/cmXMLWriter.cxx index e2dce93d..eda5bef 100644 --- a/Source/cmXMLWriter.cxx +++ b/Source/cmXMLWriter.cxx @@ -11,8 +11,6 @@ ============================================================================*/ #include "cmXMLWriter.h" -#include "cmXMLSafe.h" - #include #include diff --git a/Source/cmXMLWriter.h b/Source/cmXMLWriter.h index 8a88dd4..c303963 100644 --- a/Source/cmXMLWriter.h +++ b/Source/cmXMLWriter.h @@ -12,7 +12,7 @@ #ifndef cmXMLWiter_h #define cmXMLWiter_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include "cmXMLSafe.h" diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx index 44f71f1..167d60a 100644 --- a/Source/cmcldeps.cxx +++ b/Source/cmcldeps.cxx @@ -21,6 +21,7 @@ #include #include +#include #include #include diff --git a/Tests/CMakeLib/run_compile_commands.cxx b/Tests/CMakeLib/run_compile_commands.cxx index b811c7f..502ffe7 100644 --- a/Tests/CMakeLib/run_compile_commands.cxx +++ b/Tests/CMakeLib/run_compile_commands.cxx @@ -1,5 +1,13 @@ #include "cmSystemTools.h" +#include +#include +#include +#include +#include +#include +#include + class CompileCommandParser { public: diff --git a/Tests/CMakeLib/testSystemTools.cxx b/Tests/CMakeLib/testSystemTools.cxx index a3846c0..e654d1e 100644 --- a/Tests/CMakeLib/testSystemTools.cxx +++ b/Tests/CMakeLib/testSystemTools.cxx @@ -11,6 +11,9 @@ ============================================================================*/ #include "cmSystemTools.h" +#include +#include + #define cmPassed(m) std::cout << "Passed: " << m << "\n" #define cmFailed(m) \ std::cout << "FAILED: " << m << "\n"; \ ----------------------------------------------------------------------- Summary of changes: Source/CursesDialog/cmCursesCacheEntryComposite.h | 2 ++ Source/cmCacheManager.h | 1 + Source/cmGhsMultiTargetGenerator.h | 4 ++-- Source/cmState.cxx | 9 +++++++++ Source/cmState.h | 14 ++++++++++---- Source/cmSystemTools.h | 5 ++++- Source/cmTarget.cxx | 12 ++++++++---- Source/cmTarget.h | 21 ++++++++++++--------- Source/cmTest.cxx | 6 +++--- Source/cmTest.h | 7 +++++-- Source/cmTestGenerator.cxx | 8 ++++++++ Source/cmTestGenerator.h | 8 +++++++- Source/cmUuid.cxx | 4 ++-- Source/cmUuid.h | 5 ++++- Source/cmVariableWatch.cxx | 2 ++ Source/cmVariableWatch.h | 6 +++++- Source/cmVersion.cxx | 2 +- Source/cmVersion.h | 2 +- Source/cmXMLParser.cxx | 6 ++++-- Source/cmXMLParser.h | 4 +++- Source/cmXMLSafe.cxx | 2 -- Source/cmXMLSafe.h | 2 +- Source/cmXMLWriter.cxx | 2 -- Source/cmXMLWriter.h | 2 +- Source/cmcldeps.cxx | 1 + Tests/CMakeLib/run_compile_commands.cxx | 8 ++++++++ Tests/CMakeLib/testSystemTools.cxx | 3 +++ 27 files changed, 107 insertions(+), 41 deletions(-) hooks/post-receive -- CMake From daniel at pfeifer-mail.de Tue Aug 16 19:50:27 2016 From: daniel at pfeifer-mail.de (Daniel Pfeifer) Date: Tue, 16 Aug 2016 19:50:27 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1278-g662661b Message-ID: <20160816235027.849ECF3DE9@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 662661b2b462946f8ba6c82af22f014a18619756 (commit) via e7b842e18955d13f6d9c021bab4a8935bf282744 (commit) from 11d0fcfcfecdcef2e21a1acb550979d208e43aa0 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=662661b2b462946f8ba6c82af22f014a18619756 commit 662661b2b462946f8ba6c82af22f014a18619756 Merge: 11d0fcf e7b842e Author: Daniel Pfeifer AuthorDate: Tue Aug 16 19:50:25 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 16 19:50:25 2016 -0400 Merge topic 'readability-named-parameter' into next e7b842e1 Make sure unnused parameters are /*named*/ https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e7b842e18955d13f6d9c021bab4a8935bf282744 commit e7b842e18955d13f6d9c021bab4a8935bf282744 Author: Daniel Pfeifer AuthorDate: Wed Aug 17 01:49:57 2016 +0200 Commit: Daniel Pfeifer CommitDate: Wed Aug 17 01:49:57 2016 +0200 Make sure unnused parameters are /*named*/ diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx index b1f6864..9120a2f 100644 --- a/Source/CPack/cmCPackArchiveGenerator.cxx +++ b/Source/CPack/cmCPackArchiveGenerator.cxx @@ -259,7 +259,7 @@ int cmCPackArchiveGenerator::PackageFiles() return 1; } -int cmCPackArchiveGenerator::GenerateHeader(std::ostream*) +int cmCPackArchiveGenerator::GenerateHeader(std::ostream* /*unused*/) { return 1; } diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx index 771519c..de572c0 100644 --- a/Source/CPack/cpack.cxx +++ b/Source/CPack/cpack.cxx @@ -50,7 +50,7 @@ static const char* cmDocumentationOptions[][2] = { { CM_NULLPTR, CM_NULLPTR } }; -int cpackUnknownArgument(const char*, void*) +int cpackUnknownArgument(const char* /*unused*/, void* /*unused*/) { return 1; } diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx index 0e08e1c..7baf7a3 100644 --- a/Source/CTest/cmCTestBZR.cxx +++ b/Source/CTest/cmCTestBZR.cxx @@ -19,7 +19,7 @@ #include -extern "C" int cmBZRXMLParserUnknownEncodingHandler(void*, +extern "C" int cmBZRXMLParserUnknownEncodingHandler(void* /*unused*/, const XML_Char* name, XML_Encoding* info) { @@ -215,7 +215,7 @@ private: return true; } - void StartElement(const std::string& name, const char**) CM_OVERRIDE + void StartElement(const std::string& name, const char** /*atts*/) CM_OVERRIDE { this->CData.clear(); if (name == "log") { @@ -275,7 +275,7 @@ private: this->CData.clear(); } - void ReportError(int, int, const char* msg) CM_OVERRIDE + void ReportError(int /*line*/, int /*column*/, const char* msg) CM_OVERRIDE { this->BZR->Log << "Error parsing bzr log xml: " << msg << "\n"; } diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index eddbddc..9dab98a 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -123,14 +123,15 @@ int cmCTestBuildAndTestHandler::RunCMake(std::string* outstring, return 0; } -void CMakeMessageCallback(const char* m, const char*, bool&, void* s) +void CMakeMessageCallback(const char* m, const char* /*unused*/, + bool& /*unused*/, void* s) { std::string* out = (std::string*)s; *out += m; *out += "\n"; } -void CMakeProgressCallback(const char* msg, float, void* s) +void CMakeProgressCallback(const char* msg, float /*unused*/, void* s) { std::string* out = (std::string*)s; *out += msg; diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx index b335e32..6910f6f 100644 --- a/Source/CTest/cmCTestCurl.cxx +++ b/Source/CTest/cmCTestCurl.cxx @@ -54,8 +54,8 @@ static size_t curlWriteMemoryCallback(void* ptr, size_t size, size_t nmemb, return realsize; } -static size_t curlDebugCallback(CURL*, curl_infotype, char* chPtr, size_t size, - void* data) +static size_t curlDebugCallback(CURL* /*unused*/, curl_infotype /*unused*/, + char* chPtr, size_t size, void* data) { std::vector* vec = static_cast*>(data); vec->insert(vec->end(), chPtr, chPtr + size); diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx index 1bda9be..09ae1fc 100644 --- a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx +++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx @@ -14,7 +14,7 @@ #include "cmCTestScriptHandler.h" bool cmCTestEmptyBinaryDirectoryCommand::InitialPass( - std::vector const& args, cmExecutionStatus&) + std::vector const& args, cmExecutionStatus& /*unused*/) { if (args.size() != 1) { this->SetError("called with incorrect number of arguments"); diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx index eb3d611..3e62a1a 100644 --- a/Source/CTest/cmCTestHG.cxx +++ b/Source/CTest/cmCTestHG.cxx @@ -261,7 +261,7 @@ private: return output; } - void ReportError(int, int, const char* msg) CM_OVERRIDE + void ReportError(int /*line*/, int /*column*/, const char* msg) CM_OVERRIDE { this->HG->Log << "Error parsing hg log xml: " << msg << "\n"; } diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index e1361a1..325f8a3 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -32,7 +32,7 @@ cmCTestHandlerCommand::cmCTestHandlerCommand() } bool cmCTestHandlerCommand::InitialPass(std::vector const& args, - cmExecutionStatus&) + cmExecutionStatus& /*unused*/) { // Allocate space for argument values. this->Values.clear(); diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index dfa8a1a..a06c351 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -78,7 +78,7 @@ public: ostr << "\n"; this->Log += ostr.str(); } - void EndElement(const std::string&) CM_OVERRIDE {} + void EndElement(const std::string& /*name*/) CM_OVERRIDE {} const char* GetAttribute(const char* name, const char** atts) { diff --git a/Source/CTest/cmCTestReadCustomFilesCommand.cxx b/Source/CTest/cmCTestReadCustomFilesCommand.cxx index fec23e9..24e985d 100644 --- a/Source/CTest/cmCTestReadCustomFilesCommand.cxx +++ b/Source/CTest/cmCTestReadCustomFilesCommand.cxx @@ -14,7 +14,7 @@ #include "cmCTest.h" bool cmCTestReadCustomFilesCommand::InitialPass( - std::vector const& args, cmExecutionStatus&) + std::vector const& args, cmExecutionStatus& /*unused*/) { if (args.empty()) { this->SetError("called with incorrect number of arguments"); diff --git a/Source/CTest/cmCTestRunScriptCommand.cxx b/Source/CTest/cmCTestRunScriptCommand.cxx index 6b5e6ed..32bf28f 100644 --- a/Source/CTest/cmCTestRunScriptCommand.cxx +++ b/Source/CTest/cmCTestRunScriptCommand.cxx @@ -14,7 +14,7 @@ #include "cmCTestScriptHandler.h" bool cmCTestRunScriptCommand::InitialPass(std::vector const& args, - cmExecutionStatus&) + cmExecutionStatus& /*unused*/) { if (args.empty()) { this->CTestScriptHandler->RunCurrentScript(); diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx index eae0c6c..06f838c 100644 --- a/Source/CTest/cmCTestSVN.cxx +++ b/Source/CTest/cmCTestSVN.cxx @@ -372,7 +372,7 @@ private: this->CData.clear(); } - void ReportError(int, int, const char* msg) CM_OVERRIDE + void ReportError(int /*line*/, int /*column*/, const char* msg) CM_OVERRIDE { this->SVN->Log << "Error parsing svn log xml: " << msg << "\n"; } diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index b747c64..44427b0 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -61,7 +61,7 @@ public: cmCTestScriptFunctionBlocker() {} ~cmCTestScriptFunctionBlocker() CM_OVERRIDE {} bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus&) CM_OVERRIDE; + cmExecutionStatus& /*status*/) CM_OVERRIDE; // virtual bool ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf); // virtual void ScopeEnded(cmMakefile &mf); @@ -69,9 +69,9 @@ public: }; // simply update the time and don't block anything -bool cmCTestScriptFunctionBlocker::IsFunctionBlocked(const cmListFileFunction&, - cmMakefile&, - cmExecutionStatus&) +bool cmCTestScriptFunctionBlocker::IsFunctionBlocked( + const cmListFileFunction& /*lff*/, cmMakefile& /*mf*/, + cmExecutionStatus& /*status*/) { this->CTestScriptHandler->UpdateElapsedTime(); return false; @@ -265,7 +265,8 @@ int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg) return retVal; } -static void ctestScriptProgressCallback(const char* m, float, void* cd) +static void ctestScriptProgressCallback(const char* m, float /*unused*/, + void* cd) { cmCTest* ctest = static_cast(cd); if (m && *m) { diff --git a/Source/CTest/cmCTestSleepCommand.cxx b/Source/CTest/cmCTestSleepCommand.cxx index a6dd6bc..464f025 100644 --- a/Source/CTest/cmCTestSleepCommand.cxx +++ b/Source/CTest/cmCTestSleepCommand.cxx @@ -15,7 +15,7 @@ #include // required for atoi bool cmCTestSleepCommand::InitialPass(std::vector const& args, - cmExecutionStatus&) + cmExecutionStatus& /*unused*/) { if (args.empty()) { this->SetError("called with incorrect number of arguments"); diff --git a/Source/CTest/cmCTestStartCommand.cxx b/Source/CTest/cmCTestStartCommand.cxx index c64d16b..04d2f03 100644 --- a/Source/CTest/cmCTestStartCommand.cxx +++ b/Source/CTest/cmCTestStartCommand.cxx @@ -23,7 +23,7 @@ cmCTestStartCommand::cmCTestStartCommand() } bool cmCTestStartCommand::InitialPass(std::vector const& args, - cmExecutionStatus&) + cmExecutionStatus& /*unused*/) { if (args.empty()) { this->SetError("called with incorrect number of arguments"); diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 67388ad..42727d0 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -116,7 +116,8 @@ static size_t cmCTestSubmitHandlerWriteMemoryCallback(void* ptr, size_t size, return realsize; } -static size_t cmCTestSubmitHandlerCurlDebugCallback(CURL*, curl_infotype, +static size_t cmCTestSubmitHandlerCurlDebugCallback(CURL* /*unused*/, + curl_infotype /*unused*/, char* chPtr, size_t size, void* data) { @@ -976,10 +977,9 @@ bool cmCTestSubmitHandler::SubmitUsingXMLRPC( return true; } #else -bool cmCTestSubmitHandler::SubmitUsingXMLRPC(std::string const&, - std::set const&, - std::string const&, - std::string const&) +bool cmCTestSubmitHandler::SubmitUsingXMLRPC( + std::string const& /*unused*/, std::set const& /*unused*/, + std::string const& /*unused*/, std::string const& /*unused*/) { return false; } diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index cd250fb..b932277 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -54,7 +54,7 @@ public: * the CMakeLists.txt file. */ bool InitialPass(std::vector const& args, - cmExecutionStatus&) CM_OVERRIDE; + cmExecutionStatus& /*unused*/) CM_OVERRIDE; /** * The name of the command as specified in CMakeList.txt. @@ -67,7 +67,7 @@ public: }; bool cmCTestSubdirCommand::InitialPass(std::vector const& args, - cmExecutionStatus&) + cmExecutionStatus& /*unused*/) { if (args.empty()) { this->SetError("called with incorrect number of arguments"); @@ -135,7 +135,7 @@ public: * the CMakeLists.txt file. */ bool InitialPass(std::vector const& args, - cmExecutionStatus&) CM_OVERRIDE; + cmExecutionStatus& /*unused*/) CM_OVERRIDE; /** * The name of the command as specified in CMakeList.txt. @@ -148,7 +148,7 @@ public: }; bool cmCTestAddSubdirectoryCommand::InitialPass( - std::vector const& args, cmExecutionStatus&) + std::vector const& args, cmExecutionStatus& /*unused*/) { if (args.empty()) { this->SetError("called with incorrect number of arguments"); @@ -208,8 +208,8 @@ public: * This is called when the command is first encountered in * the CMakeLists.txt file. */ - bool InitialPass(std::vector const&, - cmExecutionStatus&) CM_OVERRIDE; + bool InitialPass(std::vector const& /*args*/, + cmExecutionStatus& /*unused*/) CM_OVERRIDE; /** * The name of the command as specified in CMakeList.txt. @@ -222,7 +222,7 @@ public: }; bool cmCTestAddTestCommand::InitialPass(std::vector const& args, - cmExecutionStatus&) + cmExecutionStatus& /*unused*/) { if (args.size() < 2) { this->SetError("called with incorrect number of arguments"); @@ -248,8 +248,8 @@ public: * This is called when the command is first encountered in * the CMakeLists.txt file. */ - bool InitialPass(std::vector const&, - cmExecutionStatus&) CM_OVERRIDE; + bool InitialPass(std::vector const& /*args*/, + cmExecutionStatus& /*unused*/) CM_OVERRIDE; /** * The name of the command as specified in CMakeList.txt. @@ -262,7 +262,7 @@ public: }; bool cmCTestSetTestsPropertiesCommand::InitialPass( - std::vector const& args, cmExecutionStatus&) + std::vector const& args, cmExecutionStatus& /*unused*/) { return this->TestHandler->SetTestsProperties(args); } @@ -986,7 +986,8 @@ void cmCTestTestHandler::ProcessDirectory(std::vector& passed, *this->LogFile << "End testing: " << this->CTest->CurrentTime() << std::endl; } -void cmCTestTestHandler::GenerateTestCommand(std::vector&, int) +void cmCTestTestHandler::GenerateTestCommand( + std::vector& /*unused*/, int /*unused*/) { } diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx index 3376588..24557aa 100644 --- a/Source/CTest/cmCTestVC.cxx +++ b/Source/CTest/cmCTestVC.cxx @@ -185,7 +185,7 @@ bool cmCTestVC::WriteXML(cmXMLWriter& xml) return result; } -bool cmCTestVC::WriteXMLUpdates(cmXMLWriter&) +bool cmCTestVC::WriteXMLUpdates(cmXMLWriter& /*unused*/) { cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "* CTest cannot extract updates for this VCS tool.\n"); diff --git a/Source/CTest/cmParseJacocoCoverage.cxx b/Source/CTest/cmParseJacocoCoverage.cxx index 9325812..bc05666 100644 --- a/Source/CTest/cmParseJacocoCoverage.cxx +++ b/Source/CTest/cmParseJacocoCoverage.cxx @@ -23,7 +23,7 @@ public: ~XMLParser() CM_OVERRIDE {} protected: - void EndElement(const std::string&) CM_OVERRIDE {} + void EndElement(const std::string& /*name*/) CM_OVERRIDE {} void StartElement(const std::string& name, const char** atts) CM_OVERRIDE { diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx index 606c954..80bb55d 100644 --- a/Source/CursesDialog/ccmake.cxx +++ b/Source/CursesDialog/ccmake.cxx @@ -51,7 +51,7 @@ cmCursesForm* cmCursesForm::CurrentForm = CM_NULLPTR; extern "C" { -void onsig(int) +void onsig(int /*unused*/) { if (cmCursesForm::CurrentForm) { endwin(); @@ -70,8 +70,8 @@ void onsig(int) } } -void CMakeMessageHandler(const char* message, const char* title, bool&, - void* clientData) +void CMakeMessageHandler(const char* message, const char* title, + bool& /*unused*/, void* clientData) { cmCursesForm* self = static_cast(clientData); self->AddError(message, title); diff --git a/Source/CursesDialog/cmCursesBoolWidget.cxx b/Source/CursesDialog/cmCursesBoolWidget.cxx index e36ac34..068bcdc 100644 --- a/Source/CursesDialog/cmCursesBoolWidget.cxx +++ b/Source/CursesDialog/cmCursesBoolWidget.cxx @@ -24,7 +24,8 @@ cmCursesBoolWidget::cmCursesBoolWidget(int width, int height, int left, this->SetValueAsBool(false); } -bool cmCursesBoolWidget::HandleInput(int& key, cmCursesMainForm*, WINDOW* w) +bool cmCursesBoolWidget::HandleInput(int& key, cmCursesMainForm* /*fm*/, + WINDOW* w) { // toggle boolean values with enter or space diff --git a/Source/CursesDialog/cmCursesDummyWidget.cxx b/Source/CursesDialog/cmCursesDummyWidget.cxx index 3cd36af..a960090 100644 --- a/Source/CursesDialog/cmCursesDummyWidget.cxx +++ b/Source/CursesDialog/cmCursesDummyWidget.cxx @@ -18,7 +18,8 @@ cmCursesDummyWidget::cmCursesDummyWidget(int width, int height, int left, this->Type = cmState::INTERNAL; } -bool cmCursesDummyWidget::HandleInput(int&, cmCursesMainForm*, WINDOW*) +bool cmCursesDummyWidget::HandleInput(int& /*key*/, cmCursesMainForm* /*fm*/, + WINDOW* /*w*/) { return false; } diff --git a/Source/CursesDialog/cmCursesLabelWidget.cxx b/Source/CursesDialog/cmCursesLabelWidget.cxx index e9da71e..784738b 100644 --- a/Source/CursesDialog/cmCursesLabelWidget.cxx +++ b/Source/CursesDialog/cmCursesLabelWidget.cxx @@ -25,7 +25,8 @@ cmCursesLabelWidget::~cmCursesLabelWidget() { } -bool cmCursesLabelWidget::HandleInput(int&, cmCursesMainForm*, WINDOW*) +bool cmCursesLabelWidget::HandleInput(int& /*key*/, cmCursesMainForm* /*fm*/, + WINDOW* /*w*/) { // Static text. No input is handled here. return false; diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx index 48cc42c..47f98a2 100644 --- a/Source/CursesDialog/cmCursesLongMessageForm.cxx +++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx @@ -102,7 +102,8 @@ void cmCursesLongMessageForm::PrintKeys() pos_form_cursor(this->Form); } -void cmCursesLongMessageForm::Render(int, int, int, int) +void cmCursesLongMessageForm::Render(int /*left*/, int /*top*/, int /*width*/, + int /*height*/) { int x, y; getmaxyx(stdscr, y, x); diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx index 964f3af..1d036c4 100644 --- a/Source/CursesDialog/cmCursesMainForm.cxx +++ b/Source/CursesDialog/cmCursesMainForm.cxx @@ -675,7 +675,7 @@ int cmCursesMainForm::Generate() return 0; } -void cmCursesMainForm::AddError(const char* message, const char*) +void cmCursesMainForm::AddError(const char* message, const char* /*unused*/) { this->Errors.push_back(message); } @@ -1028,7 +1028,7 @@ void cmCursesMainForm::HandleInput() } } -int cmCursesMainForm::LoadCache(const char*) +int cmCursesMainForm::LoadCache(const char* /*unused*/) { int r = this->CMakeInstance->LoadCache(); diff --git a/Source/CursesDialog/cmCursesOptionsWidget.cxx b/Source/CursesDialog/cmCursesOptionsWidget.cxx index 1a3a8c2..5892e53 100644 --- a/Source/CursesDialog/cmCursesOptionsWidget.cxx +++ b/Source/CursesDialog/cmCursesOptionsWidget.cxx @@ -31,7 +31,8 @@ cmCursesOptionsWidget::cmCursesOptionsWidget(int width, int height, int left, field_opts_off(this->Field, O_STATIC); } -bool cmCursesOptionsWidget::HandleInput(int& key, cmCursesMainForm*, WINDOW* w) +bool cmCursesOptionsWidget::HandleInput(int& key, cmCursesMainForm* /*fm*/, + WINDOW* w) { // 10 == enter diff --git a/Source/CursesDialog/cmCursesStringWidget.cxx b/Source/CursesDialog/cmCursesStringWidget.cxx index 46b8b86..c16de23 100644 --- a/Source/CursesDialog/cmCursesStringWidget.cxx +++ b/Source/CursesDialog/cmCursesStringWidget.cxx @@ -29,12 +29,13 @@ cmCursesStringWidget::cmCursesStringWidget(int width, int height, int left, field_opts_off(this->Field, O_STATIC); } -void cmCursesStringWidget::OnTab(cmCursesMainForm*, WINDOW*) +void cmCursesStringWidget::OnTab(cmCursesMainForm* /*unused*/, + WINDOW* /*unused*/) { // FORM* form = fm->GetForm(); } -void cmCursesStringWidget::OnReturn(cmCursesMainForm* fm, WINDOW*) +void cmCursesStringWidget::OnReturn(cmCursesMainForm* fm, WINDOW* /*unused*/) { FORM* form = fm->GetForm(); if (this->InEdit) { @@ -56,7 +57,8 @@ void cmCursesStringWidget::OnReturn(cmCursesMainForm* fm, WINDOW*) } } -void cmCursesStringWidget::OnType(int& key, cmCursesMainForm* fm, WINDOW*) +void cmCursesStringWidget::OnType(int& key, cmCursesMainForm* fm, + WINDOW* /*unused*/) { form_driver(fm->GetForm(), key); } diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx index ceb7d31..3da4f28 100644 --- a/Source/cmArchiveWrite.cxx +++ b/Source/cmArchiveWrite.cxx @@ -64,7 +64,8 @@ public: struct cmArchiveWrite::Callback { // archive_write_callback - static __LA_SSIZE_T Write(struct archive*, void* cd, const void* b, size_t n) + static __LA_SSIZE_T Write(struct archive* /*unused*/, void* cd, + const void* b, size_t n) { cmArchiveWrite* self = static_cast(cd); if (self->Stream.write(static_cast(b), diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx index b25e3ce..ce72eda 100644 --- a/Source/cmDepends.cxx +++ b/Source/cmDepends.cxx @@ -72,7 +72,7 @@ bool cmDepends::Write(std::ostream& makeDepends, std::ostream& internalDepends) return this->Finalize(makeDepends, internalDepends); } -bool cmDepends::Finalize(std::ostream&, std::ostream&) +bool cmDepends::Finalize(std::ostream& /*unused*/, std::ostream& /*unused*/) { return true; } @@ -123,9 +123,10 @@ void cmDepends::Clear(const char* file) << std::endl; } -bool cmDepends::WriteDependencies(const std::set&, - const std::string&, std::ostream&, - std::ostream&) +bool cmDepends::WriteDependencies(const std::set& /*unused*/, + const std::string& /*unused*/, + std::ostream& /*unused*/, + std::ostream& /*unused*/) { // This should be implemented by the subclass. return false; diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index 9ea1e48..d1521f0 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -91,8 +91,9 @@ cmDependsFortran::~cmDependsFortran() } bool cmDependsFortran::WriteDependencies(const std::set& sources, - const std::string& obj, std::ostream&, - std::ostream&) + const std::string& obj, + std::ostream& /*makeDepends*/, + std::ostream& /*internalDepends*/) { // Make sure this is a scanning instance. if (sources.empty() || sources.begin()->empty()) { diff --git a/Source/cmDependsJava.cxx b/Source/cmDependsJava.cxx index 4f5e2ae..a9130e6 100644 --- a/Source/cmDependsJava.cxx +++ b/Source/cmDependsJava.cxx @@ -23,8 +23,9 @@ cmDependsJava::~cmDependsJava() } bool cmDependsJava::WriteDependencies(const std::set& sources, - const std::string&, std::ostream&, - std::ostream&) + const std::string& /*obj*/, + std::ostream& /*makeDepends*/, + std::ostream& /*internalDepends*/) { // Make sure this is a scanning instance. if (sources.empty() || sources.begin()->empty()) { @@ -35,8 +36,9 @@ bool cmDependsJava::WriteDependencies(const std::set& sources, return true; } -bool cmDependsJava::CheckDependencies(std::istream&, const char*, - std::map&) +bool cmDependsJava::CheckDependencies( + std::istream& /*internalDepends*/, const char* /*internalDependsFileName*/, + std::map& /*validDeps*/) { return true; } diff --git a/Source/cmDynamicLoader.cxx b/Source/cmDynamicLoader.cxx index 4c31733f..f6841ad 100644 --- a/Source/cmDynamicLoader.cxx +++ b/Source/cmDynamicLoader.cxx @@ -15,8 +15,10 @@ class cmDynamicLoaderCache { public: ~cmDynamicLoaderCache(); - void CacheFile(const char* path, const cmsys::DynamicLoader::LibraryHandle&); - bool GetCacheFile(const char* path, cmsys::DynamicLoader::LibraryHandle&); + void CacheFile(const char* path, + const cmsys::DynamicLoader::LibraryHandle& /*p*/); + bool GetCacheFile(const char* path, + cmsys::DynamicLoader::LibraryHandle& /*p*/); bool FlushCache(const char* path); void FlushCache(); static cmDynamicLoaderCache* GetInstance(); diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx index 266b786..c687e2f 100644 --- a/Source/cmELF.cxx +++ b/Source/cmELF.cxx @@ -55,17 +55,17 @@ template struct cmELFByteSwapSize { }; -void cmELFByteSwap(char*, cmELFByteSwapSize<1> const&) +void cmELFByteSwap(char* /*unused*/, cmELFByteSwapSize<1> const& /*unused*/) { } -void cmELFByteSwap(char* data, cmELFByteSwapSize<2> const&) +void cmELFByteSwap(char* data, cmELFByteSwapSize<2> const& /*unused*/) { char one_byte; one_byte = data[0]; data[0] = data[1]; data[1] = one_byte; } -void cmELFByteSwap(char* data, cmELFByteSwapSize<4> const&) +void cmELFByteSwap(char* data, cmELFByteSwapSize<4> const& /*unused*/) { char one_byte; one_byte = data[0]; @@ -75,7 +75,7 @@ void cmELFByteSwap(char* data, cmELFByteSwapSize<4> const&) data[1] = data[2]; data[2] = one_byte; } -void cmELFByteSwap(char* data, cmELFByteSwapSize<8> const&) +void cmELFByteSwap(char* data, cmELFByteSwapSize<8> const& /*unused*/) { char one_byte; one_byte = data[0]; diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index e00af5e..7f01196 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -679,7 +679,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpression( } } -void cmExportFileGenerator::ReplaceInstallPrefix(std::string&) +void cmExportFileGenerator::ReplaceInstallPrefix(std::string& /*unused*/) { // Do nothing } diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 38b08f0..7747157 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -468,7 +468,7 @@ void cmExportInstallFileGenerator::ComplainAboutMissingTarget( } std::string cmExportInstallFileGenerator::InstallNameDir( - cmGeneratorTarget* target, const std::string&) + cmGeneratorTarget* target, const std::string& /*config*/) { std::string install_name_dir; diff --git a/Source/cmExternalMakefileProjectGenerator.cxx b/Source/cmExternalMakefileProjectGenerator.cxx index a527e50..b01290c 100644 --- a/Source/cmExternalMakefileProjectGenerator.cxx +++ b/Source/cmExternalMakefileProjectGenerator.cxx @@ -15,7 +15,8 @@ #include void cmExternalMakefileProjectGenerator::EnableLanguage( - std::vector const&, cmMakefile*, bool) + std::vector const& /*unused*/, cmMakefile* /*unused*/, + bool /*unused*/) { } diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index 7a277c0..e617b08 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -77,7 +77,8 @@ cmExtraEclipseCDT4Generator::GetFactory() } void cmExtraEclipseCDT4Generator::EnableLanguage( - std::vector const& languages, cmMakefile*, bool) + std::vector const& languages, cmMakefile* /*unused*/, + bool /*optional*/) { for (std::vector::const_iterator lit = languages.begin(); lit != languages.end(); ++lit) { diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index 5c909c8..6e81ee1 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -206,8 +206,7 @@ void cmExtraSublimeTextGenerator::AppendAllTargets( void cmExtraSublimeTextGenerator::AppendTarget( cmGeneratedFileStream& fout, const std::string& targetName, cmLocalGenerator* lg, cmGeneratorTarget* target, const char* make, - const cmMakefile* makefile, - const char*, // compiler + const cmMakefile* makefile, const char* /*compiler*/, MapSourceFileFlags& sourceFileFlags, bool firstTarget) { diff --git a/Source/cmFortranParserImpl.cxx b/Source/cmFortranParserImpl.cxx index a72204a..7d04898 100644 --- a/Source/cmFortranParserImpl.cxx +++ b/Source/cmFortranParserImpl.cxx @@ -161,7 +161,7 @@ int cmFortranParser_GetOldStartcond(cmFortranParser* parser) return parser->OldStartcond; } -void cmFortranParser_Error(cmFortranParser*, const char*) +void cmFortranParser_Error(cmFortranParser* /*unused*/, const char* /*unused*/) { // If there is a parser error just ignore it. The source will not // compile and the user will edit it. Then dependencies will have diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index c700156..045ded1 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -198,7 +198,7 @@ enum TransitiveProperty }; template -bool additionalTest(const char* const) +bool additionalTest(const char* const /*unused*/) { return false; } diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 6e2b16a..86fbd44 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -46,10 +46,11 @@ static const struct ZeroNode : public cmGeneratorExpressionNode bool AcceptsArbitraryContentParameter() const CM_OVERRIDE { return true; } - std::string Evaluate(const std::vector&, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + std::string Evaluate(const std::vector& /*parameters*/, + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return std::string(); } @@ -62,9 +63,10 @@ static const struct OneNode : public cmGeneratorExpressionNode bool AcceptsArbitraryContentParameter() const CM_OVERRIDE { return true; } std::string Evaluate(const std::vector& parameters, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return parameters.front(); } @@ -113,7 +115,8 @@ static const struct NotNode : public cmGeneratorExpressionNode std::string Evaluate(const std::vector& parameters, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { if (*parameters.begin() != "0" && *parameters.begin() != "1") { reportError( @@ -132,9 +135,10 @@ static const struct BoolNode : public cmGeneratorExpressionNode int NumExpectedParameters() const CM_OVERRIDE { return 1; } std::string Evaluate(const std::vector& parameters, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return !cmSystemTools::IsOff(parameters.begin()->c_str()) ? "1" : "0"; } @@ -147,9 +151,10 @@ static const struct StrEqualNode : public cmGeneratorExpressionNode int NumExpectedParameters() const CM_OVERRIDE { return 2; } std::string Evaluate(const std::vector& parameters, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return *parameters.begin() == parameters[1] ? "1" : "0"; } @@ -164,7 +169,8 @@ static const struct EqualNode : public cmGeneratorExpressionNode std::string Evaluate(const std::vector& parameters, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { char* pEnd; @@ -239,9 +245,10 @@ static const struct LowerCaseNode : public cmGeneratorExpressionNode bool AcceptsArbitraryContentParameter() const CM_OVERRIDE { return true; } std::string Evaluate(const std::vector& parameters, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return cmSystemTools::LowerCase(parameters.front()); } @@ -254,9 +261,10 @@ static const struct UpperCaseNode : public cmGeneratorExpressionNode bool AcceptsArbitraryContentParameter() const CM_OVERRIDE { return true; } std::string Evaluate(const std::vector& parameters, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return cmSystemTools::UpperCase(parameters.front()); } @@ -269,9 +277,10 @@ static const struct MakeCIdentifierNode : public cmGeneratorExpressionNode bool AcceptsArbitraryContentParameter() const CM_OVERRIDE { return true; } std::string Evaluate(const std::vector& parameters, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return cmSystemTools::MakeCidentifier(parameters.front()); } @@ -283,10 +292,11 @@ static const struct Angle_RNode : public cmGeneratorExpressionNode int NumExpectedParameters() const CM_OVERRIDE { return 0; } - std::string Evaluate(const std::vector&, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + std::string Evaluate(const std::vector& /*parameters*/, + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return ">"; } @@ -298,10 +308,11 @@ static const struct CommaNode : public cmGeneratorExpressionNode int NumExpectedParameters() const CM_OVERRIDE { return 0; } - std::string Evaluate(const std::vector&, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + std::string Evaluate(const std::vector& /*parameters*/, + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return ","; } @@ -313,10 +324,11 @@ static const struct SemicolonNode : public cmGeneratorExpressionNode int NumExpectedParameters() const CM_OVERRIDE { return 0; } - std::string Evaluate(const std::vector&, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + std::string Evaluate(const std::vector& /*parameters*/, + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return ";"; } @@ -331,7 +343,7 @@ struct CompilerIdNode : public cmGeneratorExpressionNode std::string EvaluateWithLanguage(const std::vector& parameters, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker*, + cmGeneratorExpressionDAGChecker* /*unused*/, const std::string& lang) const { const char* compilerId = context->LG->GetMakefile()->GetSafeDefinition( @@ -426,7 +438,7 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode std::string EvaluateWithLanguage(const std::vector& parameters, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker*, + cmGeneratorExpressionDAGChecker* /*unused*/, const std::string& lang) const { const char* compilerVersion = @@ -506,8 +518,9 @@ struct PlatformIdNode : public cmGeneratorExpressionNode std::string Evaluate(const std::vector& parameters, cmGeneratorExpressionContext* context, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { const char* platformId = context->LG->GetMakefile()->GetSafeDefinition("CMAKE_SYSTEM_NAME"); @@ -533,9 +546,10 @@ static const struct VersionGreaterNode : public cmGeneratorExpressionNode int NumExpectedParameters() const CM_OVERRIDE { return 2; } std::string Evaluate(const std::vector& parameters, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, parameters.front().c_str(), @@ -552,9 +566,10 @@ static const struct VersionGreaterEqNode : public cmGeneratorExpressionNode int NumExpectedParameters() const CM_OVERRIDE { return 2; } std::string Evaluate(const std::vector& parameters, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, parameters.front().c_str(), @@ -571,9 +586,10 @@ static const struct VersionLessNode : public cmGeneratorExpressionNode int NumExpectedParameters() const CM_OVERRIDE { return 2; } std::string Evaluate(const std::vector& parameters, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, parameters.front().c_str(), @@ -590,9 +606,10 @@ static const struct VersionLessEqNode : public cmGeneratorExpressionNode int NumExpectedParameters() const CM_OVERRIDE { return 2; } std::string Evaluate(const std::vector& parameters, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS_EQUAL, parameters.front().c_str(), @@ -609,9 +626,10 @@ static const struct VersionEqualNode : public cmGeneratorExpressionNode int NumExpectedParameters() const CM_OVERRIDE { return 2; } std::string Evaluate(const std::vector& parameters, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, parameters.front().c_str(), @@ -625,10 +643,11 @@ static const struct LinkOnlyNode : public cmGeneratorExpressionNode { LinkOnlyNode() {} - std::string Evaluate( - const std::vector& parameters, cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker* dagChecker) const CM_OVERRIDE + std::string Evaluate(const std::vector& parameters, + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* dagChecker) const + CM_OVERRIDE { if (!dagChecker->GetTransitivePropertiesOnly()) { return parameters.front(); @@ -643,10 +662,11 @@ static const struct ConfigurationNode : public cmGeneratorExpressionNode int NumExpectedParameters() const CM_OVERRIDE { return 0; } - std::string Evaluate(const std::vector&, + std::string Evaluate(const std::vector& /*parameters*/, cmGeneratorExpressionContext* context, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { context->HadContextSensitiveCondition = true; return context->Config; @@ -662,7 +682,8 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode std::string Evaluate(const std::vector& parameters, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { if (parameters.empty()) { return configurationNode.Evaluate(parameters, context, content, @@ -721,9 +742,10 @@ static const struct JoinNode : public cmGeneratorExpressionNode bool AcceptsArbitraryContentParameter() const CM_OVERRIDE { return true; } std::string Evaluate(const std::vector& parameters, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { std::vector list; cmSystemTools::ExpandListArgument(parameters.front(), list); @@ -1138,9 +1160,10 @@ static const struct TargetNameNode : public cmGeneratorExpressionNode bool RequiresLiteralInput() const CM_OVERRIDE { return true; } std::string Evaluate(const std::vector& parameters, - cmGeneratorExpressionContext*, - const GeneratorExpressionContent*, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { return parameters.front(); } @@ -1156,7 +1179,8 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode std::string Evaluate(const std::vector& parameters, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { if (!context->EvaluateForBuildsystem) { std::ostringstream e; @@ -1357,7 +1381,8 @@ static const struct TargetPolicyNode : public cmGeneratorExpressionNode std::string Evaluate(const std::vector& parameters, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { if (!context->HeadTarget) { reportError( @@ -1414,10 +1439,11 @@ static const struct InstallPrefixNode : public cmGeneratorExpressionNode bool GeneratesContent() const CM_OVERRIDE { return true; } int NumExpectedParameters() const CM_OVERRIDE { return 0; } - std::string Evaluate(const std::vector&, + std::string Evaluate(const std::vector& /*parameters*/, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { reportError(context, content->GetOriginalExpression(), "INSTALL_PREFIX is a marker for install(EXPORT) only. It " @@ -1534,7 +1560,7 @@ struct TargetFilesystemArtifactResultCreator { static std::string Create(cmGeneratorTarget* target, cmGeneratorExpressionContext* context, - const GeneratorExpressionContent*) + const GeneratorExpressionContent* /*unused*/) { return target->GetFullPath(context->Config, false, true); } @@ -1653,7 +1679,8 @@ static const struct ShellPathNode : public cmGeneratorExpressionNode std::string Evaluate(const std::vector& parameters, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker*) const CM_OVERRIDE + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const + CM_OVERRIDE { if (!cmSystemTools::FileIsFullPath(parameters.front())) { reportError(context, content->GetOriginalExpression(), diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 793ad2e..308051b 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -128,7 +128,7 @@ template struct DoAccept { template - static void Do(T&, cmSourceFile*) + static void Do(T& /*unused*/, cmSourceFile* /*unused*/) { } }; @@ -3271,7 +3271,8 @@ template <> bool getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt, const std::string& prop, const std::string& config, - CompatibleType, bool*) + CompatibleType /*unused*/, + bool* /*unused*/) { return tgt->GetLinkInterfaceDependentBoolProperty(prop, config); } @@ -3280,7 +3281,8 @@ template <> const char* getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt, const std::string& prop, const std::string& config, - CompatibleType t, const char**) + CompatibleType t, + const char** /*unused*/) { switch (t) { case BoolType: @@ -3303,7 +3305,7 @@ void checkPropertyConsistency(cmGeneratorTarget const* depender, const std::string& propName, std::set& emitted, const std::string& config, CompatibleType t, - PropertyType*) + PropertyType* /*unused*/) { const char* prop = dependee->GetProperty(propName); if (!prop) { @@ -3536,12 +3538,12 @@ std::string valueAsString(const char* value) template PropertyType impliedValue(PropertyType); template <> -bool impliedValue(bool) +bool impliedValue(bool /*unused*/) { return false; } template <> -const char* impliedValue(const char*) +const char* impliedValue(const char* /*unused*/) { return ""; } @@ -3552,7 +3554,8 @@ std::pair consistentProperty(PropertyType lhs, CompatibleType t); template <> -std::pair consistentProperty(bool lhs, bool rhs, CompatibleType) +std::pair consistentProperty(bool lhs, bool rhs, + CompatibleType /*unused*/) { return std::make_pair(lhs == rhs, lhs); } @@ -3626,7 +3629,7 @@ PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt, const std::string& config, const char* defaultValue, CompatibleType t, - PropertyType*) + PropertyType* /*unused*/) { PropertyType propContent = getTypedProperty(tgt, p); std::vector headPropKeys = tgt->GetPropertyKeys(); diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 3ec16c0..295f65b 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1515,7 +1515,8 @@ void cmGlobalGenerator::ClearGeneratorMembers() this->BinaryDirectories.clear(); } -void cmGlobalGenerator::ComputeTargetObjectDirectory(cmGeneratorTarget*) const +void cmGlobalGenerator::ComputeTargetObjectDirectory( + cmGeneratorTarget* /*unused*/) const { } @@ -1644,15 +1645,17 @@ int cmGlobalGenerator::TryCompile(const std::string& srcdir, } void cmGlobalGenerator::GenerateBuildCommand( - std::vector& makeCommand, const std::string&, - const std::string&, const std::string&, const std::string&, - const std::string&, bool, bool, std::vector const&) + std::vector& makeCommand, const std::string& /*unused*/, + const std::string& /*unused*/, const std::string& /*unused*/, + const std::string& /*unused*/, const std::string& /*unused*/, + bool /*unused*/, bool /*unused*/, std::vector const& /*unused*/) { makeCommand.push_back( "cmGlobalGenerator::GenerateBuildCommand not implemented"); } -int cmGlobalGenerator::Build(const std::string&, const std::string& bindir, +int cmGlobalGenerator::Build(const std::string& /*unused*/, + const std::string& bindir, const std::string& projectName, const std::string& target, std::string& output, const std::string& makeCommandCSTR, @@ -2372,10 +2375,10 @@ std::string cmGlobalGenerator::GetSharedLibFlagsForLanguage( return ""; } -void cmGlobalGenerator::AppendDirectoryForConfig(const std::string&, - const std::string&, - const std::string&, - std::string&) +void cmGlobalGenerator::AppendDirectoryForConfig(const std::string& /*unused*/, + const std::string& /*unused*/, + const std::string& /*unused*/, + std::string& /*unused*/) { // Subclasses that support multiple configurations should implement // this method to append the subdirectory for the given build diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 2f29791..accce49 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1371,8 +1371,8 @@ void cmLocalGenerator::GetTargetDefines(cmGeneratorTarget const* target, this->AddCompileDefinitions(defines, target, config, lang.c_str()); } -std::string cmLocalGenerator::GetTargetFortranFlags(cmGeneratorTarget const*, - std::string const&) +std::string cmLocalGenerator::GetTargetFortranFlags( + cmGeneratorTarget const* /*unused*/, std::string const& /*unused*/) { // Implemented by specific generators that override this. return std::string(); @@ -2478,7 +2478,8 @@ std::string& cmLocalGenerator::CreateSafeUniqueObjectFileName( } void cmLocalGenerator::ComputeObjectFilenames( - std::map&, cmGeneratorTarget const*) + std::map& /*unused*/, + cmGeneratorTarget const* /*unused*/) { } @@ -2613,7 +2614,7 @@ const char* cmLocalGenerator::GetCurrentSourceDirectory() const } std::string cmLocalGenerator::GetTargetDirectory( - const cmGeneratorTarget*) const + const cmGeneratorTarget* /*unused*/) const { cmSystemTools::Error("GetTargetDirectory" " called on cmLocalGenerator"); diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index 124fb6a..c456d88 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -293,7 +293,8 @@ std::string cmPolicies::GetRequiredPolicyError(cmPolicies::PolicyID id) } ///! Get the default status for a policy -cmPolicies::PolicyStatus cmPolicies::GetPolicyStatus(cmPolicies::PolicyID) +cmPolicies::PolicyStatus cmPolicies::GetPolicyStatus( + cmPolicies::PolicyID /*unused*/) { return cmPolicies::WARN; } diff --git a/Source/cmScriptGenerator.cxx b/Source/cmScriptGenerator.cxx index b8aae5d..a000258 100644 --- a/Source/cmScriptGenerator.cxx +++ b/Source/cmScriptGenerator.cxx @@ -117,9 +117,9 @@ void cmScriptGenerator::GenerateScriptActions(std::ostream& os, } } -void cmScriptGenerator::GenerateScriptForConfig(std::ostream&, - const std::string&, - Indent const&) +void cmScriptGenerator::GenerateScriptForConfig(std::ostream& /*unused*/, + const std::string& /*unused*/, + Indent const& /*unused*/) { // No actions for this generator. } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 5745a01..f19f0f6 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -191,7 +191,8 @@ void cmSystemTools::ExpandRegistryValues(std::string& source, KeyWOW64 view) } } #else -void cmSystemTools::ExpandRegistryValues(std::string& source, KeyWOW64) +void cmSystemTools::ExpandRegistryValues(std::string& source, + KeyWOW64 /*unused*/) { cmsys::RegularExpression regEntry("\\[(HKEY[^]]*)\\]"); while (regEntry.find(source)) { diff --git a/Source/cmXMLParser.cxx b/Source/cmXMLParser.cxx index 5e06d36..85d47b6 100644 --- a/Source/cmXMLParser.cxx +++ b/Source/cmXMLParser.cxx @@ -198,7 +198,7 @@ void cmXMLParser::ReportXmlParseError() XML_ErrorString(XML_GetErrorCode(parser))); } -void cmXMLParser::ReportError(int line, int, const char* msg) +void cmXMLParser::ReportError(int line, int /*unused*/, const char* msg) { if (this->ReportCallback) { this->ReportCallback(line, msg, this->ReportCallbackData); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index b11f4f6..08f0a6e 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -113,8 +113,9 @@ static bool cmakeCheckStampFile(const char* stampName); static bool cmakeCheckStampList(const char* stampName); -void cmWarnUnusedCliWarning(const std::string& variable, int, void* ctx, - const char*, const cmMakefile*) +void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/, + void* ctx, const char* /*unused*/, + const cmMakefile* /*unused*/) { cmake* cm = reinterpret_cast(ctx); cm->MarkCliAsUsed(variable); diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 521a5bf..8731b2b 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -124,8 +124,8 @@ static std::string cmakemainGetStack(void* clientdata) return msg; } -static void cmakemainMessageCallback(const char* m, const char*, bool&, - void* clientdata) +static void cmakemainMessageCallback(const char* m, const char* /*unused*/, + bool& /*unused*/, void* clientdata) { std::cerr << m << cmakemainGetStack(clientdata) << std::endl << std::flush; } diff --git a/Tests/CMakeLib/testGeneratedFileStream.cxx b/Tests/CMakeLib/testGeneratedFileStream.cxx index 67dd69a..e5a2f4d 100644 --- a/Tests/CMakeLib/testGeneratedFileStream.cxx +++ b/Tests/CMakeLib/testGeneratedFileStream.cxx @@ -16,7 +16,7 @@ std::cout << "FAILED: " << m1 << m2 << "\n"; \ failed = 1 -int testGeneratedFileStream(int, char* []) +int testGeneratedFileStream(int /*unused*/, char* /*unused*/ []) { int failed = 0; cmGeneratedFileStream gm; diff --git a/Tests/CMakeLib/testSystemTools.cxx b/Tests/CMakeLib/testSystemTools.cxx index a3846c0..fe958bd 100644 --- a/Tests/CMakeLib/testSystemTools.cxx +++ b/Tests/CMakeLib/testSystemTools.cxx @@ -16,7 +16,7 @@ std::cout << "FAILED: " << m << "\n"; \ failed = 1 -int testSystemTools(int, char* []) +int testSystemTools(int /*unused*/, char* /*unused*/ []) { int failed = 0; // ---------------------------------------------------------------------- diff --git a/Tests/CMakeLib/testUTF8.cxx b/Tests/CMakeLib/testUTF8.cxx index 1da23fe..019a2dd 100644 --- a/Tests/CMakeLib/testUTF8.cxx +++ b/Tests/CMakeLib/testUTF8.cxx @@ -97,7 +97,7 @@ static bool decode_bad(test_utf8_char const s) return true; } -int testUTF8(int, char* []) +int testUTF8(int /*unused*/, char* /*unused*/ []) { int result = 0; for (test_utf8_entry const* e = good_entry; e->n; ++e) { diff --git a/Tests/CMakeLib/testXMLParser.cxx b/Tests/CMakeLib/testXMLParser.cxx index 1fd5113..d5e9764 100644 --- a/Tests/CMakeLib/testXMLParser.cxx +++ b/Tests/CMakeLib/testXMLParser.cxx @@ -4,7 +4,7 @@ #include -int testXMLParser(int, char* []) +int testXMLParser(int /*unused*/, char* /*unused*/ []) { // TODO: Derive from parser and check attributes. cmXMLParser parser; diff --git a/Tests/CMakeLib/testXMLSafe.cxx b/Tests/CMakeLib/testXMLSafe.cxx index 34c38fb..4970ccc 100644 --- a/Tests/CMakeLib/testXMLSafe.cxx +++ b/Tests/CMakeLib/testXMLSafe.cxx @@ -28,7 +28,7 @@ static test_pair const pairs[] = { { 0, 0 } }; -int testXMLSafe(int, char* []) +int testXMLSafe(int /*unused*/, char* /*unused*/ []) { int result = 0; for (test_pair const* p = pairs; p->in; ++p) { ----------------------------------------------------------------------- Summary of changes: Source/CPack/cmCPackArchiveGenerator.cxx | 2 +- Source/CPack/cpack.cxx | 2 +- Source/CTest/cmCTestBZR.cxx | 6 +- Source/CTest/cmCTestBuildAndTestHandler.cxx | 5 +- Source/CTest/cmCTestCurl.cxx | 4 +- .../CTest/cmCTestEmptyBinaryDirectoryCommand.cxx | 2 +- Source/CTest/cmCTestHG.cxx | 2 +- Source/CTest/cmCTestHandlerCommand.cxx | 2 +- Source/CTest/cmCTestMemCheckHandler.cxx | 2 +- Source/CTest/cmCTestReadCustomFilesCommand.cxx | 2 +- Source/CTest/cmCTestRunScriptCommand.cxx | 2 +- Source/CTest/cmCTestSVN.cxx | 2 +- Source/CTest/cmCTestScriptHandler.cxx | 11 +- Source/CTest/cmCTestSleepCommand.cxx | 2 +- Source/CTest/cmCTestStartCommand.cxx | 2 +- Source/CTest/cmCTestSubmitHandler.cxx | 10 +- Source/CTest/cmCTestTestHandler.cxx | 23 +-- Source/CTest/cmCTestVC.cxx | 2 +- Source/CTest/cmParseJacocoCoverage.cxx | 2 +- Source/CursesDialog/ccmake.cxx | 6 +- Source/CursesDialog/cmCursesBoolWidget.cxx | 3 +- Source/CursesDialog/cmCursesDummyWidget.cxx | 3 +- Source/CursesDialog/cmCursesLabelWidget.cxx | 3 +- Source/CursesDialog/cmCursesLongMessageForm.cxx | 3 +- Source/CursesDialog/cmCursesMainForm.cxx | 4 +- Source/CursesDialog/cmCursesOptionsWidget.cxx | 3 +- Source/CursesDialog/cmCursesStringWidget.cxx | 8 +- Source/cmArchiveWrite.cxx | 3 +- Source/cmDepends.cxx | 9 +- Source/cmDependsFortran.cxx | 5 +- Source/cmDependsJava.cxx | 10 +- Source/cmDynamicLoader.cxx | 6 +- Source/cmELF.cxx | 8 +- Source/cmExportFileGenerator.cxx | 2 +- Source/cmExportInstallFileGenerator.cxx | 2 +- Source/cmExternalMakefileProjectGenerator.cxx | 3 +- Source/cmExtraEclipseCDT4Generator.cxx | 3 +- Source/cmExtraSublimeTextGenerator.cxx | 3 +- Source/cmFortranParserImpl.cxx | 2 +- Source/cmGeneratorExpressionDAGChecker.cxx | 2 +- Source/cmGeneratorExpressionNode.cxx | 177 +++++++++++--------- Source/cmGeneratorTarget.cxx | 19 ++- Source/cmGlobalGenerator.cxx | 21 ++- Source/cmLocalGenerator.cxx | 9 +- Source/cmPolicies.cxx | 3 +- Source/cmScriptGenerator.cxx | 6 +- Source/cmSystemTools.cxx | 3 +- Source/cmXMLParser.cxx | 2 +- Source/cmake.cxx | 5 +- Source/cmakemain.cxx | 4 +- Tests/CMakeLib/testGeneratedFileStream.cxx | 2 +- Tests/CMakeLib/testSystemTools.cxx | 2 +- Tests/CMakeLib/testUTF8.cxx | 2 +- Tests/CMakeLib/testXMLParser.cxx | 2 +- Tests/CMakeLib/testXMLSafe.cxx | 2 +- 55 files changed, 245 insertions(+), 190 deletions(-) hooks/post-receive -- CMake From kwrobot at kitware.com Wed Aug 17 00:01:06 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Wed, 17 Aug 2016 00:01:06 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-637-g65120d1 Message-ID: <20160817040106.C423FF5362@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 65120d180b6e7658e296fd2c4c85a23f337c06dc (commit) from e240a7c0176450e092e2398148c1e13f8940c239 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=65120d180b6e7658e296fd2c4c85a23f337c06dc commit 65120d180b6e7658e296fd2c4c85a23f337c06dc Author: Kitware Robot AuthorDate: Wed Aug 17 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Wed Aug 17 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 8d950fd..ac1ae03 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160816) +set(CMake_VERSION_PATCH 20160817) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 17 09:02:53 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 17 Aug 2016 09:02:53 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1280-g2b71053 Message-ID: <20160817130253.40EABF59A9@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 2b7105307a5d47cf29bf03d1d1bcc21b16b476bd (commit) via 10792e106aac2e5e3675c96b943818541620aa7c (commit) from 662661b2b462946f8ba6c82af22f014a18619756 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2b7105307a5d47cf29bf03d1d1bcc21b16b476bd commit 2b7105307a5d47cf29bf03d1d1bcc21b16b476bd Merge: 662661b 10792e1 Author: Brad King AuthorDate: Wed Aug 17 09:02:52 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 17 09:02:52 2016 -0400 Merge topic 'process-output-encoding' into next 10792e10 fixup! Windows: Encode child process output to internally-used encoding https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=10792e106aac2e5e3675c96b943818541620aa7c commit 10792e106aac2e5e3675c96b943818541620aa7c Author: Brad King AuthorDate: Wed Aug 17 08:57:15 2016 -0400 Commit: Brad King CommitDate: Wed Aug 17 08:57:15 2016 -0400 fixup! Windows: Encode child process output to internally-used encoding diff --git a/Source/cmProcessOutput.hxx b/Source/cmProcessOutput.hxx index c896720..daffad1 100644 --- a/Source/cmProcessOutput.hxx +++ b/Source/cmProcessOutput.hxx @@ -31,10 +31,10 @@ public: size_t id = 0); private: +#if defined(_WIN32) unsigned int codepage; unsigned int bufferSize; std::vector rawparts; -#if defined(_WIN32) bool DoDecodeText(std::string raw, std::string& decoded, wchar_t* lastChar); #endif }; ----------------------------------------------------------------------- Summary of changes: Source/cmProcessOutput.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 17 09:32:47 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 17 Aug 2016 09:32:47 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1282-g644cdf7 Message-ID: <20160817133248.8E642F5484@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 644cdf712be93436cbd3401d72852f5d4bdb0e2a (commit) via 12924660b9881d24b60ff13da840d7312fa0486f (commit) from 2b7105307a5d47cf29bf03d1d1bcc21b16b476bd (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=644cdf712be93436cbd3401d72852f5d4bdb0e2a commit 644cdf712be93436cbd3401d72852f5d4bdb0e2a Merge: 2b71053 1292466 Author: Brad King AuthorDate: Wed Aug 17 09:32:46 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 17 09:32:46 2016 -0400 Merge topic 'process-output-encoding' into next 12924660 Windows: Encode child process output to internally-used encoding https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=12924660b9881d24b60ff13da840d7312fa0486f commit 12924660b9881d24b60ff13da840d7312fa0486f Author: D?vis Mos?ns AuthorDate: Mon Aug 15 23:34:21 2016 +0300 Commit: Brad King CommitDate: Wed Aug 17 09:32:23 2016 -0400 Windows: Encode child process output to internally-used encoding Typically Windows applications (eg. MSVC compiler) use current console's codepage for output to pipes so we need to encode that to our internally-used encoding (`KWSYS_ENCODING_DEFAULT_CODEPAGE`). diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index cdc8fb1..580c3eb 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -317,6 +317,8 @@ set(SRCS cmOrderDirectories.h cmPolicies.h cmPolicies.cxx + cmProcessOutput.cxx + cmProcessOutput.hxx cmProcessTools.cxx cmProcessTools.h cmProperty.cxx @@ -375,6 +377,9 @@ set(SRCS cm_utf8.c ) +SET_PROPERTY(SOURCE cmProcessOutput.cxx APPEND PROPERTY COMPILE_DEFINITIONS + KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) + set(COMMAND_INCLUDES "#include \"cmTargetPropCommandBase.cxx\"\n") list(APPEND SRCS cmTargetPropCommandBase.cxx) set_property(SOURCE cmTargetPropCommandBase.cxx PROPERTY HEADER_FILE_ONLY ON) diff --git a/Source/cmExecProgramCommand.cxx b/Source/cmExecProgramCommand.cxx index 58bbc31..4391a19 100644 --- a/Source/cmExecProgramCommand.cxx +++ b/Source/cmExecProgramCommand.cxx @@ -11,6 +11,7 @@ ============================================================================*/ #include "cmExecProgramCommand.h" +#include "cmProcessOutput.hxx" #include "cmSystemTools.h" #include @@ -219,6 +220,7 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output, int length; char* data; int p; + cmProcessOutput processOutput; while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) { if (p == cmsysProcess_Pipe_STDOUT || p == cmsysProcess_Pipe_STDERR) { if (verbose) { @@ -230,6 +232,7 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output, // All output has been read. Wait for the process to exit. cmsysProcess_WaitForExit(cp, CM_NULLPTR); + processOutput.DecodeText(output, output); // Check the result of running the process. std::string msg; diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index d97b25f..1ffb163 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -11,6 +11,7 @@ ============================================================================*/ #include "cmExecuteProcessCommand.h" +#include "cmProcessOutput.hxx" #include "cmSystemTools.h" #include @@ -228,17 +229,21 @@ bool cmExecuteProcessCommand::InitialPass(std::vector const& args, int length; char* data; int p; + cmProcessOutput processOutput; + std::string strdata; while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) { // Put the output in the right place. if (p == cmsysProcess_Pipe_STDOUT && !output_quiet) { if (output_variable.empty()) { - cmSystemTools::Stdout(data, length); + processOutput.DecodeText(data, length, strdata, 1); + cmSystemTools::Stdout(strdata.c_str(), strdata.size()); } else { cmExecuteProcessCommandAppend(tempOutput, data, length); } } else if (p == cmsysProcess_Pipe_STDERR && !error_quiet) { if (error_variable.empty()) { - cmSystemTools::Stderr(data, length); + processOutput.DecodeText(data, length, strdata, 2); + cmSystemTools::Stderr(strdata.c_str(), strdata.size()); } else { cmExecuteProcessCommandAppend(tempError, data, length); } @@ -247,6 +252,8 @@ bool cmExecuteProcessCommand::InitialPass(std::vector const& args, // All output has been read. Wait for the process to exit. cmsysProcess_WaitForExit(cp, CM_NULLPTR); + processOutput.DecodeText(tempOutput, tempOutput); + processOutput.DecodeText(tempError, tempError); // Fix the text in the output strings. cmExecuteProcessCommandFixText(tempOutput, output_strip_trailing_whitespace); diff --git a/Source/cmProcessOutput.cxx b/Source/cmProcessOutput.cxx new file mode 100644 index 0000000..59101dd --- /dev/null +++ b/Source/cmProcessOutput.cxx @@ -0,0 +1,155 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2016 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmProcessOutput.hxx" + +#if defined(_WIN32) +#include +unsigned int cmProcessOutput::defaultCodepage = + KWSYS_ENCODING_DEFAULT_CODEPAGE; +#endif + +cmProcessOutput::cmProcessOutput(unsigned int maxSize) +{ +#if defined(_WIN32) + bufferSize = maxSize; + codepage = GetConsoleCP(); + if (!codepage) { + codepage = GetACP(); + } +#else + static_cast(maxSize); +#endif +} + +cmProcessOutput::~cmProcessOutput() +{ +} + +bool cmProcessOutput::DecodeText(std::string raw, std::string& decoded, + size_t id) +{ + bool success = true; + decoded = raw; +#if defined(_WIN32) + if (id > 0) { + if (rawparts.size() < id) { + rawparts.reserve(id); + while (rawparts.size() < id) + rawparts.push_back(std::string()); + } + raw = rawparts[id - 1] + raw; + rawparts[id - 1].clear(); + decoded = raw; + } + if (raw.size() > 0 && codepage != defaultCodepage) { + success = false; + CPINFOEXW cpinfo; + if (id > 0 && raw.size() == bufferSize && + GetCPInfoExW(codepage, 0, &cpinfo) == 1 && cpinfo.MaxCharSize > 1) { + if (cpinfo.MaxCharSize == 2 && cpinfo.LeadByte[0] != 0) { + LPSTR prevChar = + CharPrevExA(codepage, raw.c_str(), raw.c_str() + raw.size(), 0); + bool isLeadByte = + (*(prevChar + 1) == 0) && IsDBCSLeadByteEx(codepage, *prevChar); + if (isLeadByte) { + rawparts[id - 1] += *(raw.end() - 1); + raw.resize(raw.size() - 1); + } + success = DoDecodeText(raw, decoded, NULL); + } else { + bool restoreDecoded = false; + std::string firstDecoded = decoded; + wchar_t lastChar = 0; + for (UINT i = 0; i < cpinfo.MaxCharSize; i++) { + success = DoDecodeText(raw, decoded, &lastChar); + if (success && lastChar != 0) { + if (i == 0) { + firstDecoded = decoded; + } + if (lastChar == cpinfo.UnicodeDefaultChar) { + restoreDecoded = true; + rawparts[id - 1] = *(raw.end() - 1) + rawparts[id - 1]; + raw.resize(raw.size() - 1); + } else { + restoreDecoded = false; + break; + } + } else { + break; + } + } + if (restoreDecoded) { + decoded = firstDecoded; + rawparts[id - 1].clear(); + } + } + } else { + success = DoDecodeText(raw, decoded, NULL); + } + } +#else + static_cast(id); +#endif + return success; +} + +bool cmProcessOutput::DecodeText(const char* data, size_t length, + std::string& decoded, size_t id) +{ + return DecodeText(std::string(data, length), decoded, id); +} + +bool cmProcessOutput::DecodeText(std::vector raw, + std::vector& decoded, size_t id) +{ + std::string str; + const bool success = + DecodeText(std::string(raw.begin(), raw.end()), str, id); + decoded.assign(str.begin(), str.end()); + return success; +} + +#if defined(_WIN32) +bool cmProcessOutput::DoDecodeText(std::string raw, std::string& decoded, + wchar_t* lastChar) +{ + bool success = false; + const int wlength = + MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()), NULL, 0); + wchar_t* wdata = new wchar_t[wlength]; + int r = MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()), wdata, + wlength); + if (r > 0) { + if (lastChar) { + *lastChar = 0; + if ((wlength >= 2 && wdata[wlength - 2] != wdata[wlength - 1]) || + wlength >= 1) { + *lastChar = wdata[wlength - 1]; + } + } + int length = WideCharToMultiByte(defaultCodepage, 0, wdata, wlength, NULL, + 0, NULL, NULL); + char* data = new char[length + 1]; + r = WideCharToMultiByte(defaultCodepage, 0, wdata, wlength, data, length, + NULL, NULL); + if (r > 0) { + data[length] = '\0'; + decoded = data; + success = true; + } + delete[] data; + } + delete[] wdata; + return success; +} +#endif diff --git a/Source/cmProcessOutput.hxx b/Source/cmProcessOutput.hxx new file mode 100644 index 0000000..daffad1 --- /dev/null +++ b/Source/cmProcessOutput.hxx @@ -0,0 +1,42 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2016 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmProcessOutput_hxx +#define cmProcessOutput_hxx + +#include "cmStandardIncludes.h" + +#include +#include + +class cmProcessOutput +{ +public: + static unsigned int defaultCodepage; + // must match to KWSYSPE_PIPE_BUFFER_SIZE + cmProcessOutput(unsigned int maxSize = 1024); + ~cmProcessOutput(); + bool DecodeText(std::string raw, std::string& decoded, size_t id = 0); + bool DecodeText(const char* data, size_t length, std::string& decoded, + size_t id = 0); + bool DecodeText(std::vector raw, std::vector& decoded, + size_t id = 0); + +private: +#if defined(_WIN32) + unsigned int codepage; + unsigned int bufferSize; + std::vector rawparts; + bool DoDecodeText(std::string raw, std::string& decoded, wchar_t* lastChar); +#endif +}; + +#endif diff --git a/Source/cmProcessTools.cxx b/Source/cmProcessTools.cxx index 34b8df2..396d4b9 100644 --- a/Source/cmProcessTools.cxx +++ b/Source/cmProcessTools.cxx @@ -10,6 +10,7 @@ See the License for more information. ============================================================================*/ #include "cmProcessTools.h" +#include "cmProcessOutput.hxx" #include @@ -20,14 +21,18 @@ void cmProcessTools::RunProcess(struct cmsysProcess_s* cp, OutputParser* out, char* data = CM_NULLPTR; int length = 0; int p; + cmProcessOutput processOutput; + std::string strdata; while ((out || err) && (p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) { if (out && p == cmsysProcess_Pipe_STDOUT) { - if (!out->Process(data, length)) { + processOutput.DecodeText(data, length, strdata, 1); + if (!out->Process(strdata.c_str(), int(strdata.size()))) { out = CM_NULLPTR; } } else if (err && p == cmsysProcess_Pipe_STDERR) { - if (!err->Process(data, length)) { + processOutput.DecodeText(data, length, strdata, 2); + if (!err->Process(strdata.c_str(), int(strdata.size()))) { err = CM_NULLPTR; } } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 5745a01..fcf0945 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -21,6 +21,7 @@ #ifdef __QNX__ #include /* for malloc/free on QNX */ #endif +#include "cmProcessOutput.hxx" #include #include #include @@ -612,6 +613,8 @@ bool cmSystemTools::RunSingleCommand(std::vector const& command, char* data; int length; int pipe; + cmProcessOutput processOutput; + std::string strdata; if (outputflag != OUTPUT_PASSTHROUGH && (captureStdOut || captureStdErr || outputflag != OUTPUT_NONE)) { while ((pipe = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR)) > @@ -627,14 +630,16 @@ bool cmSystemTools::RunSingleCommand(std::vector const& command, if (pipe == cmsysProcess_Pipe_STDOUT) { if (outputflag != OUTPUT_NONE) { - cmSystemTools::Stdout(data, length); + processOutput.DecodeText(data, length, strdata, 1); + cmSystemTools::Stdout(strdata.c_str(), strdata.size()); } if (captureStdOut) { tempStdOut.insert(tempStdOut.end(), data, data + length); } } else if (pipe == cmsysProcess_Pipe_STDERR) { if (outputflag != OUTPUT_NONE) { - cmSystemTools::Stderr(data, length); + processOutput.DecodeText(data, length, strdata, 2); + cmSystemTools::Stderr(strdata.c_str(), strdata.size()); } if (captureStdErr) { tempStdErr.insert(tempStdErr.end(), data, data + length); @@ -646,9 +651,11 @@ bool cmSystemTools::RunSingleCommand(std::vector const& command, cmsysProcess_WaitForExit(cp, CM_NULLPTR); if (captureStdOut) { captureStdOut->assign(tempStdOut.begin(), tempStdOut.end()); + processOutput.DecodeText(*captureStdOut, *captureStdOut); } if (captureStdErr) { captureStdErr->assign(tempStdErr.begin(), tempStdErr.end()); + processOutput.DecodeText(*captureStdErr, *captureStdErr); } bool result = true; diff --git a/bootstrap b/bootstrap index 742fa2b..3402c9d 100755 --- a/bootstrap +++ b/bootstrap @@ -328,6 +328,7 @@ CMAKE_CXX_SOURCES="\ cmExprLexer \ cmExprParser \ cmExprParserHelper \ + cmProcessOutput \ " if ${cmake_system_mingw}; then @@ -1343,6 +1344,7 @@ fi cmake_c_flags_String="-DKWSYS_STRING_C" if ${cmake_system_mingw}; then cmake_c_flags_EncodingC="-DKWSYS_ENCODING_DEFAULT_CODEPAGE=CP_ACP" + cmake_cxx_flags_cmProcessOutput="${cmake_c_flags_EncodingC}" fi cmake_cxx_flags_SystemTools=" -DKWSYS_CXX_HAS_SETENV=${KWSYS_CXX_HAS_SETENV} @@ -1359,8 +1361,9 @@ echo "cmake: ${objs}" > "${cmake_bootstrap_dir}/Makefile" echo " ${cmake_cxx_compiler} ${cmake_ld_flags} ${cmake_cxx_flags} ${objs} -o cmake" >> "${cmake_bootstrap_dir}/Makefile" for a in ${CMAKE_CXX_SOURCES}; do src=`cmake_escape "${cmake_source_dir}/Source/${a}.cxx"` + src_flags=`eval echo \\${cmake_cxx_flags_\${a}}` echo "${a}.o : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile" - echo " ${cmake_cxx_compiler} ${cmake_cxx_flags} -c ${src} -o ${a}.o" >> "${cmake_bootstrap_dir}/Makefile" + echo " ${cmake_cxx_compiler} ${cmake_cxx_flags} ${src_flags} -c ${src} -o ${a}.o" >> "${cmake_bootstrap_dir}/Makefile" done echo "cmBootstrapCommands1.o : $cmBootstrapCommands1Deps" >> "${cmake_bootstrap_dir}/Makefile" echo "cmBootstrapCommands2.o : $cmBootstrapCommands2Deps" >> "${cmake_bootstrap_dir}/Makefile" ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 17 09:40:44 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 17 Aug 2016 09:40:44 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1284-gc541113 Message-ID: <20160817134044.1D5CFB1072@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via c541113797bcb0da4a9fbfdde8e7eb72d609a005 (commit) via 6138f98f924c11df5ca309861930f564a0fd5fea (commit) from 644cdf712be93436cbd3401d72852f5d4bdb0e2a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c541113797bcb0da4a9fbfdde8e7eb72d609a005 commit c541113797bcb0da4a9fbfdde8e7eb72d609a005 Merge: 644cdf7 6138f98 Author: Brad King AuthorDate: Wed Aug 17 09:40:43 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 17 09:40:43 2016 -0400 Merge topic 'process-output-encoding' into next 6138f98f Revert "Windows: Encode child process output to internally-used encoding" https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6138f98f924c11df5ca309861930f564a0fd5fea commit 6138f98f924c11df5ca309861930f564a0fd5fea Author: Brad King AuthorDate: Wed Aug 17 09:40:20 2016 -0400 Commit: Brad King CommitDate: Wed Aug 17 09:40:20 2016 -0400 Revert "Windows: Encode child process output to internally-used encoding" This reverts commit 12924660b9881d24b60ff13da840d7312fa0486f. It causes the CTest.UpdateGIT test to fail and so will need to be revised. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 580c3eb..cdc8fb1 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -317,8 +317,6 @@ set(SRCS cmOrderDirectories.h cmPolicies.h cmPolicies.cxx - cmProcessOutput.cxx - cmProcessOutput.hxx cmProcessTools.cxx cmProcessTools.h cmProperty.cxx @@ -377,9 +375,6 @@ set(SRCS cm_utf8.c ) -SET_PROPERTY(SOURCE cmProcessOutput.cxx APPEND PROPERTY COMPILE_DEFINITIONS - KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) - set(COMMAND_INCLUDES "#include \"cmTargetPropCommandBase.cxx\"\n") list(APPEND SRCS cmTargetPropCommandBase.cxx) set_property(SOURCE cmTargetPropCommandBase.cxx PROPERTY HEADER_FILE_ONLY ON) diff --git a/Source/cmExecProgramCommand.cxx b/Source/cmExecProgramCommand.cxx index 4391a19..58bbc31 100644 --- a/Source/cmExecProgramCommand.cxx +++ b/Source/cmExecProgramCommand.cxx @@ -11,7 +11,6 @@ ============================================================================*/ #include "cmExecProgramCommand.h" -#include "cmProcessOutput.hxx" #include "cmSystemTools.h" #include @@ -220,7 +219,6 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output, int length; char* data; int p; - cmProcessOutput processOutput; while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) { if (p == cmsysProcess_Pipe_STDOUT || p == cmsysProcess_Pipe_STDERR) { if (verbose) { @@ -232,7 +230,6 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output, // All output has been read. Wait for the process to exit. cmsysProcess_WaitForExit(cp, CM_NULLPTR); - processOutput.DecodeText(output, output); // Check the result of running the process. std::string msg; diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index 1ffb163..d97b25f 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -11,7 +11,6 @@ ============================================================================*/ #include "cmExecuteProcessCommand.h" -#include "cmProcessOutput.hxx" #include "cmSystemTools.h" #include @@ -229,21 +228,17 @@ bool cmExecuteProcessCommand::InitialPass(std::vector const& args, int length; char* data; int p; - cmProcessOutput processOutput; - std::string strdata; while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) { // Put the output in the right place. if (p == cmsysProcess_Pipe_STDOUT && !output_quiet) { if (output_variable.empty()) { - processOutput.DecodeText(data, length, strdata, 1); - cmSystemTools::Stdout(strdata.c_str(), strdata.size()); + cmSystemTools::Stdout(data, length); } else { cmExecuteProcessCommandAppend(tempOutput, data, length); } } else if (p == cmsysProcess_Pipe_STDERR && !error_quiet) { if (error_variable.empty()) { - processOutput.DecodeText(data, length, strdata, 2); - cmSystemTools::Stderr(strdata.c_str(), strdata.size()); + cmSystemTools::Stderr(data, length); } else { cmExecuteProcessCommandAppend(tempError, data, length); } @@ -252,8 +247,6 @@ bool cmExecuteProcessCommand::InitialPass(std::vector const& args, // All output has been read. Wait for the process to exit. cmsysProcess_WaitForExit(cp, CM_NULLPTR); - processOutput.DecodeText(tempOutput, tempOutput); - processOutput.DecodeText(tempError, tempError); // Fix the text in the output strings. cmExecuteProcessCommandFixText(tempOutput, output_strip_trailing_whitespace); diff --git a/Source/cmProcessOutput.cxx b/Source/cmProcessOutput.cxx deleted file mode 100644 index 59101dd..0000000 --- a/Source/cmProcessOutput.cxx +++ /dev/null @@ -1,155 +0,0 @@ -/*============================================================================ - CMake - Cross Platform Makefile Generator - Copyright 2000-2016 Kitware, Inc., Insight Software Consortium - - Distributed under the OSI-approved BSD License (the "License"); - see accompanying file Copyright.txt for details. - - This software is distributed WITHOUT ANY WARRANTY; without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the License for more information. -============================================================================*/ - -#include "cmProcessOutput.hxx" - -#if defined(_WIN32) -#include -unsigned int cmProcessOutput::defaultCodepage = - KWSYS_ENCODING_DEFAULT_CODEPAGE; -#endif - -cmProcessOutput::cmProcessOutput(unsigned int maxSize) -{ -#if defined(_WIN32) - bufferSize = maxSize; - codepage = GetConsoleCP(); - if (!codepage) { - codepage = GetACP(); - } -#else - static_cast(maxSize); -#endif -} - -cmProcessOutput::~cmProcessOutput() -{ -} - -bool cmProcessOutput::DecodeText(std::string raw, std::string& decoded, - size_t id) -{ - bool success = true; - decoded = raw; -#if defined(_WIN32) - if (id > 0) { - if (rawparts.size() < id) { - rawparts.reserve(id); - while (rawparts.size() < id) - rawparts.push_back(std::string()); - } - raw = rawparts[id - 1] + raw; - rawparts[id - 1].clear(); - decoded = raw; - } - if (raw.size() > 0 && codepage != defaultCodepage) { - success = false; - CPINFOEXW cpinfo; - if (id > 0 && raw.size() == bufferSize && - GetCPInfoExW(codepage, 0, &cpinfo) == 1 && cpinfo.MaxCharSize > 1) { - if (cpinfo.MaxCharSize == 2 && cpinfo.LeadByte[0] != 0) { - LPSTR prevChar = - CharPrevExA(codepage, raw.c_str(), raw.c_str() + raw.size(), 0); - bool isLeadByte = - (*(prevChar + 1) == 0) && IsDBCSLeadByteEx(codepage, *prevChar); - if (isLeadByte) { - rawparts[id - 1] += *(raw.end() - 1); - raw.resize(raw.size() - 1); - } - success = DoDecodeText(raw, decoded, NULL); - } else { - bool restoreDecoded = false; - std::string firstDecoded = decoded; - wchar_t lastChar = 0; - for (UINT i = 0; i < cpinfo.MaxCharSize; i++) { - success = DoDecodeText(raw, decoded, &lastChar); - if (success && lastChar != 0) { - if (i == 0) { - firstDecoded = decoded; - } - if (lastChar == cpinfo.UnicodeDefaultChar) { - restoreDecoded = true; - rawparts[id - 1] = *(raw.end() - 1) + rawparts[id - 1]; - raw.resize(raw.size() - 1); - } else { - restoreDecoded = false; - break; - } - } else { - break; - } - } - if (restoreDecoded) { - decoded = firstDecoded; - rawparts[id - 1].clear(); - } - } - } else { - success = DoDecodeText(raw, decoded, NULL); - } - } -#else - static_cast(id); -#endif - return success; -} - -bool cmProcessOutput::DecodeText(const char* data, size_t length, - std::string& decoded, size_t id) -{ - return DecodeText(std::string(data, length), decoded, id); -} - -bool cmProcessOutput::DecodeText(std::vector raw, - std::vector& decoded, size_t id) -{ - std::string str; - const bool success = - DecodeText(std::string(raw.begin(), raw.end()), str, id); - decoded.assign(str.begin(), str.end()); - return success; -} - -#if defined(_WIN32) -bool cmProcessOutput::DoDecodeText(std::string raw, std::string& decoded, - wchar_t* lastChar) -{ - bool success = false; - const int wlength = - MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()), NULL, 0); - wchar_t* wdata = new wchar_t[wlength]; - int r = MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()), wdata, - wlength); - if (r > 0) { - if (lastChar) { - *lastChar = 0; - if ((wlength >= 2 && wdata[wlength - 2] != wdata[wlength - 1]) || - wlength >= 1) { - *lastChar = wdata[wlength - 1]; - } - } - int length = WideCharToMultiByte(defaultCodepage, 0, wdata, wlength, NULL, - 0, NULL, NULL); - char* data = new char[length + 1]; - r = WideCharToMultiByte(defaultCodepage, 0, wdata, wlength, data, length, - NULL, NULL); - if (r > 0) { - data[length] = '\0'; - decoded = data; - success = true; - } - delete[] data; - } - delete[] wdata; - return success; -} -#endif diff --git a/Source/cmProcessOutput.hxx b/Source/cmProcessOutput.hxx deleted file mode 100644 index daffad1..0000000 --- a/Source/cmProcessOutput.hxx +++ /dev/null @@ -1,42 +0,0 @@ -/*============================================================================ - CMake - Cross Platform Makefile Generator - Copyright 2000-2016 Kitware, Inc., Insight Software Consortium - - Distributed under the OSI-approved BSD License (the "License"); - see accompanying file Copyright.txt for details. - - This software is distributed WITHOUT ANY WARRANTY; without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the License for more information. -============================================================================*/ -#ifndef cmProcessOutput_hxx -#define cmProcessOutput_hxx - -#include "cmStandardIncludes.h" - -#include -#include - -class cmProcessOutput -{ -public: - static unsigned int defaultCodepage; - // must match to KWSYSPE_PIPE_BUFFER_SIZE - cmProcessOutput(unsigned int maxSize = 1024); - ~cmProcessOutput(); - bool DecodeText(std::string raw, std::string& decoded, size_t id = 0); - bool DecodeText(const char* data, size_t length, std::string& decoded, - size_t id = 0); - bool DecodeText(std::vector raw, std::vector& decoded, - size_t id = 0); - -private: -#if defined(_WIN32) - unsigned int codepage; - unsigned int bufferSize; - std::vector rawparts; - bool DoDecodeText(std::string raw, std::string& decoded, wchar_t* lastChar); -#endif -}; - -#endif diff --git a/Source/cmProcessTools.cxx b/Source/cmProcessTools.cxx index 396d4b9..34b8df2 100644 --- a/Source/cmProcessTools.cxx +++ b/Source/cmProcessTools.cxx @@ -10,7 +10,6 @@ See the License for more information. ============================================================================*/ #include "cmProcessTools.h" -#include "cmProcessOutput.hxx" #include @@ -21,18 +20,14 @@ void cmProcessTools::RunProcess(struct cmsysProcess_s* cp, OutputParser* out, char* data = CM_NULLPTR; int length = 0; int p; - cmProcessOutput processOutput; - std::string strdata; while ((out || err) && (p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) { if (out && p == cmsysProcess_Pipe_STDOUT) { - processOutput.DecodeText(data, length, strdata, 1); - if (!out->Process(strdata.c_str(), int(strdata.size()))) { + if (!out->Process(data, length)) { out = CM_NULLPTR; } } else if (err && p == cmsysProcess_Pipe_STDERR) { - processOutput.DecodeText(data, length, strdata, 2); - if (!err->Process(strdata.c_str(), int(strdata.size()))) { + if (!err->Process(data, length)) { err = CM_NULLPTR; } } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index fcf0945..5745a01 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -21,7 +21,6 @@ #ifdef __QNX__ #include /* for malloc/free on QNX */ #endif -#include "cmProcessOutput.hxx" #include #include #include @@ -613,8 +612,6 @@ bool cmSystemTools::RunSingleCommand(std::vector const& command, char* data; int length; int pipe; - cmProcessOutput processOutput; - std::string strdata; if (outputflag != OUTPUT_PASSTHROUGH && (captureStdOut || captureStdErr || outputflag != OUTPUT_NONE)) { while ((pipe = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR)) > @@ -630,16 +627,14 @@ bool cmSystemTools::RunSingleCommand(std::vector const& command, if (pipe == cmsysProcess_Pipe_STDOUT) { if (outputflag != OUTPUT_NONE) { - processOutput.DecodeText(data, length, strdata, 1); - cmSystemTools::Stdout(strdata.c_str(), strdata.size()); + cmSystemTools::Stdout(data, length); } if (captureStdOut) { tempStdOut.insert(tempStdOut.end(), data, data + length); } } else if (pipe == cmsysProcess_Pipe_STDERR) { if (outputflag != OUTPUT_NONE) { - processOutput.DecodeText(data, length, strdata, 2); - cmSystemTools::Stderr(strdata.c_str(), strdata.size()); + cmSystemTools::Stderr(data, length); } if (captureStdErr) { tempStdErr.insert(tempStdErr.end(), data, data + length); @@ -651,11 +646,9 @@ bool cmSystemTools::RunSingleCommand(std::vector const& command, cmsysProcess_WaitForExit(cp, CM_NULLPTR); if (captureStdOut) { captureStdOut->assign(tempStdOut.begin(), tempStdOut.end()); - processOutput.DecodeText(*captureStdOut, *captureStdOut); } if (captureStdErr) { captureStdErr->assign(tempStdErr.begin(), tempStdErr.end()); - processOutput.DecodeText(*captureStdErr, *captureStdErr); } bool result = true; diff --git a/bootstrap b/bootstrap index 3402c9d..742fa2b 100755 --- a/bootstrap +++ b/bootstrap @@ -328,7 +328,6 @@ CMAKE_CXX_SOURCES="\ cmExprLexer \ cmExprParser \ cmExprParserHelper \ - cmProcessOutput \ " if ${cmake_system_mingw}; then @@ -1344,7 +1343,6 @@ fi cmake_c_flags_String="-DKWSYS_STRING_C" if ${cmake_system_mingw}; then cmake_c_flags_EncodingC="-DKWSYS_ENCODING_DEFAULT_CODEPAGE=CP_ACP" - cmake_cxx_flags_cmProcessOutput="${cmake_c_flags_EncodingC}" fi cmake_cxx_flags_SystemTools=" -DKWSYS_CXX_HAS_SETENV=${KWSYS_CXX_HAS_SETENV} @@ -1361,9 +1359,8 @@ echo "cmake: ${objs}" > "${cmake_bootstrap_dir}/Makefile" echo " ${cmake_cxx_compiler} ${cmake_ld_flags} ${cmake_cxx_flags} ${objs} -o cmake" >> "${cmake_bootstrap_dir}/Makefile" for a in ${CMAKE_CXX_SOURCES}; do src=`cmake_escape "${cmake_source_dir}/Source/${a}.cxx"` - src_flags=`eval echo \\${cmake_cxx_flags_\${a}}` echo "${a}.o : ${src} ${dep}" >> "${cmake_bootstrap_dir}/Makefile" - echo " ${cmake_cxx_compiler} ${cmake_cxx_flags} ${src_flags} -c ${src} -o ${a}.o" >> "${cmake_bootstrap_dir}/Makefile" + echo " ${cmake_cxx_compiler} ${cmake_cxx_flags} -c ${src} -o ${a}.o" >> "${cmake_bootstrap_dir}/Makefile" done echo "cmBootstrapCommands1.o : $cmBootstrapCommands1Deps" >> "${cmake_bootstrap_dir}/Makefile" echo "cmBootstrapCommands2.o : $cmBootstrapCommands2Deps" >> "${cmake_bootstrap_dir}/Makefile" ----------------------------------------------------------------------- Summary of changes: Source/CMakeLists.txt | 5 -- Source/cmExecProgramCommand.cxx | 3 - Source/cmExecuteProcessCommand.cxx | 11 +-- Source/cmProcessOutput.cxx | 155 ------------------------------------ Source/cmProcessOutput.hxx | 42 ---------- Source/cmProcessTools.cxx | 9 +-- Source/cmSystemTools.cxx | 11 +-- bootstrap | 5 +- 8 files changed, 7 insertions(+), 234 deletions(-) delete mode 100644 Source/cmProcessOutput.cxx delete mode 100644 Source/cmProcessOutput.hxx hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 17 10:46:25 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 17 Aug 2016 10:46:25 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-640-g76ff725 Message-ID: <20160817144625.7F88CF3C22@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 76ff725ae7a38b4044cc3d5dc6f8e76cbd6c20aa (commit) via ea51b71a4f76597ada400d8bdea75cc9548530a3 (commit) via c18dc6fbe5b68312be52353aa0a493106584ffe7 (commit) from 65120d180b6e7658e296fd2c4c85a23f337c06dc (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=76ff725ae7a38b4044cc3d5dc6f8e76cbd6c20aa commit 76ff725ae7a38b4044cc3d5dc6f8e76cbd6c20aa Merge: 65120d1 ea51b71 Author: Brad King AuthorDate: Wed Aug 17 10:46:23 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 17 10:46:23 2016 -0400 Merge topic 'cmake-developer-reference' ea51b71a QtIFW: Developer Reference installation c18dc6fb Added CMake_BUILD_DEVELOPER_REFERENCE option ----------------------------------------------------------------------- Summary of changes: CMakeCPack.cmake | 16 +- CMakeCPackOptions.cmake.in | 23 ++ CMakeLists.txt | 5 + Source/CMakeLists.txt | 9 + Source/QtDialog/CMakeSetup64.png | Bin 0 -> 7213 bytes ...tGUI.qs => CMake.DeveloperReference.HTML.qs.in} | 6 +- Source/dir.dox | 7 + Source/dir.dox.in | 7 + Utilities/Doxygen/CMakeLists.txt | 92 +++++++- Utilities/Doxygen/DeveloperReference/mainpage.dox | 8 + Utilities/Doxygen/authors.txt | 17 -- Utilities/Doxygen/doc_makeall.sh.in | 248 -------------------- Utilities/Doxygen/doxyfile.in | 35 +-- 13 files changed, 177 insertions(+), 296 deletions(-) create mode 100644 Source/QtDialog/CMakeSetup64.png copy Source/QtIFW/{CMake.Dialogs.QtGUI.qs => CMake.DeveloperReference.HTML.qs.in} (76%) create mode 100644 Source/dir.dox create mode 100644 Source/dir.dox.in create mode 100644 Utilities/Doxygen/DeveloperReference/mainpage.dox delete mode 100644 Utilities/Doxygen/authors.txt delete mode 100755 Utilities/Doxygen/doc_makeall.sh.in hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 17 10:46:28 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 17 Aug 2016 10:46:28 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-643-g5d16907 Message-ID: <20160817144628.80EAAF3D9B@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 5d1690725bdbd5840e1188e9025121ac2f9878ed (commit) via 49ad7f9af84dd46e5527e6fefaa47d8bde748bca (commit) via 1d408dc10f492d060b8b9546c3ed3521d7051fd8 (commit) from 76ff725ae7a38b4044cc3d5dc6f8e76cbd6c20aa (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5d1690725bdbd5840e1188e9025121ac2f9878ed commit 5d1690725bdbd5840e1188e9025121ac2f9878ed Merge: 76ff725 49ad7f9 Author: Brad King AuthorDate: Wed Aug 17 10:46:26 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 17 10:46:26 2016 -0400 Merge topic 'cmake-capabilities' 49ad7f9a cmake: Add `cmake -E capabilities` mode 1d408dc1 cmake: Constify cmake::GetRegisteredGenerators ----------------------------------------------------------------------- Summary of changes: Help/manual/cmake.1.rst | 37 +++++++++ Help/release/dev/cmake-capabilities.rst | 6 ++ Source/cmake.cxx | 81 +++++++++++++++++++- Source/cmake.h | 4 +- Source/cmcmd.cxx | 12 +++ .../E_capabilities-arg-result.txt} | 0 .../CommandLine/E_capabilities-arg-stderr.txt | 1 + .../RunCMake/CommandLine/E_capabilities-stdout.txt | 1 + Tests/RunCMake/CommandLine/RunCMakeTest.cmake | 2 + 9 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 Help/release/dev/cmake-capabilities.rst copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => CommandLine/E_capabilities-arg-result.txt} (100%) create mode 100644 Tests/RunCMake/CommandLine/E_capabilities-arg-stderr.txt create mode 100644 Tests/RunCMake/CommandLine/E_capabilities-stdout.txt hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 17 10:46:31 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 17 Aug 2016 10:46:31 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-645-gc700d11 Message-ID: <20160817144631.74411F46AD@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via c700d11d259af9c00680321804669fadbe378a22 (commit) via 7ded655f7ba82ea72a82d0555449f2df5ef38594 (commit) from 5d1690725bdbd5840e1188e9025121ac2f9878ed (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c700d11d259af9c00680321804669fadbe378a22 commit c700d11d259af9c00680321804669fadbe378a22 Merge: 5d16907 7ded655 Author: Brad King AuthorDate: Wed Aug 17 10:46:29 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 17 10:46:29 2016 -0400 Merge topic 'FindCUDA-target-include-dirs' 7ded655f FindCUDA: Take NVCC include directories from target properties ----------------------------------------------------------------------- Summary of changes: Modules/FindCUDA.cmake | 32 +++++++++++--------------------- Modules/FindCUDA/run_nvcc.cmake | 17 ++++++++++++++++- 2 files changed, 27 insertions(+), 22 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 17 10:46:34 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 17 Aug 2016 10:46:34 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-647-g29593b7 Message-ID: <20160817144634.5AD27F46B1@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 29593b79a236f9bd6653ed0ab874444ae4f38f00 (commit) via a2af850ba6dbee7797484ec5f6696525123023fc (commit) from c700d11d259af9c00680321804669fadbe378a22 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=29593b79a236f9bd6653ed0ab874444ae4f38f00 commit 29593b79a236f9bd6653ed0ab874444ae4f38f00 Merge: c700d11 a2af850 Author: Brad King AuthorDate: Wed Aug 17 10:46:32 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 17 10:46:32 2016 -0400 Merge topic 'include-what-you-use' a2af850b fix a batch of include-what-you-use violations ----------------------------------------------------------------------- Summary of changes: Source/CursesDialog/cmCursesCacheEntryComposite.h | 2 ++ Source/cmCacheManager.h | 1 + Source/cmGhsMultiTargetGenerator.h | 4 ++-- Source/cmState.cxx | 9 +++++++++ Source/cmState.h | 14 ++++++++++---- Source/cmSystemTools.h | 5 ++++- Source/cmTarget.cxx | 12 ++++++++---- Source/cmTarget.h | 21 ++++++++++++--------- Source/cmTest.cxx | 6 +++--- Source/cmTest.h | 7 +++++-- Source/cmTestGenerator.cxx | 8 ++++++++ Source/cmTestGenerator.h | 8 +++++++- Source/cmUuid.cxx | 4 ++-- Source/cmUuid.h | 5 ++++- Source/cmVariableWatch.cxx | 2 ++ Source/cmVariableWatch.h | 6 +++++- Source/cmVersion.cxx | 2 +- Source/cmVersion.h | 2 +- Source/cmXMLParser.cxx | 6 ++++-- Source/cmXMLParser.h | 4 +++- Source/cmXMLSafe.cxx | 2 -- Source/cmXMLSafe.h | 2 +- Source/cmXMLWriter.cxx | 2 -- Source/cmXMLWriter.h | 2 +- Source/cmcldeps.cxx | 1 + Tests/CMakeLib/run_compile_commands.cxx | 8 ++++++++ Tests/CMakeLib/testSystemTools.cxx | 3 +++ 27 files changed, 107 insertions(+), 41 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 17 10:46:38 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 17 Aug 2016 10:46:38 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-649-g67a7dce Message-ID: <20160817144638.551B5F4680@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 67a7dcef45fef6172514d6df1bea3ca94a04735a (commit) via e7b842e18955d13f6d9c021bab4a8935bf282744 (commit) from 29593b79a236f9bd6653ed0ab874444ae4f38f00 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=67a7dcef45fef6172514d6df1bea3ca94a04735a commit 67a7dcef45fef6172514d6df1bea3ca94a04735a Merge: 29593b7 e7b842e Author: Brad King AuthorDate: Wed Aug 17 10:46:35 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 17 10:46:35 2016 -0400 Merge topic 'readability-named-parameter' e7b842e1 Make sure unnused parameters are /*named*/ ----------------------------------------------------------------------- Summary of changes: Source/CPack/cmCPackArchiveGenerator.cxx | 2 +- Source/CPack/cpack.cxx | 2 +- Source/CTest/cmCTestBZR.cxx | 6 +- Source/CTest/cmCTestBuildAndTestHandler.cxx | 5 +- Source/CTest/cmCTestCurl.cxx | 4 +- .../CTest/cmCTestEmptyBinaryDirectoryCommand.cxx | 2 +- Source/CTest/cmCTestHG.cxx | 2 +- Source/CTest/cmCTestHandlerCommand.cxx | 2 +- Source/CTest/cmCTestMemCheckHandler.cxx | 2 +- Source/CTest/cmCTestReadCustomFilesCommand.cxx | 2 +- Source/CTest/cmCTestRunScriptCommand.cxx | 2 +- Source/CTest/cmCTestSVN.cxx | 2 +- Source/CTest/cmCTestScriptHandler.cxx | 11 +- Source/CTest/cmCTestSleepCommand.cxx | 2 +- Source/CTest/cmCTestStartCommand.cxx | 2 +- Source/CTest/cmCTestSubmitHandler.cxx | 10 +- Source/CTest/cmCTestTestHandler.cxx | 23 +-- Source/CTest/cmCTestVC.cxx | 2 +- Source/CTest/cmParseJacocoCoverage.cxx | 2 +- Source/CursesDialog/ccmake.cxx | 6 +- Source/CursesDialog/cmCursesBoolWidget.cxx | 3 +- Source/CursesDialog/cmCursesDummyWidget.cxx | 3 +- Source/CursesDialog/cmCursesLabelWidget.cxx | 3 +- Source/CursesDialog/cmCursesLongMessageForm.cxx | 3 +- Source/CursesDialog/cmCursesMainForm.cxx | 4 +- Source/CursesDialog/cmCursesOptionsWidget.cxx | 3 +- Source/CursesDialog/cmCursesStringWidget.cxx | 8 +- Source/cmArchiveWrite.cxx | 3 +- Source/cmDepends.cxx | 9 +- Source/cmDependsFortran.cxx | 5 +- Source/cmDependsJava.cxx | 10 +- Source/cmDynamicLoader.cxx | 6 +- Source/cmELF.cxx | 8 +- Source/cmExportFileGenerator.cxx | 2 +- Source/cmExportInstallFileGenerator.cxx | 2 +- Source/cmExternalMakefileProjectGenerator.cxx | 3 +- Source/cmExtraEclipseCDT4Generator.cxx | 3 +- Source/cmExtraSublimeTextGenerator.cxx | 3 +- Source/cmFortranParserImpl.cxx | 2 +- Source/cmGeneratorExpressionDAGChecker.cxx | 2 +- Source/cmGeneratorExpressionNode.cxx | 177 +++++++++++--------- Source/cmGeneratorTarget.cxx | 19 ++- Source/cmGlobalGenerator.cxx | 21 ++- Source/cmLocalGenerator.cxx | 9 +- Source/cmPolicies.cxx | 3 +- Source/cmScriptGenerator.cxx | 6 +- Source/cmSystemTools.cxx | 3 +- Source/cmXMLParser.cxx | 2 +- Source/cmake.cxx | 5 +- Source/cmakemain.cxx | 4 +- Tests/CMakeLib/testGeneratedFileStream.cxx | 2 +- Tests/CMakeLib/testSystemTools.cxx | 2 +- Tests/CMakeLib/testUTF8.cxx | 2 +- Tests/CMakeLib/testXMLParser.cxx | 2 +- Tests/CMakeLib/testXMLSafe.cxx | 2 +- 55 files changed, 245 insertions(+), 190 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 17 10:47:42 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 17 Aug 2016 10:47:42 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1291-g253e20a Message-ID: <20160817144742.2A0B6F4791@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 253e20a8ccdf6fd9287faf8cde8af74ecd13c471 (commit) via 67a7dcef45fef6172514d6df1bea3ca94a04735a (commit) via 29593b79a236f9bd6653ed0ab874444ae4f38f00 (commit) via c700d11d259af9c00680321804669fadbe378a22 (commit) via 5d1690725bdbd5840e1188e9025121ac2f9878ed (commit) via 76ff725ae7a38b4044cc3d5dc6f8e76cbd6c20aa (commit) via 65120d180b6e7658e296fd2c4c85a23f337c06dc (commit) from c541113797bcb0da4a9fbfdde8e7eb72d609a005 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=253e20a8ccdf6fd9287faf8cde8af74ecd13c471 commit 253e20a8ccdf6fd9287faf8cde8af74ecd13c471 Merge: c541113 67a7dce Author: Brad King AuthorDate: Wed Aug 17 10:47:33 2016 -0400 Commit: Brad King CommitDate: Wed Aug 17 10:47:33 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 17 11:10:20 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 17 Aug 2016 11:10:20 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1294-g15df44b Message-ID: <20160817151020.DA76FB03E9@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 15df44b216c93a123bcb005b33795e20e49f11f8 (commit) via 27591a541c3ee7c0a941295f25610631bf18ca74 (commit) via 481c9003fa41e75731bc463cdfa4310e91d5ea4c (commit) from 253e20a8ccdf6fd9287faf8cde8af74ecd13c471 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=15df44b216c93a123bcb005b33795e20e49f11f8 commit 15df44b216c93a123bcb005b33795e20e49f11f8 Merge: 253e20a 27591a5 Author: Brad King AuthorDate: Wed Aug 17 11:10:20 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 17 11:10:20 2016 -0400 Merge topic 'minor-cleanups' into next 27591a54 Define WIN32_LEAN_AND_MEAN for CMake sources on Windows 481c9003 libarchive: Fix include order in xxhash.c https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=27591a541c3ee7c0a941295f25610631bf18ca74 commit 27591a541c3ee7c0a941295f25610631bf18ca74 Author: Brad King AuthorDate: Wed Aug 17 10:43:26 2016 -0400 Commit: Brad King CommitDate: Wed Aug 17 10:48:28 2016 -0400 Define WIN32_LEAN_AND_MEAN for CMake sources on Windows This reduces APIs included by `windows.h`. We can include the headers for those APIs as needed. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index b68675d..e63bf5a 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -45,9 +45,12 @@ endif() set(EXECUTABLE_OUTPUT_PATH ${CMake_BIN_DIR}) -# ensure Unicode friendly APIs are used on Windows if(WIN32) + # ensure Unicode friendly APIs are used on Windows add_definitions(-DUNICODE -D_UNICODE) + + # minimize windows.h content + add_definitions(-DWIN32_LEAN_AND_MEAN) endif() # configure the .dox.in file https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=481c9003fa41e75731bc463cdfa4310e91d5ea4c commit 481c9003fa41e75731bc463cdfa4310e91d5ea4c Author: Brad King AuthorDate: Wed Aug 17 10:41:13 2016 -0400 Commit: Brad King CommitDate: Wed Aug 17 10:48:28 2016 -0400 libarchive: Fix include order in xxhash.c We need to include `archive_platform.h` before any system headers in order to ensure that `_WIN32_WINNT` is defined early enough. diff --git a/Utilities/cmlibarchive/libarchive/xxhash.c b/Utilities/cmlibarchive/libarchive/xxhash.c index d7f8e96..262fecb 100644 --- a/Utilities/cmlibarchive/libarchive/xxhash.c +++ b/Utilities/cmlibarchive/libarchive/xxhash.c @@ -29,12 +29,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - xxHash source repository : http://code.google.com/p/xxhash/ */ -#include -#include #include "archive_platform.h" #include "archive_xxhash.h" +#include +#include + #ifdef HAVE_LIBLZ4 /*************************************** ----------------------------------------------------------------------- Summary of changes: Source/CMakeLists.txt | 5 ++++- Utilities/cmlibarchive/libarchive/xxhash.c | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 17 13:39:47 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 17 Aug 2016 13:39:47 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1297-g2e928b1 Message-ID: <20160817173947.97CC4AFA63@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 2e928b19d912dcb7db0c6b10a89a35c5b5e2462d (commit) via 03d5ae0b37adc3fd12fa2bdb6b96252182f48d2a (commit) via 08f570b7fb76c1895663ae8665d2494c988069b4 (commit) from 15df44b216c93a123bcb005b33795e20e49f11f8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2e928b19d912dcb7db0c6b10a89a35c5b5e2462d commit 2e928b19d912dcb7db0c6b10a89a35c5b5e2462d Merge: 15df44b 03d5ae0 Author: Brad King AuthorDate: Wed Aug 17 13:39:46 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 17 13:39:46 2016 -0400 Merge topic 'msvc-suppress-rc-logo' into next 03d5ae0b Merge branch 'minor-cleanups' into msvc-suppress-rc-logo 08f570b7 MSVC: Suppress rc.exe logo/banner when CMAKE_VERBOSE_MAKEFILE is false https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=03d5ae0b37adc3fd12fa2bdb6b96252182f48d2a commit 03d5ae0b37adc3fd12fa2bdb6b96252182f48d2a Merge: 08f570b 27591a5 Author: Brad King AuthorDate: Wed Aug 17 13:30:35 2016 -0400 Commit: Brad King CommitDate: Wed Aug 17 13:30:35 2016 -0400 Merge branch 'minor-cleanups' into msvc-suppress-rc-logo https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=08f570b7fb76c1895663ae8665d2494c988069b4 commit 08f570b7fb76c1895663ae8665d2494c988069b4 Author: Taylor Braun-Jones AuthorDate: Tue Aug 16 12:36:49 2016 -0400 Commit: Taylor Braun-Jones CommitDate: Wed Aug 17 11:49:12 2016 -0400 MSVC: Suppress rc.exe logo/banner when CMAKE_VERBOSE_MAKEFILE is false This matches the current behavior for cl.exe. Closes: #16246 diff --git a/Modules/CMakeRCInformation.cmake b/Modules/CMakeRCInformation.cmake index 60276e2..8e320da 100644 --- a/Modules/CMakeRCInformation.cmake +++ b/Modules/CMakeRCInformation.cmake @@ -44,7 +44,7 @@ set(CMAKE_INCLUDE_FLAG_RC "-I") # compile a Resource file into an object file if(NOT CMAKE_RC_COMPILE_OBJECT) set(CMAKE_RC_COMPILE_OBJECT - " /fo ") + " ${CMAKE_CL_NOLOGO} /fo ") endif() mark_as_advanced( ----------------------------------------------------------------------- Summary of changes: Modules/CMakeRCInformation.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From daniel at pfeifer-mail.de Wed Aug 17 18:24:52 2016 From: daniel at pfeifer-mail.de (Daniel Pfeifer) Date: Wed, 17 Aug 2016 18:24:52 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1300-g951bc07 Message-ID: <20160817222452.8FA6BF4F54@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 951bc07441bdf29dde92ff7e0a58ec5b21a847f5 (commit) via 250091ffa36ef6df3f4fb9429aefaef95bf70661 (commit) via 373b2e483d983136415190dcc838e636077e5991 (commit) from 2e928b19d912dcb7db0c6b10a89a35c5b5e2462d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=951bc07441bdf29dde92ff7e0a58ec5b21a847f5 commit 951bc07441bdf29dde92ff7e0a58ec5b21a847f5 Merge: 2e928b1 250091f Author: Daniel Pfeifer AuthorDate: Wed Aug 17 18:24:49 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 17 18:24:49 2016 -0400 Merge topic 'include-what-you-use' into next 250091ff fix a batch of include-what-you-use violations 373b2e48 cmArchiveWrite: replace mode_t with int https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=250091ffa36ef6df3f4fb9429aefaef95bf70661 commit 250091ffa36ef6df3f4fb9429aefaef95bf70661 Author: Daniel Pfeifer AuthorDate: Thu Aug 18 00:24:24 2016 +0200 Commit: Daniel Pfeifer CommitDate: Thu Aug 18 00:24:24 2016 +0200 fix a batch of include-what-you-use violations diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx index 56da2ac..fa5a08e 100644 --- a/Source/cmArchiveWrite.cxx +++ b/Source/cmArchiveWrite.cxx @@ -16,7 +16,11 @@ #include "cm_get_date.h" #include #include +#include #include +#include +#include +#include #ifndef __LA_SSIZE_T #define __LA_SSIZE_T la_ssize_t diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h index b15c15a..c859453 100644 --- a/Source/cmArchiveWrite.h +++ b/Source/cmArchiveWrite.h @@ -12,7 +12,11 @@ #ifndef cmArchiveWrite_h #define cmArchiveWrite_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep + +#include +#include +#include #if !defined(CMAKE_BUILD_WITH_CMAKE) #error "cmArchiveWrite not allowed during bootstrap build!" diff --git a/Source/cmCLocaleEnvironmentScope.cxx b/Source/cmCLocaleEnvironmentScope.cxx index e4c74ec..e38f531 100644 --- a/Source/cmCLocaleEnvironmentScope.cxx +++ b/Source/cmCLocaleEnvironmentScope.cxx @@ -15,6 +15,7 @@ #include "cmSystemTools.h" #include +#include cmCLocaleEnvironmentScope::cmCLocaleEnvironmentScope() { diff --git a/Source/cmCLocaleEnvironmentScope.h b/Source/cmCLocaleEnvironmentScope.h index b011741..572beaf 100644 --- a/Source/cmCLocaleEnvironmentScope.h +++ b/Source/cmCLocaleEnvironmentScope.h @@ -13,7 +13,10 @@ #ifndef cmCLocaleEnvironmentScope_h #define cmCLocaleEnvironmentScope_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep + +#include +#include class cmCLocaleEnvironmentScope { diff --git a/Source/cmCPackPropertiesGenerator.cxx b/Source/cmCPackPropertiesGenerator.cxx index af01c7d..ae6b0a1 100644 --- a/Source/cmCPackPropertiesGenerator.cxx +++ b/Source/cmCPackPropertiesGenerator.cxx @@ -1,8 +1,13 @@ #include "cmCPackPropertiesGenerator.h" -#include "cmLocalGenerator.h" +#include "cmGeneratorExpression.h" +#include "cmInstalledFile.h" #include "cmOutputConverter.h" +#include +#include +#include + cmCPackPropertiesGenerator::cmCPackPropertiesGenerator( cmLocalGenerator* lg, cmInstalledFile const& installedFile, std::vector const& configurations) diff --git a/Source/cmCPackPropertiesGenerator.h b/Source/cmCPackPropertiesGenerator.h index 4d092f6..77018b0 100644 --- a/Source/cmCPackPropertiesGenerator.h +++ b/Source/cmCPackPropertiesGenerator.h @@ -12,9 +12,15 @@ #ifndef cmCPackPropertiesGenerator_h #define cmCPackPropertiesGenerator_h -#include "cmInstalledFile.h" +#include // IWYU pragma: keep + #include "cmScriptGenerator.h" +#include +#include +#include + +class cmInstalledFile; class cmLocalGenerator; /** \class cmCPackPropertiesGenerator diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index bdd7303..386c39a 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -16,10 +16,12 @@ #include "cmVersion.h" #include "cmake.h" -#include #include #include -#include +#include +#include +#include +#include cmCacheManager::cmCacheManager() { diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h index 14e0f0a..3e32cf0 100644 --- a/Source/cmCacheManager.h +++ b/Source/cmCacheManager.h @@ -12,13 +12,19 @@ #ifndef cmCacheManager_h #define cmCacheManager_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include "cmPropertyMap.h" #include "cmState.h" +#include +#include +#include +#include +#include +#include + class cmake; -class cmMarkAsAdvancedCommand; /** \class cmCacheManager * \brief Control class for cmake's cache diff --git a/Source/cmCommands.h b/Source/cmCommands.h index d0f1ab7..034c9c7 100644 --- a/Source/cmCommands.h +++ b/Source/cmCommands.h @@ -12,7 +12,7 @@ #ifndef cmCommands_h #define cmCommands_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 7ad18f0..f65e2fb 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -11,13 +11,21 @@ ============================================================================*/ #include "cmCommonTargetGenerator.h" +#include +#include +#include +#include +#include + +#include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" #include "cmGeneratorTarget.h" #include "cmGlobalCommonGenerator.h" #include "cmLocalCommonGenerator.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmSourceFile.h" -#include "cmSystemTools.h" +#include "cmState.h" cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt) : GeneratorTarget(gt) diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index 0bafde9..d3f9d64 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -12,9 +12,13 @@ #ifndef cmCommonTargetGenerator_h #define cmCommonTargetGenerator_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep -#include "cmLocalGenerator.h" +#include "cmOutputConverter.h" + +#include +#include +#include class cmGeneratorTarget; class cmGlobalCommonGenerator; diff --git a/Source/cmComputeComponentGraph.h b/Source/cmComputeComponentGraph.h index fb95f9a..cc468d9 100644 --- a/Source/cmComputeComponentGraph.h +++ b/Source/cmComputeComponentGraph.h @@ -12,11 +12,12 @@ #ifndef cmComputeComponentGraph_h #define cmComputeComponentGraph_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include "cmGraphAdjacencyList.h" #include +#include /** \class cmComputeComponentGraph * \brief Analyze a graph to determine strongly connected components. diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index fffb77d..644f4a9 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -13,13 +13,22 @@ #include "cmAlgorithms.h" #include "cmComputeComponentGraph.h" +#include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmState.h" +#include "cmSystemTools.h" #include "cmTarget.h" #include "cmake.h" #include +#include +#include +#include +#include +#include +#include /* diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index 4a33aff..7cd4140 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -12,17 +12,22 @@ #ifndef cmComputeLinkDepends_h #define cmComputeLinkDepends_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include "cmGraphAdjacencyList.h" #include "cmLinkItem.h" +#include "cmTargetLinkLibraryType.h" +#include #include +#include +#include +#include class cmComputeComponentGraph; +class cmGeneratorTarget; class cmGlobalGenerator; class cmMakefile; -class cmGeneratorTarget; class cmake; /** \class cmComputeLinkDepends diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 7db5df3..96c36f1 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -11,19 +11,25 @@ ============================================================================*/ #include "cmComputeLinkInformation.h" -#include "cmComputeLinkDepends.h" -#include "cmOrderDirectories.h" - #include "cmAlgorithms.h" +#include "cmComputeLinkDepends.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmOrderDirectories.h" #include "cmOutputConverter.h" +#include "cmPolicies.h" #include "cmState.h" +#include "cmSystemTools.h" +#include "cmTarget.h" #include "cmake.h" #include +#include +#include +#include +#include //#define CM_COMPUTE_LINK_INFO_DEBUG diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 023c781..7a67567 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -12,15 +12,19 @@ #ifndef cmComputeLinkInformation_h #define cmComputeLinkInformation_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include +#include +#include +#include +#include -class cmake; +class cmGeneratorTarget; class cmGlobalGenerator; class cmMakefile; -class cmGeneratorTarget; class cmOrderDirectories; +class cmake; /** \class cmComputeLinkInformation * \brief Compute link information for a target in one configuration. diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index ff7eb0b..8b89e33 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -12,18 +12,25 @@ #include "cmComputeTargetDepends.h" #include "cmComputeComponentGraph.h" +#include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmLinkItem.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmPolicies.h" #include "cmSourceFile.h" #include "cmState.h" #include "cmSystemTools.h" #include "cmTarget.h" +#include "cmTargetDepend.h" #include "cmake.h" -#include - #include +#include +#include +#include + +class cmListFileBacktrace; /* diff --git a/Source/cmComputeTargetDepends.h b/Source/cmComputeTargetDepends.h index 9e51d4d..587ac66 100644 --- a/Source/cmComputeTargetDepends.h +++ b/Source/cmComputeTargetDepends.h @@ -12,16 +12,19 @@ #ifndef cmComputeTargetDepends_h #define cmComputeTargetDepends_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include "cmGraphAdjacencyList.h" -#include +#include +#include +#include +#include class cmComputeComponentGraph; +class cmGeneratorTarget; class cmGlobalGenerator; class cmLinkItem; -class cmGeneratorTarget; class cmTargetDependSet; /** \class cmComputeTargetDepends https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=373b2e483d983136415190dcc838e636077e5991 commit 373b2e483d983136415190dcc838e636077e5991 Author: Daniel Pfeifer AuthorDate: Wed Aug 17 23:52:34 2016 +0200 Commit: Daniel Pfeifer CommitDate: Wed Aug 17 23:52:34 2016 +0200 cmArchiveWrite: replace mode_t with int Rationale: * mode_t is not defined on all platforms * bitmasking (operator &) promotes the value to an int anyway * libarchive uses int in the public api starting with version 4 diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx index 3da4f28..56da2ac 100644 --- a/Source/cmArchiveWrite.cxx +++ b/Source/cmArchiveWrite.cxx @@ -268,7 +268,7 @@ bool cmArchiveWrite::AddFile(const char* file, size_t skip, const char* prefix) } if (this->PermissionsMask.IsSet()) { - mode_t perm = archive_entry_perm(e); + int perm = archive_entry_perm(e); archive_entry_set_perm(e, perm & this->PermissionsMask.Get()); } diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h index f847d09..b15c15a 100644 --- a/Source/cmArchiveWrite.h +++ b/Source/cmArchiveWrite.h @@ -94,7 +94,7 @@ public: void SetMTime(std::string const& t) { this->MTime = t; } //! Sets the permissions of the added files/folders - void SetPermissions(mode_t permissions_) + void SetPermissions(int permissions_) { this->Permissions.Set(permissions_); } @@ -107,7 +107,7 @@ public: //! The permissions will be copied from the existing file //! or folder. The mask will then be applied to unset //! some of them - void SetPermissionsMask(mode_t permissionsMask_) + void SetPermissionsMask(int permissionsMask_) { this->PermissionsMask.Set(permissionsMask_); } @@ -177,8 +177,8 @@ private: //!@} //! Permissions on files/folders - cmArchiveWriteOptional Permissions; - cmArchiveWriteOptional PermissionsMask; + cmArchiveWriteOptional Permissions; + cmArchiveWriteOptional PermissionsMask; }; #endif ----------------------------------------------------------------------- Summary of changes: Source/cmArchiveWrite.cxx | 6 +++++- Source/cmArchiveWrite.h | 14 +++++++++----- Source/cmCLocaleEnvironmentScope.cxx | 1 + Source/cmCLocaleEnvironmentScope.h | 5 ++++- Source/cmCPackPropertiesGenerator.cxx | 7 ++++++- Source/cmCPackPropertiesGenerator.h | 8 +++++++- Source/cmCacheManager.cxx | 6 ++++-- Source/cmCacheManager.h | 10 ++++++++-- Source/cmCommands.h | 2 +- Source/cmCommonTargetGenerator.cxx | 10 +++++++++- Source/cmCommonTargetGenerator.h | 8 ++++++-- Source/cmComputeComponentGraph.h | 3 ++- Source/cmComputeLinkDepends.cxx | 9 +++++++++ Source/cmComputeLinkDepends.h | 9 +++++++-- Source/cmComputeLinkInformation.cxx | 12 +++++++++--- Source/cmComputeLinkInformation.h | 10 +++++++--- Source/cmComputeTargetDepends.cxx | 11 +++++++++-- Source/cmComputeTargetDepends.h | 9 ++++++--- 18 files changed, 109 insertions(+), 31 deletions(-) hooks/post-receive -- CMake From daniel at pfeifer-mail.de Wed Aug 17 18:32:08 2016 From: daniel at pfeifer-mail.de (Daniel Pfeifer) Date: Wed, 17 Aug 2016 18:32:08 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1302-g1cca31b Message-ID: <20160817223208.A152DF55B1@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 1cca31b2f5b2ac7ba21711fbe612b37d1ecc6b6c (commit) via ccb9a992dc78d04112075f4667792c89239b74d1 (commit) from 951bc07441bdf29dde92ff7e0a58ec5b21a847f5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1cca31b2f5b2ac7ba21711fbe612b37d1ecc6b6c commit 1cca31b2f5b2ac7ba21711fbe612b37d1ecc6b6c Merge: 951bc07 ccb9a99 Author: Daniel Pfeifer AuthorDate: Wed Aug 17 18:32:07 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 17 18:32:07 2016 -0400 Merge topic 'include-what-you-use' into next ccb9a992 fixup! fix a batch of include-what-you-use violations https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ccb9a992dc78d04112075f4667792c89239b74d1 commit ccb9a992dc78d04112075f4667792c89239b74d1 Author: Daniel Pfeifer AuthorDate: Thu Aug 18 00:31:49 2016 +0200 Commit: Daniel Pfeifer CommitDate: Thu Aug 18 00:31:49 2016 +0200 fixup! fix a batch of include-what-you-use violations diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx index fa5a08e..0504f70 100644 --- a/Source/cmArchiveWrite.cxx +++ b/Source/cmArchiveWrite.cxx @@ -18,9 +18,9 @@ #include #include #include +#include #include #include -#include #ifndef __LA_SSIZE_T #define __LA_SSIZE_T la_ssize_t diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h index c859453..120453b 100644 --- a/Source/cmArchiveWrite.h +++ b/Source/cmArchiveWrite.h @@ -14,8 +14,8 @@ #include // IWYU pragma: keep -#include #include +#include #include #if !defined(CMAKE_BUILD_WITH_CMAKE) diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index 386c39a..5b76162 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -16,12 +16,12 @@ #include "cmVersion.h" #include "cmake.h" +#include #include #include +#include #include #include -#include -#include cmCacheManager::cmCacheManager() { diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index f65e2fb..6167e2c 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -11,8 +11,8 @@ ============================================================================*/ #include "cmCommonTargetGenerator.h" -#include #include +#include #include #include #include diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 644f4a9..98405cf 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -22,12 +22,12 @@ #include "cmTarget.h" #include "cmake.h" -#include -#include -#include #include +#include #include #include +#include +#include #include /* diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 96c36f1..82877f3 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -25,10 +25,10 @@ #include "cmTarget.h" #include "cmake.h" -#include -#include #include +#include #include +#include #include //#define CM_COMPUTE_LINK_INFO_DEBUG diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index 8b89e33..dd07300 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -26,8 +26,8 @@ #include "cmake.h" #include -#include #include +#include #include class cmListFileBacktrace; ----------------------------------------------------------------------- Summary of changes: Source/cmArchiveWrite.cxx | 2 +- Source/cmArchiveWrite.h | 2 +- Source/cmCacheManager.cxx | 4 ++-- Source/cmCommonTargetGenerator.cxx | 2 +- Source/cmComputeLinkDepends.cxx | 6 +++--- Source/cmComputeLinkInformation.cxx | 4 ++-- Source/cmComputeTargetDepends.cxx | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) hooks/post-receive -- CMake From kwrobot at kitware.com Thu Aug 18 00:01:07 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Thu, 18 Aug 2016 00:01:07 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-650-g11e0cea Message-ID: <20160818040107.D87FBF5444@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 11e0ceaeab905075d93e279b87470b99c6401929 (commit) from 67a7dcef45fef6172514d6df1bea3ca94a04735a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=11e0ceaeab905075d93e279b87470b99c6401929 commit 11e0ceaeab905075d93e279b87470b99c6401929 Author: Kitware Robot AuthorDate: Thu Aug 18 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Thu Aug 18 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index ac1ae03..ca31b76 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160817) +set(CMake_VERSION_PATCH 20160818) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 18 08:49:29 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 18 Aug 2016 08:49:29 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1304-g3932f9c Message-ID: <20160818124929.DB615F4635@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 3932f9cf5e3ffad641988e6f36abd69c02667fe7 (commit) via cca431403460e5d23b38ad528812dadd03e8c82c (commit) from 1cca31b2f5b2ac7ba21711fbe612b37d1ecc6b6c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3932f9cf5e3ffad641988e6f36abd69c02667fe7 commit 3932f9cf5e3ffad641988e6f36abd69c02667fe7 Merge: 1cca31b cca4314 Author: Brad King AuthorDate: Thu Aug 18 08:49:28 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 18 08:49:28 2016 -0400 Merge topic 'msvc-suppress-rc-logo' into next cca43140 Revert "MSVC: Suppress rc.exe logo/banner when CMAKE_VERBOSE_MAKEFILE is false" https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cca431403460e5d23b38ad528812dadd03e8c82c commit cca431403460e5d23b38ad528812dadd03e8c82c Author: Brad King AuthorDate: Thu Aug 18 08:49:03 2016 -0400 Commit: Brad King CommitDate: Thu Aug 18 08:49:03 2016 -0400 Revert "MSVC: Suppress rc.exe logo/banner when CMAKE_VERBOSE_MAKEFILE is false" This reverts commit 08f570b7fb76c1895663ae8665d2494c988069b4. diff --git a/Modules/CMakeRCInformation.cmake b/Modules/CMakeRCInformation.cmake index 8e320da..60276e2 100644 --- a/Modules/CMakeRCInformation.cmake +++ b/Modules/CMakeRCInformation.cmake @@ -44,7 +44,7 @@ set(CMAKE_INCLUDE_FLAG_RC "-I") # compile a Resource file into an object file if(NOT CMAKE_RC_COMPILE_OBJECT) set(CMAKE_RC_COMPILE_OBJECT - " ${CMAKE_CL_NOLOGO} /fo ") + " /fo ") endif() mark_as_advanced( ----------------------------------------------------------------------- Summary of changes: Modules/CMakeRCInformation.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From daniel at pfeifer-mail.de Thu Aug 18 14:37:14 2016 From: daniel at pfeifer-mail.de (Daniel Pfeifer) Date: Thu, 18 Aug 2016 14:37:14 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1310-gcdf7e58 Message-ID: <20160818183714.F2F49F5552@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via cdf7e5800504307b820f742fc3944391d6e37292 (commit) via 7b6349da4dc968691f1a374211fcc153c8b4f1c6 (commit) via 50ad1e0a144ae1f2267a4966789e5a16372f458e (commit) via 7f97a6c94b59be7e7eba7362ce3eecdcff79ab70 (commit) via 4988b914e1fb7ca215436738ab08ed199a6f63d2 (commit) via 11e0ceaeab905075d93e279b87470b99c6401929 (commit) from 3932f9cf5e3ffad641988e6f36abd69c02667fe7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cdf7e5800504307b820f742fc3944391d6e37292 commit cdf7e5800504307b820f742fc3944391d6e37292 Merge: 3932f9c 7b6349d Author: Daniel Pfeifer AuthorDate: Thu Aug 18 14:37:12 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 18 14:37:12 2016 -0400 Merge topic 'else-after-return' into next 7b6349da CMake: don't use else after return 50ad1e0a CTest: don't use else after return 7f97a6c9 CPack: don't use else after return 4988b914 CursesDialog: don't use else after return 11e0ceae CMake Nightly Date Stamp https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7b6349da4dc968691f1a374211fcc153c8b4f1c6 commit 7b6349da4dc968691f1a374211fcc153c8b4f1c6 Author: Daniel Pfeifer AuthorDate: Thu Aug 18 20:36:29 2016 +0200 Commit: Daniel Pfeifer CommitDate: Thu Aug 18 20:36:29 2016 +0200 CMake: don't use else after return diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx index 3da4f28..df07ccc 100644 --- a/Source/cmArchiveWrite.cxx +++ b/Source/cmArchiveWrite.cxx @@ -71,9 +71,8 @@ struct cmArchiveWrite::Callback if (self->Stream.write(static_cast(b), static_cast(n))) { return static_cast<__LA_SSIZE_T>(n); - } else { - return static_cast<__LA_SSIZE_T>(-1); } + return static_cast<__LA_SSIZE_T>(-1); } }; diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 8a856a8..b4ddc3e 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -781,13 +781,12 @@ bool cmCTest::SetTest(const char* ttype, bool report) if (p != PartCount) { this->Parts[p].Enable(); return true; - } else { - if (report) { - cmCTestLog(this, ERROR_MESSAGE, "Don't know about test \"" - << ttype << "\" yet..." << std::endl); - } - return false; } + if (report) { + cmCTestLog(this, ERROR_MESSAGE, "Don't know about test \"" + << ttype << "\" yet..." << std::endl); + } + return false; } void cmCTest::Finalize() diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index bdd7303..2571698 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -574,7 +574,8 @@ const char* cmCacheManager::CacheEntry::GetProperty( { if (prop == "TYPE") { return cmState::CacheEntryTypeToString(this->Type); - } else if (prop == "VALUE") { + } + if (prop == "VALUE") { return this->Value.c_str(); } return this->Properties.GetPropertyValue(prop); diff --git a/Source/cmCommandArgumentParserHelper.cxx b/Source/cmCommandArgumentParserHelper.cxx index 42fb105..68111a0 100644 --- a/Source/cmCommandArgumentParserHelper.cxx +++ b/Source/cmCommandArgumentParserHelper.cxx @@ -75,9 +75,8 @@ char* cmCommandArgumentParserHelper::ExpandSpecialVariable(const char* key, if (cmSystemTools::GetEnv(var, str)) { if (this->EscapeQuotes) { return this->AddString(cmSystemTools::EscapeQuotes(str.c_str())); - } else { - return this->AddString(str); } + return this->AddString(str); } return this->EmptyVariable; } @@ -86,9 +85,8 @@ char* cmCommandArgumentParserHelper::ExpandSpecialVariable(const char* key, this->Makefile->GetState()->GetInitializedCacheValue(var)) { if (this->EscapeQuotes) { return this->AddString(cmSystemTools::EscapeQuotes(c)); - } else { - return this->AddString(c); } + return this->AddString(c); } return this->EmptyVariable; } @@ -162,7 +160,8 @@ char* cmCommandArgumentParserHelper::CombineUnions(char* in1, char* in2) { if (!in1) { return in2; - } else if (!in2) { + } + if (!in2) { return in1; } size_t len = strlen(in1) + strlen(in2) + 1; @@ -282,10 +281,9 @@ int cmCommandArgumentParserHelper::LexInput(char* buf, int maxlen) this->CurrentLine++; } return (1); - } else { - buf[0] = '\n'; - return (0); } + buf[0] = '\n'; + return (0); } void cmCommandArgumentParserHelper::Error(const char* str) diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx index 9bd07a3..8e2d87e 100644 --- a/Source/cmCryptoHash.cxx +++ b/Source/cmCryptoHash.cxx @@ -19,19 +19,23 @@ CM_AUTO_PTR cmCryptoHash::New(const char* algo) { if (strcmp(algo, "MD5") == 0) { return CM_AUTO_PTR(new cmCryptoHashMD5); - } else if (strcmp(algo, "SHA1") == 0) { + } + if (strcmp(algo, "SHA1") == 0) { return CM_AUTO_PTR(new cmCryptoHashSHA1); - } else if (strcmp(algo, "SHA224") == 0) { + } + if (strcmp(algo, "SHA224") == 0) { return CM_AUTO_PTR(new cmCryptoHashSHA224); - } else if (strcmp(algo, "SHA256") == 0) { + } + if (strcmp(algo, "SHA256") == 0) { return CM_AUTO_PTR(new cmCryptoHashSHA256); - } else if (strcmp(algo, "SHA384") == 0) { + } + if (strcmp(algo, "SHA384") == 0) { return CM_AUTO_PTR(new cmCryptoHashSHA384); - } else if (strcmp(algo, "SHA512") == 0) { + } + if (strcmp(algo, "SHA512") == 0) { return CM_AUTO_PTR(new cmCryptoHashSHA512); - } else { - return CM_AUTO_PTR(CM_NULLPTR); } + return CM_AUTO_PTR(CM_NULLPTR); } bool cmCryptoHash::IntFromHexDigit(char input, char& output) @@ -39,10 +43,12 @@ bool cmCryptoHash::IntFromHexDigit(char input, char& output) if (input >= '0' && input <= '9') { output = char(input - '0'); return true; - } else if (input >= 'a' && input <= 'f') { + } + if (input >= 'a' && input <= 'f') { output = char(input - 'a' + 0xA); return true; - } else if (input >= 'A' && input <= 'F') { + } + if (input >= 'A' && input <= 'F') { output = char(input - 'A' + 0xA); return true; } diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index d1521f0..5c863f0 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -521,7 +521,8 @@ bool cmDependsFortran::CopyModule(const std::vector& args) } } return true; - } else if (cmSystemTools::FileExists(mod_lower.c_str(), true)) { + } + if (cmSystemTools::FileExists(mod_lower.c_str(), true)) { if (cmDependsFortran::ModulesDiffer(mod_lower.c_str(), stamp.c_str(), compilerId.c_str())) { if (!cmSystemTools::CopyFileAlways(mod_lower, stamp)) { diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx index 919a45e..5516cf1 100644 --- a/Source/cmDocumentation.cxx +++ b/Source/cmDocumentation.cxx @@ -719,9 +719,8 @@ const char* cmDocumentation::GetNameString() const { if (!this->NameString.empty()) { return this->NameString.c_str(); - } else { - return "CMake"; } + return "CMake"; } bool cmDocumentation::IsOption(const char* arg) const diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx index c687e2f..150593b 100644 --- a/Source/cmELF.cxx +++ b/Source/cmELF.cxx @@ -832,45 +832,40 @@ cmELF::FileType cmELF::GetFileType() const { if (this->Valid()) { return this->Internal->GetFileType(); - } else { - return FileTypeInvalid; } + return FileTypeInvalid; } unsigned int cmELF::GetNumberOfSections() const { if (this->Valid()) { return this->Internal->GetNumberOfSections(); - } else { - return 0; } + return 0; } unsigned int cmELF::GetDynamicEntryCount() const { if (this->Valid()) { return this->Internal->GetDynamicEntryCount(); - } else { - return 0; } + return 0; } unsigned long cmELF::GetDynamicEntryPosition(int index) const { if (this->Valid()) { return this->Internal->GetDynamicEntryPosition(index); - } else { - return 0; } + return 0; } bool cmELF::ReadBytes(unsigned long pos, unsigned long size, char* buf) const { if (this->Valid()) { return this->Internal->ReadBytes(pos, size, buf); - } else { - return false; } + return false; } bool cmELF::GetSOName(std::string& soname) @@ -878,9 +873,8 @@ bool cmELF::GetSOName(std::string& soname) if (StringEntry const* se = this->GetSOName()) { soname = se->Value; return true; - } else { - return false; } + return false; } cmELF::StringEntry const* cmELF::GetSOName() @@ -888,9 +882,8 @@ cmELF::StringEntry const* cmELF::GetSOName() if (this->Valid() && this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary) { return this->Internal->GetSOName(); - } else { - return CM_NULLPTR; } + return CM_NULLPTR; } cmELF::StringEntry const* cmELF::GetRPath() @@ -899,9 +892,8 @@ cmELF::StringEntry const* cmELF::GetRPath() (this->Internal->GetFileType() == cmELF::FileTypeExecutable || this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) { return this->Internal->GetRPath(); - } else { - return CM_NULLPTR; } + return CM_NULLPTR; } cmELF::StringEntry const* cmELF::GetRunPath() @@ -910,9 +902,8 @@ cmELF::StringEntry const* cmELF::GetRunPath() (this->Internal->GetFileType() == cmELF::FileTypeExecutable || this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) { return this->Internal->GetRunPath(); - } else { - return CM_NULLPTR; } + return CM_NULLPTR; } void cmELF::PrintInfo(std::ostream& os) const diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index a53d285..390477a 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -211,11 +211,10 @@ void cmExportBuildFileGenerator::HandleMissingTarget( link_libs += missingTarget; missingTargets.push_back(missingTarget); return; - } else { - // We are not appending, so all exported targets should be - // known here. This is probably user-error. - this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences); } + // We are not appending, so all exported targets should be + // known here. This is probably user-error. + this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences); } // Assume the target will be exported by another command. // Append it with the export namespace. diff --git a/Source/cmExprParserHelper.cxx b/Source/cmExprParserHelper.cxx index 0771a4e..1a101ab 100644 --- a/Source/cmExprParserHelper.cxx +++ b/Source/cmExprParserHelper.cxx @@ -81,10 +81,9 @@ int cmExprParserHelper::LexInput(char* buf, int maxlen) this->CurrentLine++; } return (1); - } else { - buf[0] = '\n'; - return (0); } + buf[0] = '\n'; + return (0); } void cmExprParserHelper::Error(const char* str) diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index 0ded17a..559974e 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -124,11 +124,10 @@ void Tree::InsertPath(const std::vector& splitted, if (start + 1 < splitted.size()) { it->InsertPath(splitted, start + 1, fileName); return; - } else { - // last part of splitted - it->files.push_back(fileName); - return; } + // last part of splitted + it->files.push_back(fileName); + return; } } // Not found in folders, thus insert @@ -138,12 +137,11 @@ void Tree::InsertPath(const std::vector& splitted, newFolder.InsertPath(splitted, start + 1, fileName); folders.push_back(newFolder); return; - } else { - // last part of splitted - newFolder.files.push_back(fileName); - folders.push_back(newFolder); - return; } + // last part of splitted + newFolder.files.push_back(fileName); + folders.push_back(newFolder); + return; } void Tree::BuildVirtualFolder(cmXMLWriter& xml) const @@ -717,21 +715,22 @@ std::string cmExtraCodeBlocksGenerator::GetCBCompilerId(const cmMakefile* mf) // Translate the cmake target type into the CodeBlocks target type id int cmExtraCodeBlocksGenerator::GetCBTargetType(cmGeneratorTarget* target) { - if (target->GetType() == cmState::EXECUTABLE) { - if ((target->GetPropertyAsBool("WIN32_EXECUTABLE")) || - (target->GetPropertyAsBool("MACOSX_BUNDLE"))) { - return 0; - } else { + switch (target->GetType()) { + case cmState::EXECUTABLE: + if ((target->GetPropertyAsBool("WIN32_EXECUTABLE")) || + (target->GetPropertyAsBool("MACOSX_BUNDLE"))) { + return 0; + } return 1; - } - } else if ((target->GetType() == cmState::STATIC_LIBRARY) || - (target->GetType() == cmState::OBJECT_LIBRARY)) { - return 2; - } else if ((target->GetType() == cmState::SHARED_LIBRARY) || - (target->GetType() == cmState::MODULE_LIBRARY)) { - return 3; + case cmState::STATIC_LIBRARY: + case cmState::OBJECT_LIBRARY: + return 2; + case cmState::SHARED_LIBRARY: + case cmState::MODULE_LIBRARY: + return 3; + default: + return 4; } - return 4; } // Create the command line for building the given target using the selected diff --git a/Source/cmFileLockPool.cxx b/Source/cmFileLockPool.cxx index 7c51459..5521ac4 100644 --- a/Source/cmFileLockPool.cxx +++ b/Source/cmFileLockPool.cxx @@ -140,10 +140,9 @@ cmFileLockResult cmFileLockPool::ScopePool::Lock(const std::string& filename, if (result.IsOk()) { this->Locks.push_back(lock); return cmFileLockResult::MakeOk(); - } else { - delete lock; - return result; } + delete lock; + return result; } cmFileLockResult cmFileLockPool::ScopePool::Release( diff --git a/Source/cmFileTimeComparison.cxx b/Source/cmFileTimeComparison.cxx index 9d63505..1360b44 100644 --- a/Source/cmFileTimeComparison.cxx +++ b/Source/cmFileTimeComparison.cxx @@ -140,11 +140,14 @@ int cmFileTimeComparisonInternal::Compare(cmFileTimeComparison_Type* s1, // Compare using nanosecond resolution. if (s1->st_mtim.tv_sec < s2->st_mtim.tv_sec) { return -1; - } else if (s1->st_mtim.tv_sec > s2->st_mtim.tv_sec) { + } + if (s1->st_mtim.tv_sec > s2->st_mtim.tv_sec) { return 1; - } else if (s1->st_mtim.tv_nsec < s2->st_mtim.tv_nsec) { + } + if (s1->st_mtim.tv_nsec < s2->st_mtim.tv_nsec) { return -1; - } else if (s1->st_mtim.tv_nsec > s2->st_mtim.tv_nsec) { + } + if (s1->st_mtim.tv_nsec > s2->st_mtim.tv_nsec) { return 1; } #elif CMake_STAT_HAS_ST_MTIMESPEC @@ -185,11 +188,11 @@ bool cmFileTimeComparisonInternal::TimesDiffer(cmFileTimeComparison_Type* s1, long long t2 = s2->st_mtim.tv_sec * bil + s2->st_mtim.tv_nsec; if (t1 < t2) { return (t2 - t1) >= bil; - } else if (t2 < t1) { + } + if (t2 < t1) { return (t1 - t2) >= bil; - } else { - return false; } + return false; #elif CMake_STAT_HAS_ST_MTIMESPEC // Times are integers in units of 1ns. long long bil = 1000000000; @@ -240,11 +243,10 @@ bool cmFileTimeComparisonInternal::FileTimeCompare(const char* f1, // Compare the two modification times. *result = this->Compare(&s1, &s2); return true; - } else { - // No comparison available. Default to the same time. - *result = 0; - return false; } + // No comparison available. Default to the same time. + *result = 0; + return false; } bool cmFileTimeComparisonInternal::FileTimesDiffer(const char* f1, @@ -256,8 +258,7 @@ bool cmFileTimeComparisonInternal::FileTimesDiffer(const char* f1, if (this->Stat(f1, &s1) && this->Stat(f2, &s2)) { // Compare the two modification times. return this->TimesDiffer(&s1, &s2); - } else { - // No comparison available. Default to different times. - return true; } + // No comparison available. Default to different times. + return true; } diff --git a/Source/cmFortranParserImpl.cxx b/Source/cmFortranParserImpl.cxx index 7d04898..30a33b4 100644 --- a/Source/cmFortranParserImpl.cxx +++ b/Source/cmFortranParserImpl.cxx @@ -22,29 +22,27 @@ bool cmFortranParser_s::FindIncludeFile(const char* dir, if (cmSystemTools::FileIsFullPath(includeName)) { fileName = includeName; return cmSystemTools::FileExists(fileName.c_str(), true); - } else { - // Check for the file in the directory containing the including - // file. - std::string fullName = dir; + } + // Check for the file in the directory containing the including + // file. + std::string fullName = dir; + fullName += "/"; + fullName += includeName; + if (cmSystemTools::FileExists(fullName.c_str(), true)) { + fileName = fullName; + return true; + } + + // Search the include path for the file. + for (std::vector::const_iterator i = this->IncludePath.begin(); + i != this->IncludePath.end(); ++i) { + fullName = *i; fullName += "/"; fullName += includeName; if (cmSystemTools::FileExists(fullName.c_str(), true)) { fileName = fullName; return true; } - - // Search the include path for the file. - for (std::vector::const_iterator i = - this->IncludePath.begin(); - i != this->IncludePath.end(); ++i) { - fullName = *i; - fullName += "/"; - fullName += includeName; - if (cmSystemTools::FileExists(fullName.c_str(), true)) { - fileName = fullName; - return true; - } - } } return false; } @@ -88,9 +86,8 @@ bool cmFortranParser_FilePush(cmFortranParser* parser, const char* fname) cmFortran_yy_switch_to_buffer(buffer, parser->Scanner); parser->FileStack.push(f); return 1; - } else { - return 0; } + return 0; } bool cmFortranParser_FilePop(cmFortranParser* parser) @@ -99,15 +96,14 @@ bool cmFortranParser_FilePop(cmFortranParser* parser) // to the next one on the stack. if (parser->FileStack.empty()) { return 0; - } else { - cmFortranFile f = parser->FileStack.top(); - parser->FileStack.pop(); - fclose(f.File); - YY_BUFFER_STATE current = cmFortranLexer_GetCurrentBuffer(parser->Scanner); - cmFortran_yy_delete_buffer(current, parser->Scanner); - cmFortran_yy_switch_to_buffer(f.Buffer, parser->Scanner); - return 1; } + cmFortranFile f = parser->FileStack.top(); + parser->FileStack.pop(); + fclose(f.File); + YY_BUFFER_STATE current = cmFortranLexer_GetCurrentBuffer(parser->Scanner); + cmFortran_yy_delete_buffer(current, parser->Scanner); + cmFortran_yy_switch_to_buffer(f.Buffer, parser->Scanner); + return 1; } int cmFortranParser_Input(cmFortranParser* parser, char* buffer, diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 983bfb4..6cd6439 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -352,7 +352,8 @@ std::string cmGeneratorExpression::Preprocess(const std::string& input, { if (context == StripAllGeneratorExpressions) { return stripAllGeneratorExpressions(input); - } else if (context == BuildInterface || context == InstallInterface) { + } + if (context == BuildInterface || context == InstallInterface) { return stripExportInterface(input, context, resolveRelative); } diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 66437eb..b4b74c5 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -154,20 +154,19 @@ std::string GeneratorExpressionContent::EvaluateParameters( node, identifier, context, dagChecker, pit); parameters.push_back(lastParam); return std::string(); - } else { - std::string parameter; - std::vector::const_iterator it = - pit->begin(); - const std::vector::const_iterator - end = pit->end(); - for (; it != end; ++it) { - parameter += (*it)->Evaluate(context, dagChecker); - if (context->HadError) { - return std::string(); - } + } + std::string parameter; + std::vector::const_iterator it = + pit->begin(); + const std::vector::const_iterator end = + pit->end(); + for (; it != end; ++it) { + parameter += (*it)->Evaluate(context, dagChecker); + if (context->HadError) { + return std::string(); } - parameters.push_back(parameter); } + parameters.push_back(parameter); } } diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 86fbd44..12cf980 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -92,7 +92,8 @@ static const struct ZeroNode installInterfaceNode; for (; it != end; ++it) { \ if (*it == #FAILURE_VALUE) { \ return #FAILURE_VALUE; \ - } else if (*it != #SUCCESS_VALUE) { \ + } \ + if (*it != #SUCCESS_VALUE) { \ reportError(context, content->GetOriginalExpression(), \ "Parameters to $<" #OP \ "> must resolve to either '0' or '1'."); \ @@ -790,7 +791,8 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode "$ may not be used with Visual Studio " "generators."); return std::string(); - } else if (genName.find("Xcode") != std::string::npos) { + } + if (genName.find("Xcode") != std::string::npos) { if (dagChecker && (dagChecker->EvaluatingCompileDefinitions() || dagChecker->EvaluatingIncludeDirectories())) { reportError( diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 308051b..8bd3b82 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -361,10 +361,9 @@ const char* cmGeneratorTarget::GetOutputTargetType(bool implib) const if (implib) { // A DLL import library is treated as an archive target. return "ARCHIVE"; - } else { - // A DLL shared library is treated as a runtime target. - return "RUNTIME"; } + // A DLL shared library is treated as a runtime target. + return "RUNTIME"; } else { // For non-DLL platforms shared libraries are treated as // library targets. @@ -1324,26 +1323,23 @@ std::string cmGeneratorTarget::GetSOName(const std::string& config) const // The imported library has no builtin soname so the name // searched at runtime will be just the filename. return cmSystemTools::GetFilenameName(info->Location); - } else { - // Use the soname given if any. - if (info->SOName.find("@rpath/") == 0) { - return info->SOName.substr(6); - } - return info->SOName; } - } else { - return ""; + // Use the soname given if any. + if (info->SOName.find("@rpath/") == 0) { + return info->SOName.substr(6); + } + return info->SOName; } - } else { - // Compute the soname that will be built. - std::string name; - std::string soName; - std::string realName; - std::string impName; - std::string pdbName; - this->GetLibraryNames(name, soName, realName, impName, pdbName, config); - return soName; + return ""; } + // Compute the soname that will be built. + std::string name; + std::string soName; + std::string realName; + std::string impName; + std::string pdbName; + this->GetLibraryNames(name, soName, realName, impName, pdbName, config); + return soName; } std::string cmGeneratorTarget::GetAppBundleDirectory(const std::string& config, @@ -1418,9 +1414,8 @@ std::string cmGeneratorTarget::GetFullName(const std::string& config, { if (this->IsImported()) { return this->GetFullNameImported(config, implib); - } else { - return this->GetFullNameInternal(config, implib); } + return this->GetFullNameInternal(config, implib); } std::string cmGeneratorTarget::GetInstallNameDirForBuildTree( @@ -1444,9 +1439,8 @@ std::string cmGeneratorTarget::GetInstallNameDirForBuildTree( } dir += "/"; return dir; - } else { - return ""; } + return ""; } std::string cmGeneratorTarget::GetInstallNameDirForInstallTree() const @@ -1468,9 +1462,8 @@ std::string cmGeneratorTarget::GetInstallNameDirForInstallTree() const } } return dir; - } else { - return ""; } + return ""; } cmListFileBacktrace cmGeneratorTarget::GetBacktrace() const @@ -1516,9 +1509,8 @@ const char* cmGeneratorTarget::GetExportMacro() const this->ExportMacro = cmSystemTools::MakeCidentifier(in); } return this->ExportMacro.c_str(); - } else { - return CM_NULLPTR; } + return CM_NULLPTR; } class cmTargetCollectLinkLanguages @@ -1642,7 +1634,8 @@ public: { if (this->Preferred.empty()) { return ""; - } else if (this->Preferred.size() > 1) { + } + if (this->Preferred.size() > 1) { std::ostringstream e; e << "Target " << this->Target->GetName() << " contains multiple languages with the highest linker preference" @@ -2723,9 +2716,8 @@ std::string cmGeneratorTarget::GetFullPath(const std::string& config, { if (this->IsImported()) { return this->Target->ImportedGetFullPath(config, implib); - } else { - return this->NormalGetFullPath(config, implib, realname); } + return this->NormalGetFullPath(config, implib, realname); } std::string cmGeneratorTarget::NormalGetFullPath(const std::string& config, @@ -2770,16 +2762,15 @@ std::string cmGeneratorTarget::NormalGetRealName( std::string pdbName; this->GetExecutableNames(name, realName, impName, pdbName, config); return realName; - } else { - // Compute the real name that will be built. - std::string name; - std::string soName; - std::string realName; - std::string impName; - std::string pdbName; - this->GetLibraryNames(name, soName, realName, impName, pdbName, config); - return realName; } + // Compute the real name that will be built. + std::string name; + std::string soName; + std::string realName; + std::string impName; + std::string pdbName; + this->GetLibraryNames(name, soName, realName, impName, pdbName, config); + return realName; } void cmGeneratorTarget::GetLibraryNames(std::string& name, std::string& soName, @@ -3587,9 +3578,8 @@ std::pair consistentNumberProperty(const char* lhs, if (t == NumberMaxType) { return std::make_pair(true, std::max(lnum, rnum) == lnum ? lhs : rhs); - } else { - return std::make_pair(true, std::min(lnum, rnum) == lnum ? lhs : rhs); } + return std::make_pair(true, std::min(lnum, rnum) == lnum ? lhs : rhs); } template <> @@ -3906,11 +3896,11 @@ std::string cmGeneratorTarget::GetFrameworkVersion() const if (const char* fversion = this->GetProperty("FRAMEWORK_VERSION")) { return fversion; - } else if (const char* tversion = this->GetProperty("VERSION")) { + } + if (const char* tversion = this->GetProperty("VERSION")) { return tversion; - } else { - return "A"; } + return "A"; } void cmGeneratorTarget::ComputeVersionedName(std::string& vName, @@ -4169,7 +4159,8 @@ std::string cmGeneratorTarget::GetDirectory(const std::string& config, // Return the directory from which the target is imported. return cmSystemTools::GetFilenamePath( this->Target->ImportedGetFullPath(config, implib)); - } else if (OutputInfo const* info = this->GetOutputInfo(config)) { + } + if (OutputInfo const* info = this->GetOutputInfo(config)) { // Return the directory in which the target will be built. return implib ? info->ImpDir : info->OutDir; } diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 3b8aaa6..2b83479 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -93,12 +93,11 @@ std::string cmGlobalNinjaGenerator::EncodeIdent(const std::string& ident, names << "ident" << VarNum++; vars << names.str() << " = " << ident << "\n"; return "$" + names.str(); - } else { - std::string result = ident; - cmSystemTools::ReplaceString(result, " ", "$ "); - cmSystemTools::ReplaceString(result, ":", "$:"); - return result; } + std::string result = ident; + cmSystemTools::ReplaceString(result, " ", "$ "); + cmSystemTools::ReplaceString(result, ":", "$:"); + return result; } std::string cmGlobalNinjaGenerator::EncodeLiteral(const std::string& lit) diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index 0fcd8ba..72c4d1f 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -63,9 +63,8 @@ void cmInstallExportGenerator::ComputeTempDir() this->TempDir += "/Export"; if (this->Destination.empty()) { return; - } else { - this->TempDir += "/"; } + this->TempDir += "/"; // Enforce a maximum length. bool useMD5 = false; diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 28b3781..1967d2a 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -259,10 +259,9 @@ bool cmListFileParser::AddArgument(cmListFileLexer_Token* token, if (isError) { this->Makefile->IssueMessage(cmake::FATAL_ERROR, m.str()); return false; - } else { - this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, m.str()); - return true; } + this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, m.str()); + return true; } struct cmListFileBacktrace::Entry : public cmListFileContext @@ -377,10 +376,9 @@ cmListFileContext const& cmListFileBacktrace::Top() const { if (this->Cur) { return *this->Cur; - } else { - static cmListFileContext const empty; - return empty; } + static cmListFileContext const empty; + return empty; } void cmListFileBacktrace::PrintTitle(std::ostream& out) const diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index accce49..d8f6bdf 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -626,16 +626,14 @@ std::string cmLocalGenerator::ExpandRuleVariable( if (variable == "TARGET_VERSION_MAJOR") { if (replaceValues.TargetVersionMajor) { return replaceValues.TargetVersionMajor; - } else { - return "0"; } + return "0"; } if (variable == "TARGET_VERSION_MINOR") { if (replaceValues.TargetVersionMinor) { return replaceValues.TargetVersionMinor; - } else { - return "0"; } + return "0"; } if (replaceValues.Target) { if (variable == "TARGET_BASE") { @@ -644,9 +642,8 @@ std::string cmLocalGenerator::ExpandRuleVariable( std::string::size_type pos = targetBase.rfind('.'); if (pos != targetBase.npos) { return targetBase.substr(0, pos); - } else { - return targetBase; } + return targetBase; } } } @@ -813,9 +810,8 @@ const char* cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target, { if (target) { return target->GetProperty(prop); - } else { - return this->Makefile->GetProperty(prop); } + return this->Makefile->GetProperty(prop); } void cmLocalGenerator::InsertRuleLauncher(std::string& s, @@ -2365,10 +2361,9 @@ static bool cmLocalGeneratorShortenObjectName(std::string& objName, // The object name is now short enough. return true; - } else { - // The object name could not be shortened enough. - return false; } + // The object name could not be shortened enough. + return false; } bool cmLocalGeneratorCheckObjectName(std::string& objName, @@ -2382,15 +2377,13 @@ bool cmLocalGeneratorCheckObjectName(std::string& objName, if (objName.size() > max_obj_len) { // The current object file name is too long. Try to shorten it. return cmLocalGeneratorShortenObjectName(objName, max_obj_len); - } else { - // The object file name is short enough. - return true; } - } else { - // The build directory in which the object will be stored is - // already too deep. - return false; + // The object file name is short enough. + return true; } + // The build directory in which the object will be stored is + // already too deep. + return false; } #endif diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index ab7de57..28a3ab5 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -813,11 +813,10 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput( // The existing custom command is identical. Silently ignore // the duplicate. return file; - } else { - // The existing custom command is different. We need to - // generate a rule file for this new command. - file = CM_NULLPTR; } + // The existing custom command is different. We need to + // generate a rule file for this new command. + file = CM_NULLPTR; } else if (!file) { file = this->CreateSource(main_dependency); } @@ -2029,7 +2028,8 @@ void cmMakefile::AddSourceGroup(const std::vector& name, sg->SetGroupRegex(regex); } return; - } else if (i == -1) { + } + if (i == -1) { // group does not exist nor belong to any existing group // add its first component this->SourceGroups.push_back(cmSourceGroup(name[0].c_str(), regex)); @@ -2817,13 +2817,12 @@ std::string cmMakefile::GetConfigurations(std::vector& configs, cmSystemTools::ExpandListArgument(configTypes, configs); } return ""; - } else { - const std::string& buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE"); - if (singleConfig && !buildType.empty()) { - configs.push_back(buildType); - } - return buildType; } + const std::string& buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE"); + if (singleConfig && !buildType.empty()) { + configs.push_back(buildType); + } + return buildType; } #if defined(CMAKE_BUILD_WITH_CMAKE) @@ -3129,9 +3128,8 @@ cmSourceFile* cmMakefile::GetOrCreateSource(const std::string& sourceName, { if (cmSourceFile* esf = this->GetSource(sourceName)) { return esf; - } else { - return this->CreateSource(sourceName, generated); } + return this->CreateSource(sourceName, generated); } void cmMakefile::EnableLanguage(std::vector const& lang, @@ -3756,69 +3754,67 @@ bool cmMakefile::EnforceUniqueName(std::string const& name, std::string& msg, << "\" because an imported target with the same name already exists."; msg = e.str(); return false; - } else { - // target names must be globally unique - switch (this->GetPolicyStatus(cmPolicies::CMP0002)) { - case cmPolicies::WARN: - this->IssueMessage( - cmake::AUTHOR_WARNING, - cmPolicies::GetPolicyWarning(cmPolicies::CMP0002)); - case cmPolicies::OLD: - return true; - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::REQUIRED_ALWAYS: - this->IssueMessage( - cmake::FATAL_ERROR, - cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0002)); - return true; - case cmPolicies::NEW: - break; - } - - // The conflict is with a non-imported target. - // Allow this if the user has requested support. - cmake* cm = this->GetCMakeInstance(); - if (isCustom && existing->GetType() == cmState::UTILITY && - this != existing->GetMakefile() && - cm->GetState()->GetGlobalPropertyAsBool( - "ALLOW_DUPLICATE_CUSTOM_TARGETS")) { + } + // target names must be globally unique + switch (this->GetPolicyStatus(cmPolicies::CMP0002)) { + case cmPolicies::WARN: + this->IssueMessage(cmake::AUTHOR_WARNING, + cmPolicies::GetPolicyWarning(cmPolicies::CMP0002)); + case cmPolicies::OLD: return true; - } + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + this->IssueMessage( + cmake::FATAL_ERROR, + cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0002)); + return true; + case cmPolicies::NEW: + break; + } - // Produce an error that tells the user how to work around the - // problem. - std::ostringstream e; - e << "cannot create target \"" << name - << "\" because another target with the same name already exists. " - << "The existing target is "; - switch (existing->GetType()) { - case cmState::EXECUTABLE: - e << "an executable "; - break; - case cmState::STATIC_LIBRARY: - e << "a static library "; - break; - case cmState::SHARED_LIBRARY: - e << "a shared library "; - break; - case cmState::MODULE_LIBRARY: - e << "a module library "; - break; - case cmState::UTILITY: - e << "a custom target "; - break; - case cmState::INTERFACE_LIBRARY: - e << "an interface library "; - break; - default: - break; - } - e << "created in source directory \"" - << existing->GetMakefile()->GetCurrentSourceDirectory() << "\". " - << "See documentation for policy CMP0002 for more details."; - msg = e.str(); - return false; + // The conflict is with a non-imported target. + // Allow this if the user has requested support. + cmake* cm = this->GetCMakeInstance(); + if (isCustom && existing->GetType() == cmState::UTILITY && + this != existing->GetMakefile() && + cm->GetState()->GetGlobalPropertyAsBool( + "ALLOW_DUPLICATE_CUSTOM_TARGETS")) { + return true; + } + + // Produce an error that tells the user how to work around the + // problem. + std::ostringstream e; + e << "cannot create target \"" << name + << "\" because another target with the same name already exists. " + << "The existing target is "; + switch (existing->GetType()) { + case cmState::EXECUTABLE: + e << "an executable "; + break; + case cmState::STATIC_LIBRARY: + e << "a static library "; + break; + case cmState::SHARED_LIBRARY: + e << "a shared library "; + break; + case cmState::MODULE_LIBRARY: + e << "a module library "; + break; + case cmState::UTILITY: + e << "a custom target "; + break; + case cmState::INTERFACE_LIBRARY: + e << "an interface library "; + break; + default: + break; } + e << "created in source directory \"" + << existing->GetMakefile()->GetCurrentSourceDirectory() << "\". " + << "See documentation for policy CMP0002 for more details."; + msg = e.str(); + return false; } return true; } @@ -4246,15 +4242,15 @@ bool cmMakefile::HaveCStandardAvailable(cmTarget const* target, existingCIt < std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS), cmStrCmp("11"))) { return false; - } else if (needC99 && existingCStandard && - existingCIt < std::find_if(cmArrayBegin(C_STANDARDS), - cmArrayEnd(C_STANDARDS), - cmStrCmp("99"))) { + } + if (needC99 && existingCStandard && + existingCIt < std::find_if(cmArrayBegin(C_STANDARDS), + cmArrayEnd(C_STANDARDS), cmStrCmp("99"))) { return false; - } else if (needC90 && existingCStandard && - existingCIt < std::find_if(cmArrayBegin(C_STANDARDS), - cmArrayEnd(C_STANDARDS), - cmStrCmp("90"))) { + } + if (needC90 && existingCStandard && + existingCIt < std::find_if(cmArrayBegin(C_STANDARDS), + cmArrayEnd(C_STANDARDS), cmStrCmp("90"))) { return false; } return true; @@ -4332,10 +4328,11 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, cmArrayEnd(CXX_STANDARDS), cmStrCmp("11"))) { return false; - } else if (needCxx98 && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), - cmStrCmp("98"))) { + } + if (needCxx98 && + existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), + cmArrayEnd(CXX_STANDARDS), + cmStrCmp("98"))) { return false; } return true; diff --git a/Source/cmNewLineStyle.cxx b/Source/cmNewLineStyle.cxx index c03f60d..d64993a 100644 --- a/Source/cmNewLineStyle.cxx +++ b/Source/cmNewLineStyle.cxx @@ -34,19 +34,18 @@ bool cmNewLineStyle::ReadFromArguments(const std::vector& args, if (eol == "LF" || eol == "UNIX") { NewLineStyle = LF; return true; - } else if (eol == "CRLF" || eol == "WIN32" || eol == "DOS") { + } + if (eol == "CRLF" || eol == "WIN32" || eol == "DOS") { NewLineStyle = CRLF; return true; - } else { - errorString = "NEWLINE_STYLE sets an unknown style, only LF, " - "CRLF, UNIX, DOS, and WIN32 are supported"; - return false; } - } else { - errorString = "NEWLINE_STYLE must set a style: " - "LF, CRLF, UNIX, DOS, or WIN32"; + errorString = "NEWLINE_STYLE sets an unknown style, only LF, " + "CRLF, UNIX, DOS, and WIN32 are supported"; return false; } + errorString = "NEWLINE_STYLE must set a style: " + "LF, CRLF, UNIX, DOS, or WIN32"; + return false; } } return true; diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index 28bd992..f1da4d5 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -347,7 +347,8 @@ static std::string GetRccExecutable(cmGeneratorTarget const* target) return std::string(); } return qt5Rcc->ImportedGetLocation(""); - } else if (strcmp(qtVersion, "4") == 0) { + } + if (strcmp(qtVersion, "4") == 0) { cmGeneratorTarget* qt4Rcc = lg->FindGeneratorTargetToUse("Qt4::rcc"); if (!qt4Rcc) { cmSystemTools::Error("Qt4::rcc target not found ", targetName.c_str()); diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx index 04727b2..5869a01 100644 --- a/Source/cmSourceFile.cxx +++ b/Source/cmSourceFile.cxx @@ -295,9 +295,8 @@ const char* cmSourceFile::GetProperty(const std::string& prop) const if (prop == "LOCATION") { if (this->FullPath.empty()) { return CM_NULLPTR; - } else { - return this->FullPath.c_str(); } + return this->FullPath.c_str(); } const char* retVal = this->Properties.GetPropertyValue(prop); diff --git a/Source/cmState.cxx b/Source/cmState.cxx index d4eb90a..073c239 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -1702,7 +1702,8 @@ const char* cmState::Directory::GetProperty(const std::string& prop, return parent.GetDirectory().GetCurrentSource(); } return ""; - } else if (prop == "LISTFILE_STACK") { + } + if (prop == "LISTFILE_STACK") { std::vector listFiles; cmState::Snapshot snp = this->Snapshot_; while (snp.IsValid()) { @@ -1712,10 +1713,12 @@ const char* cmState::Directory::GetProperty(const std::string& prop, std::reverse(listFiles.begin(), listFiles.end()); output = cmJoin(listFiles, ";"); return output.c_str(); - } else if (prop == "CACHE_VARIABLES") { + } + if (prop == "CACHE_VARIABLES") { output = cmJoin(this->Snapshot_.State->GetCacheEntryKeys(), ";"); return output.c_str(); - } else if (prop == "VARIABLES") { + } + if (prop == "VARIABLES") { std::vector res = this->Snapshot_.ClosureKeys(); std::vector cacheKeys = this->Snapshot_.State->GetCacheEntryKeys(); @@ -1723,13 +1726,16 @@ const char* cmState::Directory::GetProperty(const std::string& prop, std::sort(res.begin(), res.end()); output = cmJoin(res, ";"); return output.c_str(); - } else if (prop == "INCLUDE_DIRECTORIES") { + } + if (prop == "INCLUDE_DIRECTORIES") { output = cmJoin(this->GetIncludeDirectoriesEntries(), ";"); return output.c_str(); - } else if (prop == "COMPILE_OPTIONS") { + } + if (prop == "COMPILE_OPTIONS") { output = cmJoin(this->GetCompileOptionsEntries(), ";"); return output.c_str(); - } else if (prop == "COMPILE_DEFINITIONS") { + } + if (prop == "COMPILE_DEFINITIONS") { output = cmJoin(this->GetCompileDefinitionsEntries(), ";"); return output.c_str(); } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index f19f0f6..21a50cb 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -333,9 +333,8 @@ void cmSystemTools::Message(const char* m1, const char* title) (*s_MessageCallback)(m1, title, s_DisableMessages, s_MessageCallbackClientData); return; - } else { - std::cerr << m1 << std::endl << std::flush; } + std::cerr << m1 << std::endl << std::flush; } void cmSystemTools::ReportLastSystemError(const char* msg) @@ -1688,7 +1687,8 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line, if (pipe == cmsysProcess_Pipe_Timeout) { // Timeout has been exceeded. return pipe; - } else if (pipe == cmsysProcess_Pipe_STDOUT) { + } + if (pipe == cmsysProcess_Pipe_STDOUT) { // Append to the stdout buffer. std::vector::size_type size = out.size(); out.insert(out.end(), data, data + length); @@ -1704,13 +1704,13 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line, line.append(&out[0], outiter - out.begin()); out.erase(out.begin(), out.end()); return cmsysProcess_Pipe_STDOUT; - } else if (!err.empty()) { + } + if (!err.empty()) { line.append(&err[0], erriter - err.begin()); err.erase(err.begin(), err.end()); return cmsysProcess_Pipe_STDERR; - } else { - return cmsysProcess_Pipe_None; } + return cmsysProcess_Pipe_None; } } } @@ -2218,13 +2218,12 @@ bool cmSystemTools::ChangeRPath(std::string const& file, // The new rpath is empty and there is no rpath anyway so it is // okay. return true; - } else { - if (emsg) { - *emsg = "No valid ELF RPATH or RUNPATH entry exists in the file; "; - *emsg += elf.GetErrorMessage(); - } - return false; } + if (emsg) { + *emsg = "No valid ELF RPATH or RUNPATH entry exists in the file; "; + *emsg += elf.GetErrorMessage(); + } + return false; } for (int i = 0; i < se_count; ++i) { @@ -2382,7 +2381,8 @@ bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op, if (lhs < rhs) { // lhs < rhs, so true if operation is LESS return (op & cmSystemTools::OP_LESS) != 0; - } else if (lhs > rhs) { + } + if (lhs > rhs) { // lhs > rhs, so true if operation is GREATER return (op & cmSystemTools::OP_GREATER) != 0; } diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 5681885..ed04d2f 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -774,12 +774,14 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) << prop << "\" is not allowed."; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); return; - } else if (prop == "NAME") { + } + if (prop == "NAME") { std::ostringstream e; e << "NAME property is read-only\n"; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); return; - } else if (prop == "INCLUDE_DIRECTORIES") { + } + if (prop == "INCLUDE_DIRECTORIES") { this->Internal->IncludeDirectoriesEntries.clear(); this->Internal->IncludeDirectoriesBacktraces.clear(); if (value) { @@ -856,12 +858,14 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value, << prop << "\" is not allowed."; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); return; - } else if (prop == "NAME") { + } + if (prop == "NAME") { std::ostringstream e; e << "NAME property is read-only\n"; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); return; - } else if (prop == "INCLUDE_DIRECTORIES") { + } + if (prop == "INCLUDE_DIRECTORIES") { if (value && *value) { this->Internal->IncludeDirectoriesEntries.push_back(value); cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); @@ -1230,9 +1234,10 @@ const char* cmTarget::GetProperty(const std::string& prop, return output.c_str(); } // the type property returns what type the target is - else if (prop == propTYPE) { + if (prop == propTYPE) { return cmState::GetTargetTypeName(this->GetType()); - } else if (prop == propINCLUDE_DIRECTORIES) { + } + if (prop == propINCLUDE_DIRECTORIES) { if (this->Internal->IncludeDirectoriesEntries.empty()) { return CM_NULLPTR; } @@ -1240,7 +1245,8 @@ const char* cmTarget::GetProperty(const std::string& prop, static std::string output; output = cmJoin(this->Internal->IncludeDirectoriesEntries, ";"); return output.c_str(); - } else if (prop == propCOMPILE_FEATURES) { + } + if (prop == propCOMPILE_FEATURES) { if (this->Internal->CompileFeaturesEntries.empty()) { return CM_NULLPTR; } @@ -1248,7 +1254,8 @@ const char* cmTarget::GetProperty(const std::string& prop, static std::string output; output = cmJoin(this->Internal->CompileFeaturesEntries, ";"); return output.c_str(); - } else if (prop == propCOMPILE_OPTIONS) { + } + if (prop == propCOMPILE_OPTIONS) { if (this->Internal->CompileOptionsEntries.empty()) { return CM_NULLPTR; } @@ -1256,7 +1263,8 @@ const char* cmTarget::GetProperty(const std::string& prop, static std::string output; output = cmJoin(this->Internal->CompileOptionsEntries, ";"); return output.c_str(); - } else if (prop == propCOMPILE_DEFINITIONS) { + } + if (prop == propCOMPILE_DEFINITIONS) { if (this->Internal->CompileDefinitionsEntries.empty()) { return CM_NULLPTR; } @@ -1264,15 +1272,20 @@ const char* cmTarget::GetProperty(const std::string& prop, static std::string output; output = cmJoin(this->Internal->CompileDefinitionsEntries, ";"); return output.c_str(); - } else if (prop == propIMPORTED) { + } + if (prop == propIMPORTED) { return this->IsImported() ? "TRUE" : "FALSE"; - } else if (prop == propNAME) { + } + if (prop == propNAME) { return this->GetName().c_str(); - } else if (prop == propBINARY_DIR) { + } + if (prop == propBINARY_DIR) { return this->GetMakefile()->GetCurrentBinaryDirectory(); - } else if (prop == propSOURCE_DIR) { + } + if (prop == propSOURCE_DIR) { return this->GetMakefile()->GetCurrentSourceDirectory(); - } else if (prop == propSOURCES) { + } + if (prop == propSOURCES) { if (this->Internal->SourceEntries.empty()) { return CM_NULLPTR; } diff --git a/Source/cmUuid.cxx b/Source/cmUuid.cxx index 7bfc109..b072964 100644 --- a/Source/cmUuid.cxx +++ b/Source/cmUuid.cxx @@ -180,13 +180,14 @@ bool cmUuid::IntFromHexDigit(char input, char& output) const if (input >= '0' && input <= '9') { output = char(input - '0'); return true; - } else if (input >= 'a' && input <= 'f') { + } + if (input >= 'a' && input <= 'f') { output = char(input - 'a' + 0xA); return true; - } else if (input >= 'A' && input <= 'F') { + } + if (input >= 'A' && input <= 'F') { output = char(input - 'A' + 0xA); return true; - } else { - return false; } + return false; } diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 9e338e8..74c3f71 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -1513,9 +1513,8 @@ int cmake::Run(const std::vector& args, bool noconfigure) if (this->GetWorkingMode() != NORMAL_MODE) { if (cmSystemTools::GetErrorOccuredFlag()) { return -1; - } else { - return 0; } + return 0; } // If MAKEFLAGS are given in the environment, remove the environment @@ -2063,11 +2062,10 @@ cmInstalledFile* cmake::GetOrCreateInstalledFile(cmMakefile* mf, if (i != this->InstalledFiles.end()) { cmInstalledFile& file = i->second; return &file; - } else { - cmInstalledFile& file = this->InstalledFiles[name]; - file.SetName(mf, name); - return &file; } + cmInstalledFile& file = this->InstalledFiles[name]; + file.SetName(mf, name); + return &file; } cmInstalledFile const* cmake::GetInstalledFile(const std::string& name) const @@ -2078,9 +2076,8 @@ cmInstalledFile const* cmake::GetInstalledFile(const std::string& name) const if (i != this->InstalledFiles.end()) { cmInstalledFile const& file = i->second; return &file; - } else { - return CM_NULLPTR; } + return CM_NULLPTR; } int cmake::GetSystemInformation(std::vector& args) @@ -2253,11 +2250,10 @@ static bool cmakeCheckStampFile(const char* stampName) std::cout << "CMake does not need to re-run because " << stampName << " is up-to-date.\n"; return true; - } else { - cmSystemTools::RemoveFile(stampTemp); - cmSystemTools::Error("Cannot restore timestamp ", stampName); - return false; } + cmSystemTools::RemoveFile(stampTemp); + cmSystemTools::Error("Cannot restore timestamp ", stampName); + return false; } static bool cmakeCheckStampList(const char* stampList) diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 8731b2b..1505d00 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -163,7 +163,8 @@ int main(int ac, char const* const* av) if (ac > 1) { if (strcmp(av[1], "--build") == 0) { return do_build(ac, av); - } else if (strcmp(av[1], "-E") == 0) { + } + if (strcmp(av[1], "-E") == 0) { return do_command(ac, av); } } @@ -237,7 +238,8 @@ int do_cmake(int ac, char const* const* av) "Use cmake-gui or ccmake for an interactive dialog.\n"; /* clang-format on */ return 1; - } else if (strcmp(av[i], "--system-information") == 0) { + } + if (strcmp(av[i], "--system-information") == 0) { sysinfo = true; } else if (strcmp(av[i], "-N") == 0) { view_only = true; @@ -313,9 +315,8 @@ int do_cmake(int ac, char const* const* av) // interpret negative return values as errors. if (res != 0) { return 1; - } else { - return 0; } + return 0; } static int do_build(int ac, char const* const* av) diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index be023b1..f25c085 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -262,7 +262,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector& args) // run include what you use command and then run the compile // command. This is an internal undocumented option and should // only be used by CMake itself when running iwyu. - else if (args[1] == "__run_iwyu") { + if (args[1] == "__run_iwyu") { if (args.size() < 3) { std::cerr << "__run_iwyu Usage: -E __run_iwyu [--iwyu=/path/iwyu]" " [--tidy=/path/tidy] -- compile command\n"; @@ -393,13 +393,13 @@ int cmcmd::ExecuteCMakeCommand(std::vector& args) } // Echo string - else if (args[1] == "echo") { + if (args[1] == "echo") { std::cout << cmJoin(cmMakeRange(args).advance(2), " ") << std::endl; return 0; } // Echo string no new line - else if (args[1] == "echo_append") { + if (args[1] == "echo_append") { std::cout << cmJoin(cmMakeRange(args).advance(2), " "); return 0; } @@ -851,7 +851,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector& args) cmSystemTools::Error("Can not use compression flags with format: ", format.c_str()); return 1; - } else if (nCompress > 1) { + } + if (nCompress > 1) { cmSystemTools::Error("Can only compress a tar file one way; " "at most one flag of z, j, or J may be used"); return 1; @@ -995,12 +996,12 @@ static void cmcmdProgressReport(std::string const& dir, std::string const& num) int count = 0; if (!progFile) { return; - } else { - if (1 != fscanf(progFile, "%i", &count)) { - cmSystemTools::Message("Could not read from progress file."); - } - fclose(progFile); } + if (1 != fscanf(progFile, "%i", &count)) { + cmSystemTools::Message("Could not read from progress file."); + } + fclose(progFile); + const char* last = num.c_str(); for (const char* c = last;; ++c) { if (*c == ',' || *c == '\0') { https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=50ad1e0a144ae1f2267a4966789e5a16372f458e commit 50ad1e0a144ae1f2267a4966789e5a16372f458e Author: Daniel Pfeifer AuthorDate: Thu Aug 18 20:04:21 2016 +0200 Commit: Daniel Pfeifer CommitDate: Thu Aug 18 20:04:21 2016 +0200 CTest: don't use else after return diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index f96ef6d..230e8c5 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -532,9 +532,8 @@ public: if (this->FTC->FileTimeCompare(l.c_str(), r.c_str(), &result) && result != 0) { return result < 0; - } else { - return l < r; } + return l < r; } private: diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx index 37bdf9a..fb96308 100644 --- a/Source/CTest/cmCTestCVS.cxx +++ b/Source/CTest/cmCTestCVS.cxx @@ -216,10 +216,9 @@ std::string cmCTestCVS::ComputeBranchFlag(std::string const& dir) std::string flag = "-r"; flag += tagLine.substr(1); return flag; - } else { - // Use the default branch. - return "-b"; } + // Use the default branch. + return "-b"; } void cmCTestCVS::LoadRevisions(std::string const& file, const char* branchFlag, diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 3f37f2a..dd6eb3a 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -763,12 +763,11 @@ int cmCTestCoverageHandler::HandleMumpsCoverage( this->Quiet); cov.ReadCoverageFile(coverageFile.c_str()); return static_cast(cont->TotalCoverage.size()); - } else { - cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, - " Cannot find GTM coverage file: " << coverageFile - << std::endl, - this->Quiet); } + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + " Cannot find GTM coverage file: " << coverageFile + << std::endl, + this->Quiet); cmParseCacheCoverage ccov(*cont, this->CTest); coverageFile = this->CTest->GetBinaryDir() + "/cache_coverage.cmcov"; if (cmSystemTools::FileExists(coverageFile.c_str())) { diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx index 3eed79e..fedcb1f 100644 --- a/Source/CTest/cmCTestLaunch.cxx +++ b/Source/CTest/cmCTestLaunch.cxx @@ -126,12 +126,11 @@ bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv) this->HandleRealArg(this->RealArgV[i]); } return true; - } else { - this->RealArgC = 0; - this->RealArgV = CM_NULLPTR; - std::cerr << "No launch/command separator ('--') found!\n"; - return false; } + this->RealArgC = 0; + this->RealArgV = CM_NULLPTR; + std::cerr << "No launch/command separator ('--') found!\n"; + return false; } void cmCTestLaunch::HandleRealArg(const char* arg) diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index a06c351..7d0715f 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -638,27 +638,24 @@ bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str, std::string& log, std::vector& results) { - if (this->MemoryTesterStyle == cmCTestMemCheckHandler::VALGRIND) { - return this->ProcessMemCheckValgrindOutput(str, log, results); - } else if (this->MemoryTesterStyle == cmCTestMemCheckHandler::PURIFY) { - return this->ProcessMemCheckPurifyOutput(str, log, results); - } else if (this->MemoryTesterStyle == - cmCTestMemCheckHandler::ADDRESS_SANITIZER || - this->MemoryTesterStyle == - cmCTestMemCheckHandler::THREAD_SANITIZER || - this->MemoryTesterStyle == - cmCTestMemCheckHandler::MEMORY_SANITIZER || - this->MemoryTesterStyle == cmCTestMemCheckHandler::UB_SANITIZER) { - return this->ProcessMemCheckSanitizerOutput(str, log, results); - } else if (this->MemoryTesterStyle == - cmCTestMemCheckHandler::BOUNDS_CHECKER) { - return this->ProcessMemCheckBoundsCheckerOutput(str, log, results); - } else { - log.append("\nMemory checking style used was: "); - log.append("None that I know"); - log = str; + switch (this->MemoryTesterStyle) { + case cmCTestMemCheckHandler::VALGRIND: + return this->ProcessMemCheckValgrindOutput(str, log, results); + case cmCTestMemCheckHandler::PURIFY: + return this->ProcessMemCheckPurifyOutput(str, log, results); + case cmCTestMemCheckHandler::ADDRESS_SANITIZER: + case cmCTestMemCheckHandler::THREAD_SANITIZER: + case cmCTestMemCheckHandler::MEMORY_SANITIZER: + case cmCTestMemCheckHandler::UB_SANITIZER: + return this->ProcessMemCheckSanitizerOutput(str, log, results); + case cmCTestMemCheckHandler::BOUNDS_CHECKER: + return this->ProcessMemCheckBoundsCheckerOutput(str, log, results); + default: + log.append("\nMemory checking style used was: "); + log.append("None that I know"); + log = str; + return true; } - return true; } std::vector::size_type cmCTestMemCheckHandler::FindOrAddWarning( diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index a4e0b95..2632870 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -824,9 +824,8 @@ bool cmCTestMultiProcessHandler::CheckCycles() << this->Properties[root]->Name << "\".\nPlease fix the cycle and run ctest again.\n"); return false; - } else { - s.push(*d); } + s.push(*d); } } } diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx index d4a32f1..82422a3 100644 --- a/Source/CTest/cmCTestP4.cxx +++ b/Source/CTest/cmCTestP4.cxx @@ -373,9 +373,8 @@ std::string cmCTestP4::GetWorkingRevision() if (rev.empty()) { return "0"; - } else { - return rev; } + return rev; } void cmCTestP4::NoteOldRevision() diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 9e3802a..49acbbf 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -54,7 +54,8 @@ bool cmCTestRunTest::CheckOutput() if (p == cmsysProcess_Pipe_None) { // Process has terminated and all output read. return false; - } else if (p == cmsysProcess_Pipe_STDOUT) { + } + if (p == cmsysProcess_Pipe_STDOUT) { // Store this line of output. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex() << ": " << line << std::endl); @@ -82,8 +83,7 @@ bool cmCTestRunTest::CheckOutput() } } } - } else // if(p == cmsysProcess_Pipe_Timeout) - { + } else { // if(p == cmsysProcess_Pipe_Timeout) break; } } diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx index 06f838c..bee8296 100644 --- a/Source/CTest/cmCTestSVN.cxx +++ b/Source/CTest/cmCTestSVN.cxx @@ -80,11 +80,11 @@ static bool cmCTestSVNPathStarts(std::string const& p1, std::string const& p2) // Does path p1 start with path p2? if (p1.size() == p2.size()) { return p1 == p2; - } else if (p1.size() > p2.size() && p1[p2.size()] == '/') { + } + if (p1.size() > p2.size() && p1[p2.size()] == '/') { return strncmp(p1.c_str(), p2.c_str(), p2.size()) == 0; - } else { - return false; } + return false; } std::string cmCTestSVN::LoadInfo(SVNInfo& svninfo) @@ -295,9 +295,8 @@ bool cmCTestSVN::RunSVNCommand(std::vector const& parameters, if (strcmp(parameters[0], "update") == 0) { return RunUpdateCommand(&args[0], out, err); - } else { - return RunChild(&args[0], out, err); } + return RunChild(&args[0], out, err); } class cmCTestSVN::LogParser : public cmCTestVC::OutputLogger, diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index b932277..3ce0317 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -284,14 +284,13 @@ inline int GetNextNumber(std::string const& in, int& val, } pos = pos2 + 1; return 1; + } + if (in.size() - pos == 0) { + val = -1; } else { - if (in.size() - pos == 0) { - val = -1; - } else { - val = atoi(in.substr(pos, in.size() - pos).c_str()); - } - return 0; + val = atoi(in.substr(pos, in.size() - pos).c_str()); } + return 0; } // get the next number in a string with numbers separated by , @@ -311,14 +310,13 @@ inline int GetNextRealNumber(std::string const& in, double& val, } pos = pos2 + 1; return 1; + } + if (in.size() - pos == 0) { + val = -1; } else { - if (in.size() - pos == 0) { - val = -1; - } else { - val = atof(in.substr(pos, in.size() - pos).c_str()); - } - return 0; + val = atof(in.substr(pos, in.size() - pos).c_str()); } + return 0; } cmCTestTestHandler::cmCTestTestHandler() diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx index 7393d21..016b32b 100644 --- a/Source/CTest/cmCTestUploadCommand.cxx +++ b/Source/CTest/cmCTestUploadCommand.cxx @@ -49,14 +49,13 @@ bool cmCTestUploadCommand::CheckArgumentValue(std::string const& arg) if (cmSystemTools::FileExists(arg.c_str())) { this->Files.insert(arg); return true; - } else { - std::ostringstream e; - e << "File \"" << arg << "\" does not exist. Cannot submit " - << "a non-existent file."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); - this->ArgumentDoing = ArgumentDoingError; - return false; } + std::ostringstream e; + e << "File \"" << arg << "\" does not exist. Cannot submit " + << "a non-existent file."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); + this->ArgumentDoing = ArgumentDoingError; + return false; } // Look for other arguments. diff --git a/Source/CTest/cmParseBlanketJSCoverage.cxx b/Source/CTest/cmParseBlanketJSCoverage.cxx index fa539e4..976a92d 100644 --- a/Source/CTest/cmParseBlanketJSCoverage.cxx +++ b/Source/CTest/cmParseBlanketJSCoverage.cxx @@ -42,9 +42,8 @@ public: std::string foundFileName = line.substr(begIndex + 3, endIndex - (begIndex + 4)); return foundFileName; - } else { - return line.substr(begIndex, line.npos); } + return line.substr(begIndex, line.npos); } bool ParseFile(std::string const& file) { diff --git a/Source/CTest/cmParseMumpsCoverage.cxx b/Source/CTest/cmParseMumpsCoverage.cxx index d786d79..af01496 100644 --- a/Source/CTest/cmParseMumpsCoverage.cxx +++ b/Source/CTest/cmParseMumpsCoverage.cxx @@ -128,16 +128,15 @@ bool cmParseMumpsCoverage::FindMumpsFile(std::string const& routine, if (i != this->RoutineToDirectory.end()) { filepath = i->second; return true; - } else { - // try some alternate names - const char* tryname[] = { "GUX", "GTM", "ONT", CM_NULLPTR }; - for (int k = 0; tryname[k] != CM_NULLPTR; k++) { - std::string routine2 = routine + tryname[k]; - i = this->RoutineToDirectory.find(routine2); - if (i != this->RoutineToDirectory.end()) { - filepath = i->second; - return true; - } + } + // try some alternate names + const char* tryname[] = { "GUX", "GTM", "ONT", CM_NULLPTR }; + for (int k = 0; tryname[k] != CM_NULLPTR; k++) { + std::string routine2 = routine + tryname[k]; + i = this->RoutineToDirectory.find(routine2); + if (i != this->RoutineToDirectory.end()) { + filepath = i->second; + return true; } } return false; diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 92fe642..30cd102 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -124,10 +124,10 @@ int cmProcess::GetNextOutputLine(std::string& line, double timeout) int p = cmsysProcess_WaitForData(this->Process, &data, &length, &timeout); if (p == cmsysProcess_Pipe_Timeout) { return cmsysProcess_Pipe_Timeout; - } else if (p == cmsysProcess_Pipe_STDOUT) { + } + if (p == cmsysProcess_Pipe_STDOUT) { this->Output.insert(this->Output.end(), data, data + length); - } else // p == cmsysProcess_Pipe_None - { + } else { // p == cmsysProcess_Pipe_None // The process will provide no more data. break; } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7f97a6c94b59be7e7eba7362ce3eecdcff79ab70 commit 7f97a6c94b59be7e7eba7362ce3eecdcff79ab70 Author: Daniel Pfeifer AuthorDate: Thu Aug 18 19:47:32 2016 +0200 Commit: Daniel Pfeifer CommitDate: Thu Aug 18 19:47:32 2016 +0200 CPack: don't use else after return diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx index 9120a2f..0d3725d 100644 --- a/Source/CPack/cmCPackArchiveGenerator.cxx +++ b/Source/CPack/cmCPackArchiveGenerator.cxx @@ -231,10 +231,8 @@ int cmCPackArchiveGenerator::PackageFiles() // There will be 1 package for each component group // however one may require to ignore component group and // in this case you'll get 1 package for each component. - else { - return PackageComponents(componentPackageMethod == - ONE_PACKAGE_PER_COMPONENT); - } + return PackageComponents(componentPackageMethod == + ONE_PACKAGE_PER_COMPONENT); } // CASE 3 : NON COMPONENT package. diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx index 3edc430..1f3ac51 100644 --- a/Source/CPack/cmCPackDebGenerator.cxx +++ b/Source/CPack/cmCPackDebGenerator.cxx @@ -242,15 +242,11 @@ int cmCPackDebGenerator::PackageFiles() // There will be 1 package for each component group // however one may require to ignore component group and // in this case you'll get 1 package for each component. - else { - return PackageComponents(componentPackageMethod == - ONE_PACKAGE_PER_COMPONENT); - } + return PackageComponents(componentPackageMethod == + ONE_PACKAGE_PER_COMPONENT); } // CASE 3 : NON COMPONENT package. - else { - return PackageComponentsAllInOne(""); - } + return PackageComponentsAllInOne(""); } int cmCPackDebGenerator::createDeb() @@ -694,9 +690,8 @@ std::string cmCPackDebGenerator::GetComponentInstallDirNameSuffix( "CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP"; if (CM_NULLPTR != GetOption(groupVar)) { return std::string(GetOption(groupVar)); - } else { - return componentName; } + return componentName; } // The following code is taken from OpenBSD ar: diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index 58a2243..96c218c 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -67,7 +67,8 @@ int cmCPackGenerator::PrepareNames() cmCPackLog::LOG_ERROR, "CPACK_SET_DESTDIR is set to ON but the '" << Name << "' generator does NOT support it." << std::endl); return 0; - } else if (SETDESTDIR_SHOULD_NOT_BE_USED == SupportsSetDestdir()) { + } + if (SETDESTDIR_SHOULD_NOT_BE_USED == SupportsSetDestdir()) { cmCPackLogger(cmCPackLog::LOG_WARNING, "CPACK_SET_DESTDIR is set to ON but it is " << "usually a bad idea to do that with '" << Name diff --git a/Source/CPack/cmCPackRPMGenerator.cxx b/Source/CPack/cmCPackRPMGenerator.cxx index 2568d17..5d81a49 100644 --- a/Source/CPack/cmCPackRPMGenerator.cxx +++ b/Source/CPack/cmCPackRPMGenerator.cxx @@ -215,15 +215,11 @@ int cmCPackRPMGenerator::PackageFiles() // There will be 1 package for each component group // however one may require to ignore component group and // in this case you'll get 1 package for each component. - else { - return PackageComponents(componentPackageMethod == - ONE_PACKAGE_PER_COMPONENT); - } + return PackageComponents(componentPackageMethod == + ONE_PACKAGE_PER_COMPONENT); } // CASE 3 : NON COMPONENT package. - else { - return PackageComponentsAllInOne(""); - } + return PackageComponentsAllInOne(""); } bool cmCPackRPMGenerator::SupportsComponentInstallation() const @@ -247,7 +243,6 @@ std::string cmCPackRPMGenerator::GetComponentInstallDirNameSuffix( "CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP"; if (CM_NULLPTR != GetOption(groupVar)) { return std::string(GetOption(groupVar)); - } else { - return componentName; } + return componentName; } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4988b914e1fb7ca215436738ab08ed199a6f63d2 commit 4988b914e1fb7ca215436738ab08ed199a6f63d2 Author: Daniel Pfeifer AuthorDate: Thu Aug 18 19:39:54 2016 +0200 Commit: Daniel Pfeifer CommitDate: Thu Aug 18 19:39:54 2016 +0200 CursesDialog: don't use else after return diff --git a/Source/CursesDialog/cmCursesBoolWidget.cxx b/Source/CursesDialog/cmCursesBoolWidget.cxx index 068bcdc..99f7dcc 100644 --- a/Source/CursesDialog/cmCursesBoolWidget.cxx +++ b/Source/CursesDialog/cmCursesBoolWidget.cxx @@ -40,9 +40,8 @@ bool cmCursesBoolWidget::HandleInput(int& key, cmCursesMainForm* /*fm*/, touchwin(w); wrefresh(w); return true; - } else { - return false; } + return false; } void cmCursesBoolWidget::SetValueAsBool(bool value) diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx index ea12756..462cb6e 100644 --- a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx +++ b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx @@ -110,7 +110,6 @@ const char* cmCursesCacheEntryComposite::GetValue() { if (this->Label) { return this->Label->GetValue(); - } else { - return CM_NULLPTR; } + return CM_NULLPTR; } diff --git a/Source/CursesDialog/cmCursesOptionsWidget.cxx b/Source/CursesDialog/cmCursesOptionsWidget.cxx index 5892e53..9a88aef 100644 --- a/Source/CursesDialog/cmCursesOptionsWidget.cxx +++ b/Source/CursesDialog/cmCursesOptionsWidget.cxx @@ -13,10 +13,7 @@ #include "cmCursesMainForm.h" -inline int ctrl(int z) -{ - return (z & 037); -} +#define ctrl(z) ((z)&037) cmCursesOptionsWidget::cmCursesOptionsWidget(int width, int height, int left, int top) @@ -34,25 +31,27 @@ cmCursesOptionsWidget::cmCursesOptionsWidget(int width, int height, int left, bool cmCursesOptionsWidget::HandleInput(int& key, cmCursesMainForm* /*fm*/, WINDOW* w) { - - // 10 == enter - if (key == 10 || key == KEY_ENTER) { - this->NextOption(); - touchwin(w); - wrefresh(w); - return true; - } else if (key == KEY_LEFT || key == ctrl('b')) { - touchwin(w); - wrefresh(w); - this->PreviousOption(); - return true; - } else if (key == KEY_RIGHT || key == ctrl('f')) { - this->NextOption(); - touchwin(w); - wrefresh(w); - return true; - } else { - return false; + switch (key) { + case 10: // 10 == enter + case KEY_ENTER: + this->NextOption(); + touchwin(w); + wrefresh(w); + return true; + case KEY_LEFT: + case ctrl('b'): + touchwin(w); + wrefresh(w); + this->PreviousOption(); + return true; + case KEY_RIGHT: + case ctrl('f'): + this->NextOption(); + touchwin(w); + wrefresh(w); + return true; + default: + return false; } } diff --git a/Source/CursesDialog/cmCursesStringWidget.cxx b/Source/CursesDialog/cmCursesStringWidget.cxx index c16de23..db98a00 100644 --- a/Source/CursesDialog/cmCursesStringWidget.cxx +++ b/Source/CursesDialog/cmCursesStringWidget.cxx @@ -94,10 +94,9 @@ bool cmCursesStringWidget::HandleInput(int& key, cmCursesMainForm* fm, // quit if (key == 'q') { return false; - } else { - key = getch(); - continue; } + key = getch(); + continue; } // If resize occurred during edit, move out of edit mode @@ -207,7 +206,6 @@ bool cmCursesStringWidget::PrintKeys() curses_move(y - 3, 0); printw(fmt_s, "Editing option, press [enter] to leave edit."); return true; - } else { - return false; } + return false; } ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- Source/CPack/cmCPackArchiveGenerator.cxx | 6 +- Source/CPack/cmCPackDebGenerator.cxx | 13 +- Source/CPack/cmCPackGenerator.cxx | 3 +- Source/CPack/cmCPackRPMGenerator.cxx | 13 +- Source/CTest/cmCTestBuildHandler.cxx | 3 +- Source/CTest/cmCTestCVS.cxx | 5 +- Source/CTest/cmCTestCoverageHandler.cxx | 9 +- Source/CTest/cmCTestLaunch.cxx | 9 +- Source/CTest/cmCTestMemCheckHandler.cxx | 37 ++--- Source/CTest/cmCTestMultiProcessHandler.cxx | 3 +- Source/CTest/cmCTestP4.cxx | 3 +- Source/CTest/cmCTestRunTest.cxx | 6 +- Source/CTest/cmCTestSVN.cxx | 9 +- Source/CTest/cmCTestTestHandler.cxx | 22 ++- Source/CTest/cmCTestUploadCommand.cxx | 13 +- Source/CTest/cmParseBlanketJSCoverage.cxx | 3 +- Source/CTest/cmParseMumpsCoverage.cxx | 19 ++- Source/CTest/cmProcess.cxx | 6 +- Source/CursesDialog/cmCursesBoolWidget.cxx | 3 +- .../CursesDialog/cmCursesCacheEntryComposite.cxx | 3 +- Source/CursesDialog/cmCursesOptionsWidget.cxx | 45 +++--- Source/CursesDialog/cmCursesStringWidget.cxx | 8 +- Source/cmArchiveWrite.cxx | 3 +- Source/cmCTest.cxx | 11 +- Source/cmCacheManager.cxx | 3 +- Source/cmCommandArgumentParserHelper.cxx | 14 +- Source/cmCryptoHash.cxx | 24 +-- Source/cmDependsFortran.cxx | 3 +- Source/cmDocumentation.cxx | 3 +- Source/cmELF.cxx | 27 ++-- Source/cmExportBuildFileGenerator.cxx | 7 +- Source/cmExprParserHelper.cxx | 5 +- Source/cmExtraCodeBlocksGenerator.cxx | 43 +++-- Source/cmFileLockPool.cxx | 5 +- Source/cmFileTimeComparison.cxx | 27 ++-- Source/cmFortranParserImpl.cxx | 50 +++--- Source/cmGeneratorExpression.cxx | 3 +- Source/cmGeneratorExpressionEvaluator.cxx | 23 ++- Source/cmGeneratorExpressionNode.cxx | 6 +- Source/cmGeneratorTarget.cxx | 83 +++++----- Source/cmGlobalNinjaGenerator.cxx | 9 +- Source/cmInstallExportGenerator.cxx | 3 +- Source/cmListFileCache.cxx | 10 +- Source/cmLocalGenerator.cxx | 29 ++-- Source/cmMakefile.cxx | 167 ++++++++++---------- Source/cmNewLineStyle.cxx | 15 +- Source/cmQtAutoGeneratorInitializer.cxx | 3 +- Source/cmSourceFile.cxx | 3 +- Source/cmState.cxx | 18 ++- Source/cmSystemTools.cxx | 26 +-- Source/cmTarget.cxx | 41 +++-- Source/cmUuid.cxx | 9 +- Source/cmake.cxx | 20 +-- Source/cmakemain.cxx | 9 +- Source/cmcmd.cxx | 19 +-- 56 files changed, 458 insertions(+), 506 deletions(-) hooks/post-receive -- CMake From kwrobot at kitware.com Fri Aug 19 00:01:09 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Fri, 19 Aug 2016 00:01:09 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-651-g03d0e6b Message-ID: <20160819040109.8EC7FF5872@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 03d0e6b9bb5e046c424966f9ad06c7a7c7434abe (commit) from 11e0ceaeab905075d93e279b87470b99c6401929 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=03d0e6b9bb5e046c424966f9ad06c7a7c7434abe commit 03d0e6b9bb5e046c424966f9ad06c7a7c7434abe Author: Kitware Robot AuthorDate: Fri Aug 19 00:01:05 2016 -0400 Commit: Kitware Robot CommitDate: Fri Aug 19 00:01:05 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index ca31b76..18c4d8b 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160818) +set(CMake_VERSION_PATCH 20160819) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From kwrobot at kitware.com Sat Aug 20 00:01:05 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Sat, 20 Aug 2016 00:01:05 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-652-g8142698 Message-ID: <20160820040105.E4EC6F532E@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 8142698e7a9752bf849945cf147fcf4ae609359f (commit) from 03d0e6b9bb5e046c424966f9ad06c7a7c7434abe (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8142698e7a9752bf849945cf147fcf4ae609359f commit 8142698e7a9752bf849945cf147fcf4ae609359f Author: Kitware Robot AuthorDate: Sat Aug 20 00:01:03 2016 -0400 Commit: Kitware Robot CommitDate: Sat Aug 20 00:01:03 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 18c4d8b..c5870b9 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160819) +set(CMake_VERSION_PATCH 20160820) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From kwrobot at kitware.com Sun Aug 21 00:01:07 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Sun, 21 Aug 2016 00:01:07 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-653-g020c3e4 Message-ID: <20160821040107.8C5ACF57DE@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 020c3e409d6a64ac0562c1a1f972c56ad2c875e8 (commit) from 8142698e7a9752bf849945cf147fcf4ae609359f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=020c3e409d6a64ac0562c1a1f972c56ad2c875e8 commit 020c3e409d6a64ac0562c1a1f972c56ad2c875e8 Author: Kitware Robot AuthorDate: Sun Aug 21 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Sun Aug 21 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index c5870b9..e63c392 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160820) +set(CMake_VERSION_PATCH 20160821) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From kwrobot at kitware.com Mon Aug 22 00:01:05 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Mon, 22 Aug 2016 00:01:05 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-654-g74ee03a Message-ID: <20160822040105.C74BFF563F@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 74ee03a2628753cd6c8919277b3c3331caca70f0 (commit) from 020c3e409d6a64ac0562c1a1f972c56ad2c875e8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=74ee03a2628753cd6c8919277b3c3331caca70f0 commit 74ee03a2628753cd6c8919277b3c3331caca70f0 Author: Kitware Robot AuthorDate: Mon Aug 22 00:01:03 2016 -0400 Commit: Kitware Robot CommitDate: Mon Aug 22 00:01:03 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index e63c392..bdefd2b 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160821) +set(CMake_VERSION_PATCH 20160822) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From steveire at gmail.com Mon Aug 22 17:55:51 2016 From: steveire at gmail.com (Stephen Kelly) Date: Mon, 22 Aug 2016 17:55:51 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1313-g41b3c6b Message-ID: <20160822215551.8217BF4E1B@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 41b3c6b77a37839c5bbf93c2f4b2a19de55ab19b (commit) via d10f2d8b29f54388f74beaaf4a56275d881f5b85 (commit) via 6a1e4d673a8ecf9aaf3d7335c84d454c40f417f9 (commit) from cdf7e5800504307b820f742fc3944391d6e37292 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=41b3c6b77a37839c5bbf93c2f4b2a19de55ab19b commit 41b3c6b77a37839c5bbf93c2f4b2a19de55ab19b Merge: cdf7e58 d10f2d8 Author: Stephen Kelly AuthorDate: Mon Aug 22 17:55:49 2016 -0400 Commit: CMake Topic Stage CommitDate: Mon Aug 22 17:55:49 2016 -0400 Merge topic 'version-cleanups' into next d10f2d8b Version: Remove check for existence of CVS repository 6a1e4d67 Version: Use cmakedefine01 for boolean https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d10f2d8b29f54388f74beaaf4a56275d881f5b85 commit d10f2d8b29f54388f74beaaf4a56275d881f5b85 Author: Stephen Kelly AuthorDate: Mon Aug 22 23:46:01 2016 +0200 Commit: Stephen Kelly CommitDate: Mon Aug 22 23:54:46 2016 +0200 Version: Remove check for existence of CVS repository diff --git a/Source/CMakeVersionSource.cmake b/Source/CMakeVersionSource.cmake index bc5975e..4f22ded 100644 --- a/Source/CMakeVersionSource.cmake +++ b/Source/CMakeVersionSource.cmake @@ -29,11 +29,4 @@ if(EXISTS ${CMake_SOURCE_DIR}/.git/HEAD) endif() endif() endif() -elseif(EXISTS ${CMake_SOURCE_DIR}/CVS/Repository) - file(READ ${CMake_SOURCE_DIR}/CVS/Repository repo) - set(branch "") - if("${repo}" MATCHES "\\.git/([^\r\n]*)") - set(branch "${CMAKE_MATCH_1}") - endif() - set(CMake_VERSION_SOURCE "cvs${branch}") endif() https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6a1e4d673a8ecf9aaf3d7335c84d454c40f417f9 commit 6a1e4d673a8ecf9aaf3d7335c84d454c40f417f9 Author: Stephen Kelly AuthorDate: Wed Jul 27 00:07:32 2016 +0200 Commit: Stephen Kelly CommitDate: Mon Aug 22 23:52:14 2016 +0200 Version: Use cmakedefine01 for boolean The CMake_VERSION_IS_DIRTY CMake variable is not set by CMakeVersionCompute or its delegate if not building from git, or if the git executable is not found. That means that cmVersionConfig.h would be generated to contain an empty C++ define for CMake_VERSION_IS_DIRTY. cmake::ReportCapabilities() requires the preprocessor define to have a value, so use the standard construct for booleans of cmakedefine01. diff --git a/Source/cmVersionConfig.h.in b/Source/cmVersionConfig.h.in index 92abfbe..ab3c1af 100644 --- a/Source/cmVersionConfig.h.in +++ b/Source/cmVersionConfig.h.in @@ -13,5 +13,5 @@ #define CMake_VERSION_MINOR @CMake_VERSION_MINOR@ #define CMake_VERSION_PATCH @CMake_VERSION_PATCH@ #define CMake_VERSION_SUFFIX "@CMake_VERSION_SUFFIX@" -#define CMake_VERSION_IS_DIRTY @CMake_VERSION_IS_DIRTY@ +#cmakedefine01 CMake_VERSION_IS_DIRTY #define CMake_VERSION "@CMake_VERSION@" ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersionSource.cmake | 7 ------- Source/cmVersionConfig.h.in | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) hooks/post-receive -- CMake From kwrobot at kitware.com Tue Aug 23 00:01:08 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Tue, 23 Aug 2016 00:01:08 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-655-g68b51a5 Message-ID: <20160823040108.AA747F4D64@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 68b51a57e535f67a6837bc0af5e3b00a225f2154 (commit) from 74ee03a2628753cd6c8919277b3c3331caca70f0 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=68b51a57e535f67a6837bc0af5e3b00a225f2154 commit 68b51a57e535f67a6837bc0af5e3b00a225f2154 Author: Kitware Robot AuthorDate: Tue Aug 23 00:01:05 2016 -0400 Commit: Kitware Robot CommitDate: Tue Aug 23 00:01:05 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index bdefd2b..da0aba0 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160822) +set(CMake_VERSION_PATCH 20160823) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 23 08:58:13 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 23 Aug 2016 08:58:13 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1315-g188dba7 Message-ID: <20160823125813.B9728F4D2A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 188dba7ceae98682307541495294e54d3c6824aa (commit) via f29d18477360388cf66be5f1c17e2aae5fb14453 (commit) from 41b3c6b77a37839c5bbf93c2f4b2a19de55ab19b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=188dba7ceae98682307541495294e54d3c6824aa commit 188dba7ceae98682307541495294e54d3c6824aa Merge: 41b3c6b f29d184 Author: Brad King AuthorDate: Tue Aug 23 08:58:12 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 23 08:58:12 2016 -0400 Merge topic 'include-what-you-use' into next f29d1847 fix a batch of include-what-you-use violations https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f29d18477360388cf66be5f1c17e2aae5fb14453 commit f29d18477360388cf66be5f1c17e2aae5fb14453 Author: Daniel Pfeifer AuthorDate: Thu Aug 18 00:24:24 2016 +0200 Commit: Brad King CommitDate: Tue Aug 23 08:56:59 2016 -0400 fix a batch of include-what-you-use violations diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx index 56da2ac..0504f70 100644 --- a/Source/cmArchiveWrite.cxx +++ b/Source/cmArchiveWrite.cxx @@ -16,7 +16,11 @@ #include "cm_get_date.h" #include #include +#include #include +#include +#include +#include #ifndef __LA_SSIZE_T #define __LA_SSIZE_T la_ssize_t diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h index b15c15a..120453b 100644 --- a/Source/cmArchiveWrite.h +++ b/Source/cmArchiveWrite.h @@ -12,7 +12,11 @@ #ifndef cmArchiveWrite_h #define cmArchiveWrite_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep + +#include +#include +#include #if !defined(CMAKE_BUILD_WITH_CMAKE) #error "cmArchiveWrite not allowed during bootstrap build!" diff --git a/Source/cmCLocaleEnvironmentScope.cxx b/Source/cmCLocaleEnvironmentScope.cxx index e4c74ec..e38f531 100644 --- a/Source/cmCLocaleEnvironmentScope.cxx +++ b/Source/cmCLocaleEnvironmentScope.cxx @@ -15,6 +15,7 @@ #include "cmSystemTools.h" #include +#include cmCLocaleEnvironmentScope::cmCLocaleEnvironmentScope() { diff --git a/Source/cmCLocaleEnvironmentScope.h b/Source/cmCLocaleEnvironmentScope.h index b011741..572beaf 100644 --- a/Source/cmCLocaleEnvironmentScope.h +++ b/Source/cmCLocaleEnvironmentScope.h @@ -13,7 +13,10 @@ #ifndef cmCLocaleEnvironmentScope_h #define cmCLocaleEnvironmentScope_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep + +#include +#include class cmCLocaleEnvironmentScope { diff --git a/Source/cmCPackPropertiesGenerator.cxx b/Source/cmCPackPropertiesGenerator.cxx index af01c7d..ae6b0a1 100644 --- a/Source/cmCPackPropertiesGenerator.cxx +++ b/Source/cmCPackPropertiesGenerator.cxx @@ -1,8 +1,13 @@ #include "cmCPackPropertiesGenerator.h" -#include "cmLocalGenerator.h" +#include "cmGeneratorExpression.h" +#include "cmInstalledFile.h" #include "cmOutputConverter.h" +#include +#include +#include + cmCPackPropertiesGenerator::cmCPackPropertiesGenerator( cmLocalGenerator* lg, cmInstalledFile const& installedFile, std::vector const& configurations) diff --git a/Source/cmCPackPropertiesGenerator.h b/Source/cmCPackPropertiesGenerator.h index 4d092f6..77018b0 100644 --- a/Source/cmCPackPropertiesGenerator.h +++ b/Source/cmCPackPropertiesGenerator.h @@ -12,9 +12,15 @@ #ifndef cmCPackPropertiesGenerator_h #define cmCPackPropertiesGenerator_h -#include "cmInstalledFile.h" +#include // IWYU pragma: keep + #include "cmScriptGenerator.h" +#include +#include +#include + +class cmInstalledFile; class cmLocalGenerator; /** \class cmCPackPropertiesGenerator diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index bdd7303..5b76162 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -16,10 +16,12 @@ #include "cmVersion.h" #include "cmake.h" -#include +#include #include #include -#include +#include +#include +#include cmCacheManager::cmCacheManager() { diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h index 14e0f0a..3e32cf0 100644 --- a/Source/cmCacheManager.h +++ b/Source/cmCacheManager.h @@ -12,13 +12,19 @@ #ifndef cmCacheManager_h #define cmCacheManager_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include "cmPropertyMap.h" #include "cmState.h" +#include +#include +#include +#include +#include +#include + class cmake; -class cmMarkAsAdvancedCommand; /** \class cmCacheManager * \brief Control class for cmake's cache diff --git a/Source/cmCommands.h b/Source/cmCommands.h index d0f1ab7..034c9c7 100644 --- a/Source/cmCommands.h +++ b/Source/cmCommands.h @@ -12,7 +12,7 @@ #ifndef cmCommands_h #define cmCommands_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 7ad18f0..6167e2c 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -11,13 +11,21 @@ ============================================================================*/ #include "cmCommonTargetGenerator.h" +#include +#include +#include +#include +#include + +#include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" #include "cmGeneratorTarget.h" #include "cmGlobalCommonGenerator.h" #include "cmLocalCommonGenerator.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmSourceFile.h" -#include "cmSystemTools.h" +#include "cmState.h" cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt) : GeneratorTarget(gt) diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index 0bafde9..d3f9d64 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -12,9 +12,13 @@ #ifndef cmCommonTargetGenerator_h #define cmCommonTargetGenerator_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep -#include "cmLocalGenerator.h" +#include "cmOutputConverter.h" + +#include +#include +#include class cmGeneratorTarget; class cmGlobalCommonGenerator; diff --git a/Source/cmComputeComponentGraph.h b/Source/cmComputeComponentGraph.h index fb95f9a..cc468d9 100644 --- a/Source/cmComputeComponentGraph.h +++ b/Source/cmComputeComponentGraph.h @@ -12,11 +12,12 @@ #ifndef cmComputeComponentGraph_h #define cmComputeComponentGraph_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include "cmGraphAdjacencyList.h" #include +#include /** \class cmComputeComponentGraph * \brief Analyze a graph to determine strongly connected components. diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index fffb77d..98405cf 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -13,13 +13,22 @@ #include "cmAlgorithms.h" #include "cmComputeComponentGraph.h" +#include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmState.h" +#include "cmSystemTools.h" #include "cmTarget.h" #include "cmake.h" +#include #include +#include +#include +#include +#include +#include /* diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index 4a33aff..7cd4140 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -12,17 +12,22 @@ #ifndef cmComputeLinkDepends_h #define cmComputeLinkDepends_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include "cmGraphAdjacencyList.h" #include "cmLinkItem.h" +#include "cmTargetLinkLibraryType.h" +#include #include +#include +#include +#include class cmComputeComponentGraph; +class cmGeneratorTarget; class cmGlobalGenerator; class cmMakefile; -class cmGeneratorTarget; class cmake; /** \class cmComputeLinkDepends diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 7db5df3..82877f3 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -11,19 +11,25 @@ ============================================================================*/ #include "cmComputeLinkInformation.h" -#include "cmComputeLinkDepends.h" -#include "cmOrderDirectories.h" - #include "cmAlgorithms.h" +#include "cmComputeLinkDepends.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmOrderDirectories.h" #include "cmOutputConverter.h" +#include "cmPolicies.h" #include "cmState.h" +#include "cmSystemTools.h" +#include "cmTarget.h" #include "cmake.h" +#include #include +#include +#include +#include //#define CM_COMPUTE_LINK_INFO_DEBUG diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 023c781..7a67567 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -12,15 +12,19 @@ #ifndef cmComputeLinkInformation_h #define cmComputeLinkInformation_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include +#include +#include +#include +#include -class cmake; +class cmGeneratorTarget; class cmGlobalGenerator; class cmMakefile; -class cmGeneratorTarget; class cmOrderDirectories; +class cmake; /** \class cmComputeLinkInformation * \brief Compute link information for a target in one configuration. diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index ff7eb0b..dd07300 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -12,18 +12,25 @@ #include "cmComputeTargetDepends.h" #include "cmComputeComponentGraph.h" +#include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmLinkItem.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmPolicies.h" #include "cmSourceFile.h" #include "cmState.h" #include "cmSystemTools.h" #include "cmTarget.h" +#include "cmTargetDepend.h" #include "cmake.h" -#include - #include +#include +#include +#include + +class cmListFileBacktrace; /* diff --git a/Source/cmComputeTargetDepends.h b/Source/cmComputeTargetDepends.h index 9e51d4d..587ac66 100644 --- a/Source/cmComputeTargetDepends.h +++ b/Source/cmComputeTargetDepends.h @@ -12,16 +12,19 @@ #ifndef cmComputeTargetDepends_h #define cmComputeTargetDepends_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include "cmGraphAdjacencyList.h" -#include +#include +#include +#include +#include class cmComputeComponentGraph; +class cmGeneratorTarget; class cmGlobalGenerator; class cmLinkItem; -class cmGeneratorTarget; class cmTargetDependSet; /** \class cmComputeTargetDepends ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 23 08:59:56 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 23 Aug 2016 08:59:56 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-658-gd15a502 Message-ID: <20160823125956.A9C50F4EC0@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via d15a502f8eec903bd25ab5e1e5ce646eff68a4fc (commit) via 27591a541c3ee7c0a941295f25610631bf18ca74 (commit) via 481c9003fa41e75731bc463cdfa4310e91d5ea4c (commit) from 68b51a57e535f67a6837bc0af5e3b00a225f2154 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d15a502f8eec903bd25ab5e1e5ce646eff68a4fc commit d15a502f8eec903bd25ab5e1e5ce646eff68a4fc Merge: 68b51a5 27591a5 Author: Brad King AuthorDate: Tue Aug 23 08:59:54 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 23 08:59:54 2016 -0400 Merge topic 'minor-cleanups' 27591a54 Define WIN32_LEAN_AND_MEAN for CMake sources on Windows 481c9003 libarchive: Fix include order in xxhash.c ----------------------------------------------------------------------- Summary of changes: Source/CMakeLists.txt | 5 ++++- Utilities/cmlibarchive/libarchive/xxhash.c | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 23 08:59:59 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 23 Aug 2016 08:59:59 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-661-g762131f Message-ID: <20160823125959.54C38F4F13@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 762131fe8d585ced6b259a451ccde8fded2a8ca4 (commit) via f29d18477360388cf66be5f1c17e2aae5fb14453 (commit) via 373b2e483d983136415190dcc838e636077e5991 (commit) from d15a502f8eec903bd25ab5e1e5ce646eff68a4fc (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=762131fe8d585ced6b259a451ccde8fded2a8ca4 commit 762131fe8d585ced6b259a451ccde8fded2a8ca4 Merge: d15a502 f29d184 Author: Brad King AuthorDate: Tue Aug 23 08:59:57 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 23 08:59:57 2016 -0400 Merge topic 'include-what-you-use' f29d1847 fix a batch of include-what-you-use violations 373b2e48 cmArchiveWrite: replace mode_t with int ----------------------------------------------------------------------- Summary of changes: Source/cmArchiveWrite.cxx | 6 +++++- Source/cmArchiveWrite.h | 14 +++++++++----- Source/cmCLocaleEnvironmentScope.cxx | 1 + Source/cmCLocaleEnvironmentScope.h | 5 ++++- Source/cmCPackPropertiesGenerator.cxx | 7 ++++++- Source/cmCPackPropertiesGenerator.h | 8 +++++++- Source/cmCacheManager.cxx | 6 ++++-- Source/cmCacheManager.h | 10 ++++++++-- Source/cmCommands.h | 2 +- Source/cmCommonTargetGenerator.cxx | 10 +++++++++- Source/cmCommonTargetGenerator.h | 8 ++++++-- Source/cmComputeComponentGraph.h | 3 ++- Source/cmComputeLinkDepends.cxx | 9 +++++++++ Source/cmComputeLinkDepends.h | 9 +++++++-- Source/cmComputeLinkInformation.cxx | 12 +++++++++--- Source/cmComputeLinkInformation.h | 10 +++++++--- Source/cmComputeTargetDepends.cxx | 11 +++++++++-- Source/cmComputeTargetDepends.h | 9 ++++++--- 18 files changed, 109 insertions(+), 31 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 23 09:00:02 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 23 Aug 2016 09:00:02 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-666-g797f7ad Message-ID: <20160823130002.CB9CDF4F1B@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 797f7ad87d6f1b6dd7cbbb553d5525ac8ee390f1 (commit) via 7b6349da4dc968691f1a374211fcc153c8b4f1c6 (commit) via 50ad1e0a144ae1f2267a4966789e5a16372f458e (commit) via 7f97a6c94b59be7e7eba7362ce3eecdcff79ab70 (commit) via 4988b914e1fb7ca215436738ab08ed199a6f63d2 (commit) from 762131fe8d585ced6b259a451ccde8fded2a8ca4 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=797f7ad87d6f1b6dd7cbbb553d5525ac8ee390f1 commit 797f7ad87d6f1b6dd7cbbb553d5525ac8ee390f1 Merge: 762131f 7b6349d Author: Brad King AuthorDate: Tue Aug 23 09:00:00 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 23 09:00:00 2016 -0400 Merge topic 'else-after-return' 7b6349da CMake: don't use else after return 50ad1e0a CTest: don't use else after return 7f97a6c9 CPack: don't use else after return 4988b914 CursesDialog: don't use else after return ----------------------------------------------------------------------- Summary of changes: Source/CPack/cmCPackArchiveGenerator.cxx | 6 +- Source/CPack/cmCPackDebGenerator.cxx | 13 +- Source/CPack/cmCPackGenerator.cxx | 3 +- Source/CPack/cmCPackRPMGenerator.cxx | 13 +- Source/CTest/cmCTestBuildHandler.cxx | 3 +- Source/CTest/cmCTestCVS.cxx | 5 +- Source/CTest/cmCTestCoverageHandler.cxx | 9 +- Source/CTest/cmCTestLaunch.cxx | 9 +- Source/CTest/cmCTestMemCheckHandler.cxx | 37 ++--- Source/CTest/cmCTestMultiProcessHandler.cxx | 3 +- Source/CTest/cmCTestP4.cxx | 3 +- Source/CTest/cmCTestRunTest.cxx | 6 +- Source/CTest/cmCTestSVN.cxx | 9 +- Source/CTest/cmCTestTestHandler.cxx | 22 ++- Source/CTest/cmCTestUploadCommand.cxx | 13 +- Source/CTest/cmParseBlanketJSCoverage.cxx | 3 +- Source/CTest/cmParseMumpsCoverage.cxx | 19 ++- Source/CTest/cmProcess.cxx | 6 +- Source/CursesDialog/cmCursesBoolWidget.cxx | 3 +- .../CursesDialog/cmCursesCacheEntryComposite.cxx | 3 +- Source/CursesDialog/cmCursesOptionsWidget.cxx | 45 +++--- Source/CursesDialog/cmCursesStringWidget.cxx | 8 +- Source/cmArchiveWrite.cxx | 3 +- Source/cmCTest.cxx | 11 +- Source/cmCacheManager.cxx | 3 +- Source/cmCommandArgumentParserHelper.cxx | 14 +- Source/cmCryptoHash.cxx | 24 +-- Source/cmDependsFortran.cxx | 3 +- Source/cmDocumentation.cxx | 3 +- Source/cmELF.cxx | 27 ++-- Source/cmExportBuildFileGenerator.cxx | 7 +- Source/cmExprParserHelper.cxx | 5 +- Source/cmExtraCodeBlocksGenerator.cxx | 43 +++-- Source/cmFileLockPool.cxx | 5 +- Source/cmFileTimeComparison.cxx | 27 ++-- Source/cmFortranParserImpl.cxx | 50 +++--- Source/cmGeneratorExpression.cxx | 3 +- Source/cmGeneratorExpressionEvaluator.cxx | 23 ++- Source/cmGeneratorExpressionNode.cxx | 6 +- Source/cmGeneratorTarget.cxx | 83 +++++----- Source/cmGlobalNinjaGenerator.cxx | 9 +- Source/cmInstallExportGenerator.cxx | 3 +- Source/cmListFileCache.cxx | 10 +- Source/cmLocalGenerator.cxx | 29 ++-- Source/cmMakefile.cxx | 167 ++++++++++---------- Source/cmNewLineStyle.cxx | 15 +- Source/cmQtAutoGeneratorInitializer.cxx | 3 +- Source/cmSourceFile.cxx | 3 +- Source/cmState.cxx | 18 ++- Source/cmSystemTools.cxx | 26 +-- Source/cmTarget.cxx | 41 +++-- Source/cmUuid.cxx | 9 +- Source/cmake.cxx | 20 +-- Source/cmakemain.cxx | 9 +- Source/cmcmd.cxx | 19 +-- 55 files changed, 457 insertions(+), 505 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 23 09:05:20 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 23 Aug 2016 09:05:20 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1324-g916478f Message-ID: <20160823130520.E0261F511A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 916478fcca7cf98494207507e1567360b07dbddd (commit) via 797f7ad87d6f1b6dd7cbbb553d5525ac8ee390f1 (commit) via 762131fe8d585ced6b259a451ccde8fded2a8ca4 (commit) via d15a502f8eec903bd25ab5e1e5ce646eff68a4fc (commit) via 68b51a57e535f67a6837bc0af5e3b00a225f2154 (commit) via 74ee03a2628753cd6c8919277b3c3331caca70f0 (commit) via 020c3e409d6a64ac0562c1a1f972c56ad2c875e8 (commit) via 8142698e7a9752bf849945cf147fcf4ae609359f (commit) via 03d0e6b9bb5e046c424966f9ad06c7a7c7434abe (commit) from 188dba7ceae98682307541495294e54d3c6824aa (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=916478fcca7cf98494207507e1567360b07dbddd commit 916478fcca7cf98494207507e1567360b07dbddd Merge: 188dba7 797f7ad Author: Brad King AuthorDate: Tue Aug 23 09:05:12 2016 -0400 Commit: Brad King CommitDate: Tue Aug 23 09:05:12 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 23 09:13:10 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 23 Aug 2016 09:13:10 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1327-g9c9dd3f Message-ID: <20160823131310.773E8F38EF@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 9c9dd3f3ab771a24254960784e77975f4f1d3a7e (commit) via 617af35806961859b3ef479e793cb6d48be6c30d (commit) via a9b8668f4306023f2a046221c8c27e486484b1ae (commit) from 916478fcca7cf98494207507e1567360b07dbddd (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9c9dd3f3ab771a24254960784e77975f4f1d3a7e commit 9c9dd3f3ab771a24254960784e77975f4f1d3a7e Merge: 916478f 617af35 Author: Brad King AuthorDate: Tue Aug 23 09:13:09 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 23 09:13:09 2016 -0400 Merge topic 'version-cleanups' into next 617af358 Version: Always define CMake_VERSION_IS_DIRTY to 0 or 1 a9b8668f Revert "Version: Use cmakedefine01 for boolean" https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=617af35806961859b3ef479e793cb6d48be6c30d commit 617af35806961859b3ef479e793cb6d48be6c30d Author: Brad King AuthorDate: Tue Aug 23 09:09:03 2016 -0400 Commit: Brad King CommitDate: Tue Aug 23 09:09:36 2016 -0400 Version: Always define CMake_VERSION_IS_DIRTY to 0 or 1 In cmVersionConfig.h we must define this macro with a value because clients expect it to have one. Also ensure that all CMakeLists.txt code paths have an initialized value. Reported-by: Stephen Kelly diff --git a/Source/CMakeVersionCompute.cmake b/Source/CMakeVersionCompute.cmake index 3bdcfd6..d9218d7 100644 --- a/Source/CMakeVersionCompute.cmake +++ b/Source/CMakeVersionCompute.cmake @@ -7,6 +7,7 @@ if("${CMake_VERSION_PATCH}" VERSION_LESS 20000000) set(CMake_VERSION_IS_RELEASE 1) set(CMake_VERSION_SOURCE "") else() + set(CMake_VERSION_IS_DIRTY 0) # may be set to 1 by CMakeVersionSource set(CMake_VERSION_IS_RELEASE 0) include(${CMake_SOURCE_DIR}/Source/CMakeVersionSource.cmake) endif() diff --git a/Source/CMakeVersionSource.cmake b/Source/CMakeVersionSource.cmake index 4f22ded..5ea1de3 100644 --- a/Source/CMakeVersionSource.cmake +++ b/Source/CMakeVersionSource.cmake @@ -24,8 +24,6 @@ if(EXISTS ${CMake_SOURCE_DIR}/.git/HEAD) ) if(dirty) set(CMake_VERSION_IS_DIRTY 1) - else() - set(CMake_VERSION_IS_DIRTY 0) endif() endif() endif() https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a9b8668f4306023f2a046221c8c27e486484b1ae commit a9b8668f4306023f2a046221c8c27e486484b1ae Author: Brad King AuthorDate: Tue Aug 23 09:06:24 2016 -0400 Commit: Brad King CommitDate: Tue Aug 23 09:06:24 2016 -0400 Revert "Version: Use cmakedefine01 for boolean" This reverts commit 6a1e4d673a8ecf9aaf3d7335c84d454c40f417f9. diff --git a/Source/cmVersionConfig.h.in b/Source/cmVersionConfig.h.in index ab3c1af..92abfbe 100644 --- a/Source/cmVersionConfig.h.in +++ b/Source/cmVersionConfig.h.in @@ -13,5 +13,5 @@ #define CMake_VERSION_MINOR @CMake_VERSION_MINOR@ #define CMake_VERSION_PATCH @CMake_VERSION_PATCH@ #define CMake_VERSION_SUFFIX "@CMake_VERSION_SUFFIX@" -#cmakedefine01 CMake_VERSION_IS_DIRTY +#define CMake_VERSION_IS_DIRTY @CMake_VERSION_IS_DIRTY@ #define CMake_VERSION "@CMake_VERSION@" ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersionCompute.cmake | 1 + Source/CMakeVersionSource.cmake | 2 -- Source/cmVersionConfig.h.in | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 23 09:13:16 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 23 Aug 2016 09:13:16 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1330-g683a631 Message-ID: <20160823131316.868A5F3944@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 683a63143a68a9ef50c659e86693a16ccc210c8d (commit) via aec06dd4922187ce5346d20a9f0d53f01b6ce9fc (commit) via ef13efab56464890f171c2a2142b64b728f4f2e8 (commit) from 9c9dd3f3ab771a24254960784e77975f4f1d3a7e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=683a63143a68a9ef50c659e86693a16ccc210c8d commit 683a63143a68a9ef50c659e86693a16ccc210c8d Merge: 9c9dd3f aec06dd Author: Brad King AuthorDate: Tue Aug 23 09:13:15 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 23 09:13:15 2016 -0400 Merge topic 'version-cleanups' into next aec06dd4 Version: Always define CMake_VERSION_IS_DIRTY to 0 or 1 ef13efab Version: Remove check for existence of CVS repository https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=aec06dd4922187ce5346d20a9f0d53f01b6ce9fc commit aec06dd4922187ce5346d20a9f0d53f01b6ce9fc Author: Brad King AuthorDate: Tue Aug 23 09:09:03 2016 -0400 Commit: Brad King CommitDate: Tue Aug 23 09:11:57 2016 -0400 Version: Always define CMake_VERSION_IS_DIRTY to 0 or 1 In cmVersionConfig.h we must define this macro with a value because clients expect it to have one. Also ensure that all CMakeLists.txt code paths have an initialized value. Reported-by: Stephen Kelly diff --git a/Source/CMakeVersionCompute.cmake b/Source/CMakeVersionCompute.cmake index 3bdcfd6..d9218d7 100644 --- a/Source/CMakeVersionCompute.cmake +++ b/Source/CMakeVersionCompute.cmake @@ -7,6 +7,7 @@ if("${CMake_VERSION_PATCH}" VERSION_LESS 20000000) set(CMake_VERSION_IS_RELEASE 1) set(CMake_VERSION_SOURCE "") else() + set(CMake_VERSION_IS_DIRTY 0) # may be set to 1 by CMakeVersionSource set(CMake_VERSION_IS_RELEASE 0) include(${CMake_SOURCE_DIR}/Source/CMakeVersionSource.cmake) endif() diff --git a/Source/CMakeVersionSource.cmake b/Source/CMakeVersionSource.cmake index 4f22ded..5ea1de3 100644 --- a/Source/CMakeVersionSource.cmake +++ b/Source/CMakeVersionSource.cmake @@ -24,8 +24,6 @@ if(EXISTS ${CMake_SOURCE_DIR}/.git/HEAD) ) if(dirty) set(CMake_VERSION_IS_DIRTY 1) - else() - set(CMake_VERSION_IS_DIRTY 0) endif() endif() endif() https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ef13efab56464890f171c2a2142b64b728f4f2e8 commit ef13efab56464890f171c2a2142b64b728f4f2e8 Author: Stephen Kelly AuthorDate: Mon Aug 22 23:46:01 2016 +0200 Commit: Brad King CommitDate: Tue Aug 23 09:11:57 2016 -0400 Version: Remove check for existence of CVS repository diff --git a/Source/CMakeVersionSource.cmake b/Source/CMakeVersionSource.cmake index bc5975e..4f22ded 100644 --- a/Source/CMakeVersionSource.cmake +++ b/Source/CMakeVersionSource.cmake @@ -29,11 +29,4 @@ if(EXISTS ${CMake_SOURCE_DIR}/.git/HEAD) endif() endif() endif() -elseif(EXISTS ${CMake_SOURCE_DIR}/CVS/Repository) - file(READ ${CMake_SOURCE_DIR}/CVS/Repository repo) - set(branch "") - if("${repo}" MATCHES "\\.git/([^\r\n]*)") - set(branch "${CMAKE_MATCH_1}") - endif() - set(CMake_VERSION_SOURCE "cvs${branch}") endif() ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 23 10:41:56 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 23 Aug 2016 10:41:56 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1332-gef255b4 Message-ID: <20160823144156.144CDF3794@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via ef255b495f0258451eb53ba6f6525f58a4b5f60b (commit) via 9bd0643a771b19131d14613e963d61d4b32106ee (commit) from 683a63143a68a9ef50c659e86693a16ccc210c8d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ef255b495f0258451eb53ba6f6525f58a4b5f60b commit ef255b495f0258451eb53ba6f6525f58a4b5f60b Merge: 683a631 9bd0643 Author: Brad King AuthorDate: Tue Aug 23 10:41:54 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 23 10:41:54 2016 -0400 Merge topic 'test-extra-generator-dedup' into next 9bd0643a Tests: Refactor testing of extra generators. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9bd0643a771b19131d14613e963d61d4b32106ee commit 9bd0643a771b19131d14613e963d61d4b32106ee Author: Chaoren Lin AuthorDate: Wed Aug 17 13:48:23 2016 -0700 Commit: Brad King CommitDate: Tue Aug 23 10:37:38 2016 -0400 Tests: Refactor testing of extra generators. Use a loop instead of repeating the same thing multiple times. diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 6f1805b..c119cfd 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -569,60 +569,43 @@ if(BUILD_TESTING) ADD_LINK_FLAGS_TEST(mod_flags_config dll_flags_config) ADD_LINK_FLAGS_TEST(exe_flags_config mod_flags_config) - # If we are running right now with a UnixMakefiles based generator, + # If we are running right now with a Unix Makefiles or Ninja based generator, # build the "Simple" test with the ExtraGenerators, if available # This doesn't test whether the generated project files work (unfortunately), # mainly it tests that cmake doesn't crash when generating these project files. - if(${CMAKE_GENERATOR} MATCHES "Unix Makefiles" OR ${CMAKE_GENERATOR} MATCHES "KDevelop") + if(${CMAKE_GENERATOR} MATCHES "Unix Makefiles" OR ${CMAKE_GENERATOR} MATCHES "Ninja") + # check which generators we have execute_process(COMMAND ${CMAKE_CMAKE_COMMAND} --help OUTPUT_VARIABLE cmakeOutput ERROR_VARIABLE cmakeOutput) - # check for the Eclipse generator - if ("${cmakeOutput}" MATCHES Eclipse) - add_test(Simple_EclipseGenerator ${CMAKE_CTEST_COMMAND} - --build-and-test - "${CMake_SOURCE_DIR}/Tests/Simple" - "${CMake_BINARY_DIR}/Tests/Simple_EclipseGenerator" - --build-two-config - --build-generator "Eclipse CDT4 - Unix Makefiles" - --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}" - --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}" - --build-project Simple - --build-options ${build_options} - --test-command Simple) - list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Simple_EclipseGenerator") - endif () - # check for the CodeBlocks generator - if ("${cmakeOutput}" MATCHES CodeBlocks) - add_test(Simple_CodeBlocksGenerator ${CMAKE_CTEST_COMMAND} - --build-and-test - "${CMake_SOURCE_DIR}/Tests/Simple" - "${CMake_BINARY_DIR}/Tests/Simple_CodeBlocksGenerator" - --build-two-config - --build-generator "CodeBlocks - Unix Makefiles" - --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}" - --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}" - --build-project Simple - --build-options ${build_options} - --test-command Simple) - list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Simple_CodeBlocksGenerator") - endif () - # check for the KDevelop3 generator - if ("${cmakeOutput}" MATCHES KDevelop3) - add_test(Simple_KDevelop3Generator ${CMAKE_CTEST_COMMAND} - --build-and-test - "${CMake_SOURCE_DIR}/Tests/Simple" - "${CMake_BINARY_DIR}/Tests/Simple_KDevelop3Generator" - --build-two-config - --build-generator "KDevelop3 - Unix Makefiles" - --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}" - --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}" - --build-project Simple - --build-options ${build_options} - --test-command Simple) - list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Simple_KDevelop3Generator") - endif () + set(extraGenerators + "CodeBlocks" + "CodeLite" + "Eclipse CDT4" + "Kate" + "KDevelop3" + "Sublime Text 2") + + foreach(extraGenerator ${extraGenerators}) + if ("${cmakeOutput}" MATCHES "${extraGenerator} - ${CMAKE_GENERATOR}") + set(extraGeneratorTestName "Simple_${extraGenerator}Generator") + string(REPLACE " " "" extraGeneratorTestName ${extraGeneratorTestName}) + + add_test(${extraGeneratorTestName} ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/Simple" + "${CMake_BINARY_DIR}/Tests/${extraGeneratorTestName}" + --build-two-config + --build-generator "${extraGenerator} - ${CMAKE_GENERATOR}" + --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}" + --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}" + --build-project Simple + --build-options ${build_options} + --test-command Simple) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${extraGeneratorTestName}") + endif () + endforeach(extraGenerator) endif() ----------------------------------------------------------------------- Summary of changes: Tests/CMakeLists.txt | 77 ++++++++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 47 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 23 10:48:04 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 23 Aug 2016 10:48:04 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1334-ga19d6dc Message-ID: <20160823144804.E3C5AF4300@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via a19d6dc8f66ca81b9e9e8b0ca329ec04ff6879d2 (commit) via 2dc9a754b539bb215ad2360a27327a629ad26627 (commit) from ef255b495f0258451eb53ba6f6525f58a4b5f60b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a19d6dc8f66ca81b9e9e8b0ca329ec04ff6879d2 commit a19d6dc8f66ca81b9e9e8b0ca329ec04ff6879d2 Merge: ef255b4 2dc9a75 Author: Brad King AuthorDate: Tue Aug 23 10:48:04 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 23 10:48:04 2016 -0400 Merge topic 'FindCUDA-fix-arch-regex' into next 2dc9a754 FindCUDA: Support `2.1(2.0)` architecture notation https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2dc9a754b539bb215ad2360a27327a629ad26627 commit 2dc9a754b539bb215ad2360a27327a629ad26627 Author: Boris Fomitchev AuthorDate: Thu Aug 18 12:00:42 2016 -0700 Commit: Brad King CommitDate: Tue Aug 23 10:47:27 2016 -0400 FindCUDA: Support `2.1(2.0)` architecture notation Also tweak some messages and comments. diff --git a/Modules/FindCUDA/select_compute_arch.cmake b/Modules/FindCUDA/select_compute_arch.cmake index d516831..5ce71a9 100644 --- a/Modules/FindCUDA/select_compute_arch.cmake +++ b/Modules/FindCUDA/select_compute_arch.cmake @@ -102,7 +102,7 @@ function(CUDA_SELECT_NVCC_ARCH_FLAGS out_variable) set(CUDA_ARCH_LIST ${CUDA_COMMON_GPU_ARCHITECTURES}) elseif("${CUDA_ARCH_LIST}" STREQUAL "Auto") CUDA_DETECT_INSTALLED_GPUS(CUDA_ARCH_LIST) - message(STATUS "Autodetected CUDA architecture(s): ${cuda_arch_bin}") + message(STATUS "Autodetected CUDA architecture(s): ${CUDA_ARCH_LIST}") endif() # Now process the list and look for names @@ -116,7 +116,7 @@ function(CUDA_SELECT_NVCC_ARCH_FLAGS out_variable) set(add_ptx TRUE) set(arch_name ${CMAKE_MATCH_1}) endif() - if(arch_name MATCHES "([0-9]\\.[0-9])$") + if(arch_name MATCHES "^([0-9]\\.[0-9](\\([0-9]\\.[0-9]\\))?)$") set(arch_bin ${CMAKE_MATCH_1}) set(arch_ptx ${arch_bin}) else() @@ -173,11 +173,11 @@ function(CUDA_SELECT_NVCC_ARCH_FLAGS out_variable) # Tell NVCC to add binaries for the specified GPUs foreach(arch ${cuda_arch_bin}) if(arch MATCHES "([0-9]+)\\(([0-9]+)\\)") - # User explicitly specified PTX for the concrete BIN + # User explicitly specified ARCH for the concrete CODE list(APPEND nvcc_flags -gencode arch=compute_${CMAKE_MATCH_2},code=sm_${CMAKE_MATCH_1}) list(APPEND nvcc_archs_readable sm_${CMAKE_MATCH_1}) else() - # User didn't explicitly specify PTX for the concrete BIN, we assume PTX=BIN + # User didn't explicitly specify ARCH for the concrete CODE, we assume ARCH=CODE list(APPEND nvcc_flags -gencode arch=compute_${arch},code=sm_${arch}) list(APPEND nvcc_archs_readable sm_${arch}) endif() ----------------------------------------------------------------------- Summary of changes: Modules/FindCUDA/select_compute_arch.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 23 11:24:41 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 23 Aug 2016 11:24:41 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1336-gc37e432 Message-ID: <20160823152441.2F286F52B4@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via c37e43220147d6cc2e677088953c5ffb510dc8ff (commit) via 15cc50fbb505b526e28c708e4e1b16e79a66799c (commit) from a19d6dc8f66ca81b9e9e8b0ca329ec04ff6879d2 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c37e43220147d6cc2e677088953c5ffb510dc8ff commit c37e43220147d6cc2e677088953c5ffb510dc8ff Merge: a19d6dc 15cc50f Author: Brad King AuthorDate: Tue Aug 23 11:24:40 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 23 11:24:40 2016 -0400 Merge topic 'doc-get_cmake_property' into next 15cc50fb Help: Clarify get_cmake_property command documentation https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=15cc50fbb505b526e28c708e4e1b16e79a66799c commit 15cc50fbb505b526e28c708e4e1b16e79a66799c Author: Brad King AuthorDate: Tue Aug 23 11:14:09 2016 -0400 Commit: Brad King CommitDate: Tue Aug 23 11:14:09 2016 -0400 Help: Clarify get_cmake_property command documentation Closes: #13810, #16258 diff --git a/Help/command/get_cmake_property.rst b/Help/command/get_cmake_property.rst index 3a6fb41..497ab4e 100644 --- a/Help/command/get_cmake_property.rst +++ b/Help/command/get_cmake_property.rst @@ -1,15 +1,20 @@ get_cmake_property ------------------ -Get a property of the CMake instance. +Get a global property of the CMake instance. :: get_cmake_property(VAR property) -Get a property from the CMake instance. The value of the property is +Get a global property from the CMake instance. The value of the property is stored in the variable ``VAR``. If the property is not found, ``VAR`` will be set to "NOTFOUND". See the :manual:`cmake-properties(7)` manual for available properties. -See also the more general :command:`get_property` command. +See also the :command:`get_property` command ``GLOBAL`` option. + +In addition to global properties, this command (for historical reasons) +also supports the :prop_dir:`VARIABLES` and :prop_dir:`MACROS` directory +properties. It also supports a special ``COMPONENTS`` global property that +lists the components given to the :command:`install` command. ----------------------------------------------------------------------- Summary of changes: Help/command/get_cmake_property.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 23 13:16:41 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 23 Aug 2016 13:16:41 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1360-g8a5c096 Message-ID: <20160823171641.81758F4E55@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 8a5c096810ffeed47062c20555f3e138459a76ed (commit) via 7b637ebdc97655462d08d8ff70bee5d4f32e4681 (commit) via c2f561e58c799cc82df7db70710ae2f79b8b6b64 (commit) via 6b84df8da98169af43d4173dfbd1dedf5979dcb2 (commit) via d7d4083025f3007b862dd500c8f5fc64e105055b (commit) via b22294bc41c3ce62e561c7123c3f489a750dcb66 (commit) via b6a3102a9f8da05b50d4f4e96dd9f42ace37aa9b (commit) via d1e3cec2aa17a2f07f22c64c3bd29c765d69d9d2 (commit) via 504db72d99fc2302de605fd9c2f845c1b8865500 (commit) via fa6325782112063b5d425714a37c8ebd01b90d7c (commit) via 6299693f8aa5f5a61cec82215b73a2040a8d8603 (commit) via 29b51379de352980dd453243bea7ed37ed300c62 (commit) via 7d9b49fbdf55b28d2979af89a8192607df487ca1 (commit) via 4389664a26be4d1f96a55c34e5fac9ac1248e5f0 (commit) via 328191f65f7fb58ece6f749fbfc3462539c7afc1 (commit) via 9e032304ea4133dd6c59b2c0f3b686d4a7aac2a5 (commit) via fde59c4d882e104459dbdf8a07a22899427b6657 (commit) via 52b6effd817ae44577f86df4f382b0c98df7402a (commit) via 8e0cb45e5591cc778b054780f9e6290c3f239815 (commit) via d5e7d5f3ebb42e1a8b38e4bd30f717cdac81ed77 (commit) via 64be1ae4a3ae98e63cf35d495f0ca06c77cdf923 (commit) via 47866770cee381851ccc8070f64459909a838288 (commit) via 735f168bf08a4fdf1d9e245035d2dbcadbed652f (commit) via c148803a575ed1c3639123190b1d6a5d31578f34 (commit) from c37e43220147d6cc2e677088953c5ffb510dc8ff (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8a5c096810ffeed47062c20555f3e138459a76ed commit 8a5c096810ffeed47062c20555f3e138459a76ed Merge: c37e432 7b637eb Author: Brad King AuthorDate: Tue Aug 23 13:16:37 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 23 13:16:37 2016 -0400 Merge topic 'android-platform-modules' into next 7b637ebd Android: Add `ANDROID` variable to indicate the target c2f561e5 Android: Add test cases covering use of the NDK and standalone toolchains 6b84df8d Help: Document cross compiling for Android d7d40830 Android: Select the STL type for NDK builds b22294bc Android: Populate compiler flags for current ABI b6a3102a Android: Add a CMAKE_BUILD_TYPE default d1e3cec2 Android: Add Clang -target option for current ABI 504db72d Android: Add placeholders for compiler/abi-specific settings fa632578 Android: Avoid interfering with common pre-existing toolchain files 6299693f Android: Search for NDK and standalone toolchain in more places 29b51379 Android: Detect and save a standalone toolchain without the NDK 7d9b49fb Android: Detect settings from the CMAKE_SYSROOT if it is set 4389664a Android: Detect and save a toolchain from the NDK 328191f6 Android: Set CMAKE_SYSROOT automatically 9e032304 Android: Detect and save the architecture, ABI, and processor fde59c4d Android: Detect and save the API level ... https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7b637ebdc97655462d08d8ff70bee5d4f32e4681 commit 7b637ebdc97655462d08d8ff70bee5d4f32e4681 Author: Brad King AuthorDate: Tue Aug 23 13:08:53 2016 -0400 Commit: Brad King CommitDate: Tue Aug 23 13:10:51 2016 -0400 Android: Add `ANDROID` variable to indicate the target Allow projects to use `if(ANDROID)` to condition their Android-specific code paths. diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index cdce6f6..275b66c 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -173,6 +173,7 @@ Variables that Describe the System .. toctree:: :maxdepth: 1 + /variable/ANDROID /variable/APPLE /variable/BORLAND /variable/CMAKE_CL_64 diff --git a/Help/variable/ANDROID.rst b/Help/variable/ANDROID.rst new file mode 100644 index 0000000..fede4ca --- /dev/null +++ b/Help/variable/ANDROID.rst @@ -0,0 +1,5 @@ +ANDROID +------- + +Set to ``1`` when the target system (:variable:`CMAKE_SYSTEM_NAME`) is +``Android``. diff --git a/Modules/Platform/Android.cmake b/Modules/Platform/Android.cmake index 1bdad04..3d69733 100644 --- a/Modules/Platform/Android.cmake +++ b/Modules/Platform/Android.cmake @@ -1,5 +1,7 @@ include(Platform/Linux) +set(ANDROID 1) + # Android has soname, but binary names must end in ".so" so we cannot append # a version number. Also we cannot portably represent symlinks on the host. set(CMAKE_PLATFORM_NO_VERSIONED_SONAME 1) diff --git a/Tests/RunCMake/Android/common.cmake b/Tests/RunCMake/Android/common.cmake index a679f6c..7eac5d6 100644 --- a/Tests/RunCMake/Android/common.cmake +++ b/Tests/RunCMake/Android/common.cmake @@ -1,6 +1,10 @@ enable_language(C) enable_language(CXX) +if(NOT ANDROID) + message(SEND_ERROR "CMake variable 'ANDROID' is not set to a true value.") +endif() + foreach(f "${CMAKE_C_ANDROID_TOOLCHAIN_PREFIX}gcc${CMAKE_C_ANDROID_TOOLCHAIN_SUFFIX}" "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}g++${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}" https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c2f561e58c799cc82df7db70710ae2f79b8b6b64 commit c2f561e58c799cc82df7db70710ae2f79b8b6b64 Author: Brad King AuthorDate: Tue Jun 21 16:18:56 2016 -0400 Commit: Brad King CommitDate: Tue Aug 23 12:53:10 2016 -0400 Android: Add test cases covering use of the NDK and standalone toolchains diff --git a/Tests/RunCMake/Android/BadSYSROOT-result.txt b/Tests/RunCMake/Android/BadSYSROOT-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Android/BadSYSROOT-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Android/BadSYSROOT-stderr.txt b/Tests/RunCMake/Android/BadSYSROOT-stderr.txt new file mode 100644 index 0000000..e17ca03 --- /dev/null +++ b/Tests/RunCMake/Android/BadSYSROOT-stderr.txt @@ -0,0 +1,20 @@ +^CMake Error at .*/Modules/Platform/Android-Determine.cmake:[0-9]+ \(message\): + The value of CMAKE_SYSROOT: + + .* + + does not match any of the forms: + + /platforms/android-/arch- + /sysroot + + where: + + = Android NDK directory \(with forward slashes\) + = Android API version number \(decimal digits\) + = Android ARCH name \(lower case\) + = Path to standalone toolchain prefix + +Call Stack \(most recent call first\): + .*/Modules/CMakeDetermineSystem.cmake:[0-9]+ \(include\) + CMakeLists.txt:2 \(project\)$ diff --git a/Tests/RunCMake/Android/BadSYSROOT.cmake b/Tests/RunCMake/Android/BadSYSROOT.cmake new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/Android/CMakeLists.txt b/Tests/RunCMake/Android/CMakeLists.txt new file mode 100644 index 0000000..dc92486 --- /dev/null +++ b/Tests/RunCMake/Android/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.6) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/Android/RunCMakeTest.cmake b/Tests/RunCMake/Android/RunCMakeTest.cmake new file mode 100644 index 0000000..39b77cd --- /dev/null +++ b/Tests/RunCMake/Android/RunCMakeTest.cmake @@ -0,0 +1,218 @@ +cmake_minimum_required(VERSION 3.6) + +include(RunCMake) +foreach(v TEST_ANDROID_NDK TEST_ANDROID_STANDALONE_TOOLCHAIN) + string(REPLACE "|" ";" ${v} "${${v}}") +endforeach() + +function(run_Android case) + set(RunCMake_TEST_OPTIONS + -DCMAKE_SYSTEM_NAME=Android + ${RunCMake_TEST_OPTIONS} + ${ARGN} + ) + + # Use a single build tree for a few tests without cleaning. + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build) + set(RunCMake_TEST_NO_CLEAN 1) + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + run_cmake(${case}) + run_cmake_command(${case}-build ${CMAKE_COMMAND} --build .) +endfunction() + +set(RunCMake_TEST_OPTIONS + -DCMAKE_SYSTEM_NAME=Android + -DCMAKE_SYSROOT=${CMAKE_CURRENT_SOURCE_DIR} + ) +run_cmake(BadSYSROOT) +unset(RunCMake_TEST_OPTIONS) + +foreach(ndk IN LISTS TEST_ANDROID_NDK) + # Load available toolchain versions and abis. + file(GLOB _config_mks + "${ndk}/build/core/toolchains/*/config.mk" + "${ndk}/toolchains/*/config.mk" + ) + set(_versions "") + set(_latest_gcc 0) + set(_latest_clang "") + set(_latest_clang_vers 0) + foreach(config_mk IN LISTS _config_mks) + file(STRINGS "${config_mk}" _abis REGEX "^TOOLCHAIN_ABIS +:= +[^ ].*( |$)") + if(_abis AND "${config_mk}" MATCHES [[-((clang)?([0-9]\.[0-9]|))/config\.mk$]]) + set(_version "${CMAKE_MATCH_1}") + set(_is_clang "${CMAKE_MATCH_2}") + set(_cur_vers "${CMAKE_MATCH_3}") + if(_is_clang) + if(_latest_clang_vers STREQUAL "") + # already the latest possible + elseif(_cur_vers STREQUAL "" OR _cur_vers VERSION_GREATER _latest_clang_vers) + set(_latest_clang_vers "${_cur_vers}") + set(_latest_clang "${_version}") + endif() + else() + if(_version VERSION_GREATER _latest_gcc) + set(_latest_gcc ${_version}) + endif() + endif() + list(APPEND _versions "${_version}") + string(REGEX MATCHALL "[a-z][a-z0-9_-]+" _abis "${_abis}") + list(APPEND _abis_${_version} ${_abis}) + endif() + endforeach() + set(_abis_ ${_abis_${_latest_gcc}}) + set(_abis_clang ${_abis_${_latest_clang}}) + if(_versions MATCHES "clang") + set(_versions "clang" ${_versions}) + endif() + list(REMOVE_DUPLICATES _versions) + list(SORT _versions) + set(_versions ";${_versions}") + foreach(vers IN LISTS _versions) + list(REMOVE_DUPLICATES _abis_${vers}) + endforeach() + + # Test failure cases. + message(STATUS "ndk='${ndk}'") + set(RunCMake_TEST_OPTIONS + -DCMAKE_SYSTEM_NAME=Android + -DCMAKE_ANDROID_NDK=${ndk} + -DCMAKE_ANDROID_ARCH_ABI=badabi + ) + run_cmake(ndk-badabi) + set(RunCMake_TEST_OPTIONS + -DCMAKE_SYSTEM_NAME=Android + -DCMAKE_ANDROID_NDK=${ndk} + -DCMAKE_ANDROID_ARCH_ABI=x86 + -DCMAKE_ANDROID_ARM_MODE=0 + ) + run_cmake(ndk-badarm) + set(RunCMake_TEST_OPTIONS + -DCMAKE_SYSTEM_NAME=Android + -DCMAKE_ANDROID_NDK=${ndk} + -DCMAKE_ANDROID_ARM_NEON=0 + ) + run_cmake(ndk-badneon) + set(RunCMake_TEST_OPTIONS + -DCMAKE_SYSTEM_NAME=Android + -DCMAKE_ANDROID_NDK=${ndk} + -DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=badver + ) + run_cmake(ndk-badver) + set(RunCMake_TEST_OPTIONS + -DCMAKE_SYSTEM_NAME=Android + -DCMAKE_ANDROID_NDK=${ndk} + -DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=1.0 + ) + run_cmake(ndk-badvernum) + set(RunCMake_TEST_OPTIONS + -DCMAKE_SYSTEM_NAME=Android + -DCMAKE_ANDROID_NDK=${ndk} + -DCMAKE_ANDROID_STL_TYPE=badstl + ) + run_cmake(ndk-badstl) + unset(RunCMake_TEST_OPTIONS) + + # Find a sysroot to test. + file(GLOB _sysroots "${ndk}/platforms/android-[0-9][0-9]/arch-arm") + if(_sysroots) + list(GET _sysroots 0 _sysroot) + set(RunCMake_TEST_OPTIONS + -DCMAKE_SYSTEM_NAME=Android + -DCMAKE_SYSROOT=${_sysroot} + ) + run_cmake(ndk-sysroot-armeabi) + unset(RunCMake_TEST_OPTIONS) + endif() + + # Find available STLs. + set(stl_types + none + system + gnustl_static + gnustl_shared + ) + + if(IS_DIRECTORY "${ndk}/sources/cxx-stl/gabi++/libs") + list(APPEND stl_types gabi++_static gabi++_shared) + endif() + if(IS_DIRECTORY "${ndk}/sources/cxx-stl/stlport/libs") + list(APPEND stl_types stlport_static stlport_shared) + endif() + if(IS_DIRECTORY "${ndk}/sources/cxx-stl/llvm-libc++/libs") + list(APPEND stl_types c++_static c++_shared) + endif() + + # List possible ABIs. + set(abi_names + armeabi + armeabi-v6 + armeabi-v7a + arm64-v8a + mips + mips64 + x86 + x86_64 + ) + + # Test all combinations. + foreach(vers IN LISTS _versions) + foreach(stl IN LISTS stl_types) + foreach(config Release Debug) + # Test this combination for all available abis. + message(STATUS "ndk='${ndk}' vers='${vers}' stl='${stl}' config='${config}'") + set(RunCMake_TEST_OPTIONS + -DCMAKE_ANDROID_NDK=${ndk} + -DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=${vers} + -DCMAKE_ANDROID_STL_TYPE=${stl} + -DCMAKE_BUILD_TYPE=${config} + ) + foreach(abi IN LISTS abi_names) + # Skip ABIs not supported by this compiler. + if(NOT ";${_abis_${vers}};" MATCHES ";${abi};") + continue() + endif() + + # Skip combinations that seem to be broken. + if("${stl};${abi}" MATCHES [[^c\+\+_static;armeabi]]) + continue() + endif() + + # Run the tests for this combination. + if("${abi}" STREQUAL "armeabi") + run_Android(ndk-armeabi-thumb) # default: -DCMAKE_ANDROID_ARCH_ABI=armeabi -DCMAKE_ANDROID_ARM_MODE=0 + run_Android(ndk-armeabi-arm -DCMAKE_ANDROID_ARM_MODE=1) # default: -DCMAKE_ANDROID_ARCH_ABI=armeabi + else() + run_Android(ndk-${abi} -DCMAKE_ANDROID_ARCH_ABI=${abi}) + if("${abi}" STREQUAL "armeabi-v7a") + run_Android(ndk-${abi}-neon -DCMAKE_ANDROID_ARCH_ABI=${abi} -DCMAKE_ANDROID_ARM_NEON=1) + endif() + endif() + endforeach() + unset(RunCMake_TEST_OPTIONS) + endforeach() + endforeach() + endforeach() +endforeach() + +foreach(toolchain IN LISTS TEST_ANDROID_STANDALONE_TOOLCHAIN) + message(STATUS "toolchain='${toolchain}'") + + set(RunCMake_TEST_OPTIONS + -DCMAKE_SYSTEM_NAME=Android + -DCMAKE_SYSROOT=${toolchain}/sysroot + ) + run_cmake(standalone-sysroot) + unset(RunCMake_TEST_OPTIONS) + + foreach(config Release Debug) + message(STATUS "toolchain='${toolchain}' config='${config}'") + set(RunCMake_TEST_OPTIONS + -DCMAKE_ANDROID_STANDALONE_TOOLCHAIN=${toolchain} + -DCMAKE_BUILD_TYPE=${config} + ) + run_Android(standalone) + unset(RunCMake_TEST_OPTIONS) + endforeach() +endforeach() diff --git a/Tests/RunCMake/Android/android.c b/Tests/RunCMake/Android/android.c new file mode 100644 index 0000000..30e8574 --- /dev/null +++ b/Tests/RunCMake/Android/android.c @@ -0,0 +1,6 @@ +#include "android.h" + +int main(void) +{ + return 0; +} diff --git a/Tests/RunCMake/Android/android.cxx b/Tests/RunCMake/Android/android.cxx new file mode 100644 index 0000000..e6a6cda --- /dev/null +++ b/Tests/RunCMake/Android/android.cxx @@ -0,0 +1,45 @@ +#include "android.h" + +#ifndef STL_NONE +#include +#include +#ifndef STL_SYSTEM +#include +#include +#ifndef STL_GABI +#include +#include +#endif +#endif +#endif + +int main() +{ +#if !defined(STL_NONE) + // Require -lm implied by linking as C++. + std::printf("%p\n", static_cast(&std::sin)); +#endif +#if defined(STL_NONE) + return 0; +#elif defined(STL_SYSTEM) + return 0; +#else + try { + delete (new int); + } catch (std::exception const& e) { +#if defined(STL_GABI) + e.what(); + typeid(e).name(); +#else + std::cerr << e.what() << std::endl; + std::cerr << typeid(e).name() << std::endl; +#endif + } +#if defined(STL_GABI) + return 0; +#else + std::string s; + return static_cast(s.size()); +#endif +#endif +} diff --git a/Tests/RunCMake/Android/android.h b/Tests/RunCMake/Android/android.h new file mode 100644 index 0000000..a5fd67e --- /dev/null +++ b/Tests/RunCMake/Android/android.h @@ -0,0 +1,103 @@ +#ifndef __ANDROID__ +#error "__ANDROID__ not defined" +#endif + +#include + +#if API_LEVEL != __ANDROID_API__ +#error "API levels do not match" +#endif + +#ifdef COMPILER_IS_CLANG +#ifndef __clang__ +#error "COMPILER_IS_CLANG but __clang__ is not defined" +#endif +#else +#ifdef __clang__ +#error "!COMPILER_IS_CLANG but __clang__ is defined" +#endif +#endif + +#ifdef ARM_MODE +#if ARM_MODE == 1 && defined(__thumb__) +#error "ARM_MODE==1 but __thumb__ is defined" +#elif ARM_MODE == 0 && !defined(__thumb__) +#error "ARM_MODE==0 but __thumb__ is not defined" +#endif +#endif + +#ifdef ARM_NEON +#if ARM_NEON == 0 && defined(__ARM_NEON__) +#error "ARM_NEON==0 but __ARM_NEON__ is defined" +#elif ARM_NEON == 1 && !defined(__ARM_NEON__) +#error "ARM_NEON==1 but __ARM_NEON__ is not defined" +#endif +#endif + +#ifdef ABI_armeabi +#ifndef __ARM_EABI__ +#error "ABI_armeabi: __ARM_EABI__ not defined" +#endif +#if __ARM_ARCH != 5 +#error "ABI_armeabi: __ARM_ARCH is not 5" +#endif +#endif + +#ifdef ABI_armeabi_v6 +#ifndef __ARM_EABI__ +#error "ABI_armeabi_v6: __ARM_EABI__ not defined" +#endif +#if __ARM_ARCH != 6 +#error "ABI_armeabi_v6: __ARM_ARCH is not 6" +#endif +#endif + +#ifdef ABI_armeabi_v7a +#ifndef __ARM_EABI__ +#error "ABI_armeabi_v7a: __ARM_EABI__ not defined" +#endif +#if __ARM_ARCH != 7 +#error "ABI_armeabi_v7a: __ARM_ARCH is not 7" +#endif +#endif + +#ifdef ABI_arm64_v8a +#ifdef __ARM_EABI__ +#error "ABI_arm64_v8a: __ARM_EABI__ defined" +#endif +#ifndef __aarch64__ +#error "ABI_arm64_v8a: __aarch64__ not defined" +#endif +#endif + +#ifdef ABI_mips +#if __mips != 32 +#error "ABI_mips: __mips != 32" +#endif +#ifndef _ABIO32 +#error "ABI_mips: _ABIO32 not defined" +#endif +#endif + +#ifdef ABI_mips64 +#if __mips != 64 +#error "ABI_mips64: __mips != 64" +#endif +#ifndef _ABI64 +#error "ABI_mips: _ABI64 not defined" +#endif +#endif + +#ifdef ABI_x86 +#ifndef __i686__ +#error "ABI_x86: __i686__ not defined" +#endif +#endif + +#ifdef ABI_x86_64 +#ifndef __x86_64__ +#error "ABI_x86_64: __x86_64__ not defined" +#endif +#endif + +#include diff --git a/Tests/RunCMake/Android/common.cmake b/Tests/RunCMake/Android/common.cmake new file mode 100644 index 0000000..a679f6c --- /dev/null +++ b/Tests/RunCMake/Android/common.cmake @@ -0,0 +1,56 @@ +enable_language(C) +enable_language(CXX) + +foreach(f + "${CMAKE_C_ANDROID_TOOLCHAIN_PREFIX}gcc${CMAKE_C_ANDROID_TOOLCHAIN_SUFFIX}" + "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}g++${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}" + "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}cpp${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}" + "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}ar${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}" + "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}ld${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}" + ) + if(NOT EXISTS "${f}") + message(SEND_ERROR "Expected file does not exist:\n \"${f}\"") + endif() +endforeach() + +string(APPEND CMAKE_C_FLAGS " -Werror") +string(APPEND CMAKE_CXX_FLAGS " -Werror") +string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-no-undefined") + +if(CMAKE_ANDROID_NDK) + if(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION MATCHES "clang") + add_definitions(-DCOMPILER_IS_CLANG) + endif() +elseif(CMAKE_ANDROID_STANDALONE_TOOLCHAIN) + execute_process( + COMMAND ${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/clang --version + OUTPUT_VARIABLE _out + ERROR_VARIABLE _err + RESULT_VARIABLE _res + ) + if(_res EQUAL 0) + add_definitions(-DCOMPILER_IS_CLANG) + endif() +endif() + +if(CMAKE_ANDROID_STL_TYPE STREQUAL "none") + add_definitions(-DSTL_NONE) +elseif(CMAKE_ANDROID_STL_TYPE STREQUAL "system") + add_definitions(-DSTL_SYSTEM) +elseif(CMAKE_ANDROID_STL_TYPE MATCHES [[^gabi\+\+]]) + add_definitions(-DSTL_GABI) +endif() + +string(REPLACE "-" "_" abi "${CMAKE_ANDROID_ARCH_ABI}") +add_definitions(-DABI_${abi}) +add_definitions(-DAPI_LEVEL=${CMAKE_SYSTEM_VERSION}) +if(CMAKE_ANDROID_ARCH_ABI MATCHES "^armeabi") + add_definitions(-DARM_MODE=${CMAKE_ANDROID_ARM_MODE}) + message(STATUS "CMAKE_ANDROID_ARM_MODE=${CMAKE_ANDROID_ARM_MODE}") +endif() +if(CMAKE_ANDROID_ARCH_ABI STREQUAL "armeabi-v7a") + add_definitions(-DARM_NEON=${CMAKE_ANDROID_ARM_NEON}) + message(STATUS "CMAKE_ANDROID_ARM_NEON=${CMAKE_ANDROID_ARM_NEON}") +endif() +add_executable(android_c android.c) +add_executable(android_cxx android.cxx) diff --git a/Tests/RunCMake/Android/ndk-arm64-v8a-stdout.txt b/Tests/RunCMake/Android/ndk-arm64-v8a-stdout.txt new file mode 100644 index 0000000..8d0bdc2 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-arm64-v8a-stdout.txt @@ -0,0 +1,2 @@ +-- Android: Targeting API '[0-9]+' with architecture 'arm64', ABI 'arm64-v8a', and processor 'aarch64' +-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+' diff --git a/Tests/RunCMake/Android/ndk-arm64-v8a.cmake b/Tests/RunCMake/Android/ndk-arm64-v8a.cmake new file mode 100644 index 0000000..a3185fe --- /dev/null +++ b/Tests/RunCMake/Android/ndk-arm64-v8a.cmake @@ -0,0 +1 @@ +include(common.cmake) diff --git a/Tests/RunCMake/Android/ndk-armeabi-arm-stdout.txt b/Tests/RunCMake/Android/ndk-armeabi-arm-stdout.txt new file mode 100644 index 0000000..3741da3 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-armeabi-arm-stdout.txt @@ -0,0 +1,3 @@ +-- Android: Targeting API '[0-9]+' with architecture 'arm', ABI 'armeabi', and processor 'armv5te' +-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+' +.*-- CMAKE_ANDROID_ARM_MODE=1 diff --git a/Tests/RunCMake/Android/ndk-armeabi-arm.cmake b/Tests/RunCMake/Android/ndk-armeabi-arm.cmake new file mode 100644 index 0000000..a3185fe --- /dev/null +++ b/Tests/RunCMake/Android/ndk-armeabi-arm.cmake @@ -0,0 +1 @@ +include(common.cmake) diff --git a/Tests/RunCMake/Android/ndk-armeabi-thumb-stdout.txt b/Tests/RunCMake/Android/ndk-armeabi-thumb-stdout.txt new file mode 100644 index 0000000..ce0dea2 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-armeabi-thumb-stdout.txt @@ -0,0 +1,3 @@ +-- Android: Targeting API '[0-9]+' with architecture 'arm', ABI 'armeabi', and processor 'armv5te' +-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+' +.*-- CMAKE_ANDROID_ARM_MODE=0 diff --git a/Tests/RunCMake/Android/ndk-armeabi-thumb.cmake b/Tests/RunCMake/Android/ndk-armeabi-thumb.cmake new file mode 100644 index 0000000..a3185fe --- /dev/null +++ b/Tests/RunCMake/Android/ndk-armeabi-thumb.cmake @@ -0,0 +1 @@ +include(common.cmake) diff --git a/Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stdout.txt b/Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stdout.txt new file mode 100644 index 0000000..ac2bfd5 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stdout.txt @@ -0,0 +1,3 @@ +-- Android: Targeting API '[0-9]+' with architecture 'arm', ABI 'armeabi-v7a', and processor 'armv7-a' +-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+' +.*-- CMAKE_ANDROID_ARM_NEON=1 diff --git a/Tests/RunCMake/Android/ndk-armeabi-v7a-neon.cmake b/Tests/RunCMake/Android/ndk-armeabi-v7a-neon.cmake new file mode 100644 index 0000000..a3185fe --- /dev/null +++ b/Tests/RunCMake/Android/ndk-armeabi-v7a-neon.cmake @@ -0,0 +1 @@ +include(common.cmake) diff --git a/Tests/RunCMake/Android/ndk-armeabi-v7a-stdout.txt b/Tests/RunCMake/Android/ndk-armeabi-v7a-stdout.txt new file mode 100644 index 0000000..0edb4f7 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-armeabi-v7a-stdout.txt @@ -0,0 +1,3 @@ +-- Android: Targeting API '[0-9]+' with architecture 'arm', ABI 'armeabi-v7a', and processor 'armv7-a' +-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+' +.*-- CMAKE_ANDROID_ARM_NEON=0 diff --git a/Tests/RunCMake/Android/ndk-armeabi-v7a.cmake b/Tests/RunCMake/Android/ndk-armeabi-v7a.cmake new file mode 100644 index 0000000..a3185fe --- /dev/null +++ b/Tests/RunCMake/Android/ndk-armeabi-v7a.cmake @@ -0,0 +1 @@ +include(common.cmake) diff --git a/Tests/RunCMake/Android/ndk-badabi-result.txt b/Tests/RunCMake/Android/ndk-badabi-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Android/ndk-badabi-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Android/ndk-badabi-stderr.txt b/Tests/RunCMake/Android/ndk-badabi-stderr.txt new file mode 100644 index 0000000..c089235 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-badabi-stderr.txt @@ -0,0 +1,5 @@ +^CMake Error at .*/Modules/Platform/Android-Determine.cmake:[0-9]+ \(message\): + Android: Unknown ABI CMAKE_ANDROID_ARCH_ABI='badabi'. +Call Stack \(most recent call first\): + .*/Modules/CMakeDetermineSystem.cmake:[0-9]+ \(include\) + CMakeLists.txt:[0-9]+ \(project\)$ diff --git a/Tests/RunCMake/Android/ndk-badabi.cmake b/Tests/RunCMake/Android/ndk-badabi.cmake new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/Android/ndk-badarm-result.txt b/Tests/RunCMake/Android/ndk-badarm-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Android/ndk-badarm-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Android/ndk-badarm-stderr.txt b/Tests/RunCMake/Android/ndk-badarm-stderr.txt new file mode 100644 index 0000000..f62bfc4 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-badarm-stderr.txt @@ -0,0 +1,6 @@ +^CMake Error at .*/Modules/Platform/Android-Determine.cmake:[0-9]+ \(message\): + Android: CMAKE_ANDROID_ARM_MODE is set but is valid only for 'armeabi' + architectures. +Call Stack \(most recent call first\): + .*/Modules/CMakeDetermineSystem.cmake:[0-9]+ \(include\) + CMakeLists.txt:[0-9]+ \(project\)$ diff --git a/Tests/RunCMake/Android/ndk-badarm.cmake b/Tests/RunCMake/Android/ndk-badarm.cmake new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/Android/ndk-badneon-result.txt b/Tests/RunCMake/Android/ndk-badneon-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Android/ndk-badneon-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Android/ndk-badneon-stderr.txt b/Tests/RunCMake/Android/ndk-badneon-stderr.txt new file mode 100644 index 0000000..1f0bf00 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-badneon-stderr.txt @@ -0,0 +1,6 @@ +^CMake Error at .*/Modules/Platform/Android-Determine.cmake:[0-9]+ \(message\): + Android: CMAKE_ANDROID_ARM_NEON is set but is valid only for 'armeabi-v7a' + architecture. +Call Stack \(most recent call first\): + .*/Modules/CMakeDetermineSystem.cmake:[0-9]+ \(include\) + CMakeLists.txt:[0-9]+ \(project\)$ diff --git a/Tests/RunCMake/Android/ndk-badneon.cmake b/Tests/RunCMake/Android/ndk-badneon.cmake new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/Android/ndk-badstl-result.txt b/Tests/RunCMake/Android/ndk-badstl-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Android/ndk-badstl-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Android/ndk-badstl-stderr.txt b/Tests/RunCMake/Android/ndk-badstl-stderr.txt new file mode 100644 index 0000000..c61824e --- /dev/null +++ b/Tests/RunCMake/Android/ndk-badstl-stderr.txt @@ -0,0 +1,9 @@ +^CMake Error at .*/Modules/Platform/Android-Common.cmake:[0-9]+ \(message\): + The CMAKE_ANDROID_STL_TYPE 'badstl' is not one of the allowed values: + + .* + +Call Stack \(most recent call first\): +.* + ndk-badstl.cmake:1 \(enable_language\) + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Android/ndk-badstl.cmake b/Tests/RunCMake/Android/ndk-badstl.cmake new file mode 100644 index 0000000..fa2fc91 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-badstl.cmake @@ -0,0 +1 @@ +enable_language(CXX) diff --git a/Tests/RunCMake/Android/ndk-badver-result.txt b/Tests/RunCMake/Android/ndk-badver-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Android/ndk-badver-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Android/ndk-badver-stderr.txt b/Tests/RunCMake/Android/ndk-badver-stderr.txt new file mode 100644 index 0000000..df2c5e6 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-badver-stderr.txt @@ -0,0 +1,12 @@ +^CMake Error at .*/Modules/Platform/Android/Determine-Compiler-NDK.cmake:[0-9]+ \(message\): + Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value 'badver' is not one + of the allowed forms: + + . = GCC of specified version + clang. = Clang of specified version + clang = Clang of most recent available version + +Call Stack \(most recent call first\): +.* + ndk-badver.cmake:1 \(enable_language\) + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Android/ndk-badver.cmake b/Tests/RunCMake/Android/ndk-badver.cmake new file mode 100644 index 0000000..c00af08 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-badver.cmake @@ -0,0 +1 @@ +enable_language(C) diff --git a/Tests/RunCMake/Android/ndk-badvernum-result.txt b/Tests/RunCMake/Android/ndk-badvernum-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Android/ndk-badvernum-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Android/ndk-badvernum-stderr.txt b/Tests/RunCMake/Android/ndk-badvernum-stderr.txt new file mode 100644 index 0000000..25bbaf9 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-badvernum-stderr.txt @@ -0,0 +1,13 @@ +^CMake Error at .*/Modules/Platform/Android/Determine-Compiler-NDK.cmake:[0-9]+ \(message\): + Android: No toolchain for ABI 'armeabi' found in the NDK: + + .* + + of the version specified by CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION: + + 1\.0 + +Call Stack \(most recent call first\): +.* + ndk-badvernum.cmake:1 \(enable_language\) + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Android/ndk-badvernum.cmake b/Tests/RunCMake/Android/ndk-badvernum.cmake new file mode 100644 index 0000000..c00af08 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-badvernum.cmake @@ -0,0 +1 @@ +enable_language(C) diff --git a/Tests/RunCMake/Android/ndk-mips-stdout.txt b/Tests/RunCMake/Android/ndk-mips-stdout.txt new file mode 100644 index 0000000..c744683 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-mips-stdout.txt @@ -0,0 +1,2 @@ +-- Android: Targeting API '[0-9]+' with architecture 'mips', ABI 'mips', and processor 'mips' +-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+' diff --git a/Tests/RunCMake/Android/ndk-mips.cmake b/Tests/RunCMake/Android/ndk-mips.cmake new file mode 100644 index 0000000..a3185fe --- /dev/null +++ b/Tests/RunCMake/Android/ndk-mips.cmake @@ -0,0 +1 @@ +include(common.cmake) diff --git a/Tests/RunCMake/Android/ndk-mips64-stdout.txt b/Tests/RunCMake/Android/ndk-mips64-stdout.txt new file mode 100644 index 0000000..839ddfd --- /dev/null +++ b/Tests/RunCMake/Android/ndk-mips64-stdout.txt @@ -0,0 +1,2 @@ +-- Android: Targeting API '[0-9]+' with architecture 'mips64', ABI 'mips64', and processor 'mips64' +-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+' diff --git a/Tests/RunCMake/Android/ndk-mips64.cmake b/Tests/RunCMake/Android/ndk-mips64.cmake new file mode 100644 index 0000000..a3185fe --- /dev/null +++ b/Tests/RunCMake/Android/ndk-mips64.cmake @@ -0,0 +1 @@ +include(common.cmake) diff --git a/Tests/RunCMake/Android/ndk-sysroot-armeabi-stdout.txt b/Tests/RunCMake/Android/ndk-sysroot-armeabi-stdout.txt new file mode 100644 index 0000000..d309e72 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-sysroot-armeabi-stdout.txt @@ -0,0 +1 @@ +-- Android: Targeting API '[0-9][0-9]' with architecture 'arm', ABI 'armeabi', and processor 'armv5te' diff --git a/Tests/RunCMake/Android/ndk-sysroot-armeabi.cmake b/Tests/RunCMake/Android/ndk-sysroot-armeabi.cmake new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/Android/ndk-x86-stdout.txt b/Tests/RunCMake/Android/ndk-x86-stdout.txt new file mode 100644 index 0000000..2dbb2f0 --- /dev/null +++ b/Tests/RunCMake/Android/ndk-x86-stdout.txt @@ -0,0 +1,2 @@ +-- Android: Targeting API '[0-9]+' with architecture 'x86', ABI 'x86', and processor 'i686' +-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+' diff --git a/Tests/RunCMake/Android/ndk-x86.cmake b/Tests/RunCMake/Android/ndk-x86.cmake new file mode 100644 index 0000000..a3185fe --- /dev/null +++ b/Tests/RunCMake/Android/ndk-x86.cmake @@ -0,0 +1 @@ +include(common.cmake) diff --git a/Tests/RunCMake/Android/ndk-x86_64-stdout.txt b/Tests/RunCMake/Android/ndk-x86_64-stdout.txt new file mode 100644 index 0000000..a7ae91d --- /dev/null +++ b/Tests/RunCMake/Android/ndk-x86_64-stdout.txt @@ -0,0 +1,2 @@ +-- Android: Targeting API '[0-9]+' with architecture 'x86_64', ABI 'x86_64', and processor 'x86_64' +-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+' diff --git a/Tests/RunCMake/Android/ndk-x86_64.cmake b/Tests/RunCMake/Android/ndk-x86_64.cmake new file mode 100644 index 0000000..a3185fe --- /dev/null +++ b/Tests/RunCMake/Android/ndk-x86_64.cmake @@ -0,0 +1 @@ +include(common.cmake) diff --git a/Tests/RunCMake/Android/standalone-stdout.txt b/Tests/RunCMake/Android/standalone-stdout.txt new file mode 100644 index 0000000..20b095c --- /dev/null +++ b/Tests/RunCMake/Android/standalone-stdout.txt @@ -0,0 +1 @@ +-- Android: Targeting API '[0-9]+' with architecture '[a-z0-9_-]+', ABI '[a-z0-9_-]+', and processor '[a-z0-9_-]+' diff --git a/Tests/RunCMake/Android/standalone-sysroot-stdout.txt b/Tests/RunCMake/Android/standalone-sysroot-stdout.txt new file mode 100644 index 0000000..20b095c --- /dev/null +++ b/Tests/RunCMake/Android/standalone-sysroot-stdout.txt @@ -0,0 +1 @@ +-- Android: Targeting API '[0-9]+' with architecture '[a-z0-9_-]+', ABI '[a-z0-9_-]+', and processor '[a-z0-9_-]+' diff --git a/Tests/RunCMake/Android/standalone-sysroot.cmake b/Tests/RunCMake/Android/standalone-sysroot.cmake new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/Android/standalone.cmake b/Tests/RunCMake/Android/standalone.cmake new file mode 100644 index 0000000..a3185fe --- /dev/null +++ b/Tests/RunCMake/Android/standalone.cmake @@ -0,0 +1 @@ +include(common.cmake) diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index dbd5530..323a36b 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -327,3 +327,24 @@ add_RunCMake_test_group(CPack "DEB;RPM;TGZ") # add a test to make sure symbols are exported from a shared library # for MSVC compilers CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS property is used add_RunCMake_test(AutoExportDll) + +if(CMake_TEST_ANDROID_NDK OR CMake_TEST_ANDROID_STANDALONE_TOOLCHAIN) + if(NOT "${CMAKE_GENERATOR}" MATCHES "Make|Ninja") + message(FATAL_ERROR "Android tests supported only by Makefile and Ninja generators") + endif() + foreach(v TEST_ANDROID_NDK TEST_ANDROID_STANDALONE_TOOLCHAIN) + if(CMake_${v}) + string(REPLACE ";" "|" ${v} "${CMake_${v}}") + list(APPEND Android_ARGS "-D${v}=${${v}}") + endif() + endforeach() + + add_RunCMake_test(Android) + + # This test can take a very long time due to lots of combinations. + # Use a long default timeout and provide an option to customize it. + if(NOT DEFINED CMake_TEST_ANDROID_TIMEOUT) + set(CMake_TEST_ANDROID_TIMEOUT 3000) + endif() + set_property(TEST RunCMake.Android PROPERTY TIMEOUT ${CMake_TEST_ANDROID_TIMEOUT}) +endif() https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6b84df8da98169af43d4173dfbd1dedf5979dcb2 commit 6b84df8da98169af43d4173dfbd1dedf5979dcb2 Author: Brad King AuthorDate: Mon Jun 20 15:48:12 2016 -0400 Commit: Brad King CommitDate: Tue Aug 23 12:53:10 2016 -0400 Help: Document cross compiling for Android CMake now supports cross compiling for Android using the NDK or a standalone toolchain. Document the associated variables and how how to write toolchain files for Android. diff --git a/Help/manual/cmake-toolchains.7.rst b/Help/manual/cmake-toolchains.7.rst index 390220c..74eab2d 100644 --- a/Help/manual/cmake-toolchains.7.rst +++ b/Help/manual/cmake-toolchains.7.rst @@ -290,12 +290,206 @@ Windows Store may look like this: set(CMAKE_SYSTEM_NAME WindowsStore) set(CMAKE_SYSTEM_VERSION 8.1) -Cross Compiling using NVIDIA Nsight Tegra ------------------------------------------ +.. _`Cross Compiling for Android`: -A toolchain file to configure a Visual Studio generator to -build using NVIDIA Nsight Tegra targeting Android may look -like this: +Cross Compiling for Android +--------------------------- + +A toolchain file may configure cross-compiling for Android by setting the +:variable:`CMAKE_SYSTEM_NAME` variable to ``Android``. Further configuration +is specific to the Android development environment to be used. + +For :ref:`Visual Studio Generators`, CMake expects :ref:`NVIDIA Nsight Tegra +Visual Studio Edition ` to be installed. See that section for further +configuration details. + +For :ref:`Makefile Generators` and the :generator:`Ninja` generator, +CMake expects one of these environments: + +* :ref:`NDK ` +* :ref:`Standalone Toolchain ` + +CMake uses the following steps to select one of the environments: + +* If the :variable:`CMAKE_ANDROID_NDK` variable is set, the NDK at the + specified location will be used. + +* Else, if the :variable:`CMAKE_ANDROID_STANDALONE_TOOLCHAIN` variable + is set, the Standalone Toolchain at the specified location will be used. + +* Else, if the :variable:`CMAKE_SYSROOT` variable is set to a directory + of the form ``/platforms/android-/arch-``, the ```` + part will be used as the value of :variable:`CMAKE_ANDROID_NDK` and the + NDK will be used. + +* Else, if the :variable:`CMAKE_SYSROOT` variable is set to a directory of the + form ``/sysroot``, the ```` part + will be used as the value of :variable:`CMAKE_ANDROID_STANDALONE_TOOLCHAIN` + and the Standalone Toolchain will be used. + +* Else, if a cmake variable ``ANDROID_NDK`` is set it will be used + as the value of :variable:`CMAKE_ANDROID_NDK`, and the NDK will be used. + +* Else, if a cmake variable ``ANDROID_STANDALONE_TOOLCHAIN`` is set, it will be + used as the value of :variable:`CMAKE_ANDROID_STANDALONE_TOOLCHAIN`, and the + Standalone Toolchain will be used. + +* Else, if an environment variable ``ANDROID_NDK_ROOT`` or + ``ANDROID_NDK`` is set, it will be used as the value of + :variable:`CMAKE_ANDROID_NDK`, and the NDK will be used. + +* Else, if an environment variable ``ANDROID_STANDALONE_TOOLCHAIN`` is + set then it will be used as the value of + :variable:`CMAKE_ANDROID_STANDALONE_TOOLCHAIN`, and the Standalone + Toolchain will be used. + +* Else, an error diagnostic will be issued that neither the NDK or + Standalone Toolchain can be found. + +.. _`Cross Compiling for Android with the NDK`: + +Cross Compiling for Android with the NDK +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A toolchain file may configure :ref:`Makefile Generators` or the +:generator:`Ninja` generator to target Android for cross-compiling. + +Configure use of an Android NDK with the following variables: + +:variable:`CMAKE_SYSTEM_NAME` + Set to ``Android``. Must be specified to enable cross compiling + for Android. + +:variable:`CMAKE_SYSTEM_VERSION` + Set to the Android API level. If not specified, the value is + determined as follows: + + * If the :variable:`CMAKE_ANDROID_API` variable is set, its value + is used as the API level. + * If the :variable:`CMAKE_SYSROOT` variable is set, the API level is + detected from the NDK directory structure containing the sysroot. + * Otherwise, the latest API level available in the NDK is used. + +:variable:`CMAKE_ANDROID_ARCH_ABI` + Set to the Android ABI (architecture). If not specified, this + variable will default to ``armeabi``. + The :variable:`CMAKE_ANDROID_ARCH` variable will be computed + from ``CMAKE_ANDROID_ARCH_ABI`` automatically. + Also see the :variable:`CMAKE_ANDROID_ARM_MODE` and + :variable:`CMAKE_ANDROID_ARM_NEON` variables. + +:variable:`CMAKE_ANDROID_NDK` + Set to the absolute path to the Android NDK root directory. + A ``${CMAKE_ANDROID_NDK}/platforms`` directory must exist. + If not specified, a default for this variable will be chosen + as specified :ref:`above `. + +:variable:`CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION` + Set to the version of the NDK toolchain to be selected as the compiler. + If not specified, the latest available GCC toolchain will be used. + +:variable:`CMAKE_ANDROID_STL_TYPE` + Set to specify which C++ standard library to use. If not specified, + a default will be selected as described in the variable documentation. + +The following variables will be computed and provided automatically: + +:variable:`CMAKE__ANDROID_TOOLCHAIN_PREFIX` + The absolute path prefix to the binutils in the NDK toolchain. + +:variable:`CMAKE__ANDROID_TOOLCHAIN_SUFFIX` + The host platform suffix of the binutils in the NDK toolchain. + + +For example, a toolchain file might contain: + +.. code-block:: cmake + + set(CMAKE_SYSTEM_NAME Android) + set(CMAKE_SYSTEM_VERSION 21) # API level + set(CMAKE_ANDROID_ARCH_ABI arm64-v8a) + set(CMAKE_ANDROID_NDK /path/to/android-ndk) + set(CMAKE_ANDROID_STL_TYPE gnustl_static) + +Alternatively one may specify the values without a toolchain file: + +.. code-block:: console + + $ cmake ../src \ + -DCMAKE_SYSTEM_NAME=Android \ + -DCMAKE_SYSTEM_VERSION=21 \ + -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \ + -DCMAKE_ANDROID_NDK=/path/to/android-ndk \ + -DCMAKE_ANDROID_STL_TYPE=gnustl_static + +.. _`Cross Compiling for Android with a Standalone Toolchain`: + +Cross Compiling for Android with a Standalone Toolchain +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A toolchain file may configure :ref:`Makefile Generators` or the +:generator:`Ninja` generator to target Android for cross-compiling +using a standalone toolchain. + +Configure use of an Android standalone toolchain with the following variables: + +:variable:`CMAKE_SYSTEM_NAME` + Set to ``Android``. Must be specified to enable cross compiling + for Android. + +:variable:`CMAKE_ANDROID_STANDALONE_TOOLCHAIN` + Set to the absolute path to the standalone toolchain root directory. + A ``${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/sysroot`` directory + must exist. + If not specified, a default for this variable will be chosen + as specified :ref:`above `. + +:variable:`CMAKE_ANDROID_ARM_MODE` + When the standalone toolchain targets ARM, optionally set this to ``ON`` + to target 32-bit ARM instead of 16-bit Thumb. + See variable documentation for details. + +:variable:`CMAKE_ANDROID_ARM_NEON` + When the standalone toolchain targets ARM v7, optionally set thisto ``ON`` + to target ARM NEON devices. See variable documentation for details. + +The following variables will be computed and provided automatically: + +:variable:`CMAKE_SYSTEM_VERSION` + The Android API level detected from the standalone toolchain. + +:variable:`CMAKE_ANDROID_ARCH_ABI` + The Android ABI detected from the standalone toolchain. + +:variable:`CMAKE__ANDROID_TOOLCHAIN_PREFIX` + The absolute path prefix to the binutils in the standalone toolchain. + +:variable:`CMAKE__ANDROID_TOOLCHAIN_SUFFIX` + The host platform suffix of the binutils in the standalone toolchain. + +For example, a toolchain file might contain: + +.. code-block:: cmake + + set(CMAKE_SYSTEM_NAME Android) + set(CMAKE_ANDROID_STANDALONE_TOOLCHAIN /path/to/android-toolchain) + +Alternatively one may specify the values without a toolchain file: + +.. code-block:: console + + $ cmake ../src \ + -DCMAKE_SYSTEM_NAME=Android \ + -DCMAKE_ANDROID_STANDALONE_TOOLCHAIN=/path/to/android-toolchain + +.. _`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio Edition`: + +Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio Edition +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A toolchain file to configure one of the :ref:`Visual Studio Generators` +to build using NVIDIA Nsight Tegra targeting Android may look like this: .. code-block:: cmake diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 1138b82..cdce6f6 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -225,6 +225,9 @@ Variables that Control the Build /variable/CMAKE_ANDROID_API /variable/CMAKE_ANDROID_API_MIN /variable/CMAKE_ANDROID_ARCH + /variable/CMAKE_ANDROID_ARCH_ABI + /variable/CMAKE_ANDROID_ARM_MODE + /variable/CMAKE_ANDROID_ARM_NEON /variable/CMAKE_ANDROID_ASSETS_DIRECTORIES /variable/CMAKE_ANDROID_GUI /variable/CMAKE_ANDROID_JAR_DEPENDENCIES @@ -232,11 +235,14 @@ Variables that Control the Build /variable/CMAKE_ANDROID_JAVA_SOURCE_DIR /variable/CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES /variable/CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES + /variable/CMAKE_ANDROID_NDK + /variable/CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION /variable/CMAKE_ANDROID_PROCESS_MAX /variable/CMAKE_ANDROID_PROGUARD /variable/CMAKE_ANDROID_PROGUARD_CONFIG_PATH /variable/CMAKE_ANDROID_SECURE_PROPS_PATH /variable/CMAKE_ANDROID_SKIP_ANT_STEP + /variable/CMAKE_ANDROID_STANDALONE_TOOLCHAIN /variable/CMAKE_ANDROID_STL_TYPE /variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY /variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY_CONFIG @@ -337,6 +343,8 @@ Variables for Languages /variable/CMAKE_Fortran_MODDIR_FLAG /variable/CMAKE_Fortran_MODOUT_FLAG /variable/CMAKE_INTERNAL_PLATFORM_ABI + /variable/CMAKE_LANG_ANDROID_TOOLCHAIN_PREFIX + /variable/CMAKE_LANG_ANDROID_TOOLCHAIN_SUFFIX /variable/CMAKE_LANG_ARCHIVE_APPEND /variable/CMAKE_LANG_ARCHIVE_CREATE /variable/CMAKE_LANG_ARCHIVE_FINISH diff --git a/Help/prop_tgt/ANDROID_API.rst b/Help/prop_tgt/ANDROID_API.rst index 714ad58..63464d7 100644 --- a/Help/prop_tgt/ANDROID_API.rst +++ b/Help/prop_tgt/ANDROID_API.rst @@ -1,7 +1,8 @@ ANDROID_API ----------- -Set the Android Target API version (e.g. ``15``). The version number -must be a positive decimal integer. This property is initialized by -the value of the :variable:`CMAKE_ANDROID_API` variable if it is set -when a target is created. +When :ref:`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio +Edition`, this property sets the Android target API version (e.g. ``15``). +The version number must be a positive decimal integer. This property is +initialized by the value of the :variable:`CMAKE_ANDROID_API` variable if +it is set when a target is created. diff --git a/Help/prop_tgt/ANDROID_ARCH.rst b/Help/prop_tgt/ANDROID_ARCH.rst index 5477fb5..3e07e5a 100644 --- a/Help/prop_tgt/ANDROID_ARCH.rst +++ b/Help/prop_tgt/ANDROID_ARCH.rst @@ -1,7 +1,8 @@ ANDROID_ARCH ------------ -Set the Android target architecture. +When :ref:`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio +Edition`, this property sets the Android target architecture. This is a string property that could be set to the one of the following values: diff --git a/Help/prop_tgt/ANDROID_GUI.rst b/Help/prop_tgt/ANDROID_GUI.rst index abdba7a..92e2041 100644 --- a/Help/prop_tgt/ANDROID_GUI.rst +++ b/Help/prop_tgt/ANDROID_GUI.rst @@ -1,7 +1,9 @@ ANDROID_GUI ----------- -Build an executable as an application package on Android. +When :ref:`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio +Edition`, this property specifies whether to build an executable as an +application package on Android. When this property is set to true the executable when built for Android will be created as an application package. This property is initialized diff --git a/Help/prop_tgt/ANDROID_STL_TYPE.rst b/Help/prop_tgt/ANDROID_STL_TYPE.rst index 7256e26..386e96e 100644 --- a/Help/prop_tgt/ANDROID_STL_TYPE.rst +++ b/Help/prop_tgt/ANDROID_STL_TYPE.rst @@ -1,15 +1,27 @@ ANDROID_STL_TYPE ---------------- -Set the Android property that defines the type of STL support for the project. +When :ref:`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio +Edition`, this property specifies the type of STL support for the project. This is a string property that could set to the one of the following values: -``none`` e.g. "No C++ Support" -``system`` e.g. "Minimal C++ without STL" -``gabi++_static`` e.g. "GAbi++ Static" -``gabi++_shared`` e.g. "GAbi++ Shared" -``gnustl_static`` e.g. "GNU libstdc++ Static" -``gnustl_shared`` e.g. "GNU libstdc++ Shared" -``stlport_static`` e.g. "STLport Static" -``stlport_shared`` e.g. "STLport Shared" + +``none`` + No C++ Support +``system`` + Minimal C++ without STL +``gabi++_static`` + GAbi++ Static +``gabi++_shared`` + GAbi++ Shared +``gnustl_static`` + GNU libstdc++ Static +``gnustl_shared`` + GNU libstdc++ Shared +``stlport_static`` + STLport Static +``stlport_shared`` + STLport Shared + This property is initialized by the value of the -variable:`CMAKE_ANDROID_STL_TYPE` variable if it is set when a target is created. +:variable:`CMAKE_ANDROID_STL_TYPE` variable if it is set when a target is +created. diff --git a/Help/release/dev/android-platform-modules.rst b/Help/release/dev/android-platform-modules.rst new file mode 100644 index 0000000..79ae992 --- /dev/null +++ b/Help/release/dev/android-platform-modules.rst @@ -0,0 +1,5 @@ +android-platform-modules +------------------------ + +* CMake now supports :ref:`Cross Compiling for Android` with simple + toolchain files. diff --git a/Help/variable/CMAKE_ANDROID_API.rst b/Help/variable/CMAKE_ANDROID_API.rst index c8264e0..c07a05a 100644 --- a/Help/variable/CMAKE_ANDROID_API.rst +++ b/Help/variable/CMAKE_ANDROID_API.rst @@ -1,5 +1,11 @@ CMAKE_ANDROID_API ----------------- -Default value for the :prop_tgt:`ANDROID_API` target property. -See that target property for additional information. +When :ref:`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio +Edition`, this variable may be set to specify the default value for the +:prop_tgt:`ANDROID_API` target property. See that target property for +additional information. + +Otherwise, when :ref:`Cross Compiling for Android`, this variable provides +the Android API version number targeted. This will be the same value as +the :variable:`CMAKE_SYSTEM_VERSION` variable for ``Android`` platforms. diff --git a/Help/variable/CMAKE_ANDROID_ARCH.rst b/Help/variable/CMAKE_ANDROID_ARCH.rst index 8fbb46d..b91ca57 100644 --- a/Help/variable/CMAKE_ANDROID_ARCH.rst +++ b/Help/variable/CMAKE_ANDROID_ARCH.rst @@ -1,5 +1,19 @@ CMAKE_ANDROID_ARCH ------------------ -Default value for the :prop_tgt:`ANDROID_ARCH` target property. -See that target property for additional information. +When :ref:`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio +Edition`, this variable may be set to specify the default value for the +:prop_tgt:`ANDROID_ARCH` target property. See that target property for +additional information. + +Otherwise, when :ref:`Cross Compiling for Android`, this variable provides +the name of the Android architecture corresponding to the value of the +:variable:`CMAKE_ANDROID_ARCH_ABI` variable. The architecture name +may be one of: + +* ``arm`` +* ``arm64`` +* ``mips`` +* ``mips64`` +* ``x86`` +* ``x86_64`` diff --git a/Help/variable/CMAKE_ANDROID_ARCH_ABI.rst b/Help/variable/CMAKE_ANDROID_ARCH_ABI.rst new file mode 100644 index 0000000..0a3ed3c --- /dev/null +++ b/Help/variable/CMAKE_ANDROID_ARCH_ABI.rst @@ -0,0 +1,17 @@ +CMAKE_ANDROID_ARCH_ABI +---------------------- + +When :ref:`Cross Compiling for Android`, this variable specifies the +target architecture and ABI to be used. Valid values are: + +* ``arm64-v8a`` +* ``armeabi-v7a`` +* ``armeabi-v6`` +* ``armeabi`` +* ``mips`` +* ``mips64`` +* ``x86`` +* ``x86_64`` + +See also the :variable:`CMAKE_ANDROID_ARM_MODE` and +:variable:`CMAKE_ANDROID_ARM_NEON` variables. diff --git a/Help/variable/CMAKE_ANDROID_ARM_MODE.rst b/Help/variable/CMAKE_ANDROID_ARM_MODE.rst new file mode 100644 index 0000000..ad3c37c --- /dev/null +++ b/Help/variable/CMAKE_ANDROID_ARM_MODE.rst @@ -0,0 +1,7 @@ +CMAKE_ANDROID_ARM_MODE +---------------------- + +When :ref:`Cross Compiling for Android` and :variable:`CMAKE_ANDROID_ARCH_ABI` +is set to one of the ``armeabi`` architectures, set ``CMAKE_ANDROID_ARM_MODE`` +to ``ON`` to target 32-bit ARM processors (``-marm``). Otherwise, the +default is to target the 16-bit Thumb processors (``-mthumb``). diff --git a/Help/variable/CMAKE_ANDROID_ARM_NEON.rst b/Help/variable/CMAKE_ANDROID_ARM_NEON.rst new file mode 100644 index 0000000..4b7ae03 --- /dev/null +++ b/Help/variable/CMAKE_ANDROID_ARM_NEON.rst @@ -0,0 +1,6 @@ +CMAKE_ANDROID_ARM_NEON +---------------------- + +When :ref:`Cross Compiling for Android` and :variable:`CMAKE_ANDROID_ARCH_ABI` +is set to ``armeabi-v7a`` set ``CMAKE_ANDROID_ARM_NEON`` to ``ON`` to target +ARM NEON devices. diff --git a/Help/variable/CMAKE_ANDROID_NDK.rst b/Help/variable/CMAKE_ANDROID_NDK.rst new file mode 100644 index 0000000..d241dd0 --- /dev/null +++ b/Help/variable/CMAKE_ANDROID_NDK.rst @@ -0,0 +1,7 @@ +CMAKE_ANDROID_NDK +----------------- + +When :ref:`Cross Compiling for Android with the NDK`, this variable holds +the absolute path to the root directory of the NDK. The directory must +contain a ``platforms`` subdirectory holding the ``android-`` +directories. diff --git a/Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION.rst b/Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION.rst new file mode 100644 index 0000000..dff7d64 --- /dev/null +++ b/Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION.rst @@ -0,0 +1,13 @@ +CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION +----------------------------------- + +When :ref:`Cross Compiling for Android with the NDK`, this variable +may be set to specify the version of the toolchain to be used +as the compiler. The variable must be set to one of these forms: + +* ``.``: GCC of specified version +* ``clang.``: Clang of specified version +* ``clang``: Clang of most recent available version + +A toolchain of the requested version will be selected automatically to +match the ABI named in the :variable:`CMAKE_ANDROID_ARCH_ABI` variable. diff --git a/Help/variable/CMAKE_ANDROID_STANDALONE_TOOLCHAIN.rst b/Help/variable/CMAKE_ANDROID_STANDALONE_TOOLCHAIN.rst new file mode 100644 index 0000000..ea62cab --- /dev/null +++ b/Help/variable/CMAKE_ANDROID_STANDALONE_TOOLCHAIN.rst @@ -0,0 +1,6 @@ +CMAKE_ANDROID_STANDALONE_TOOLCHAIN +---------------------------------- + +When :ref:`Cross Compiling for Android with a Standalone Toolchain`, this +variable holds the absolute path to the root directory of the toolchain. +The specified directory must contain a ``sysroot`` subdirectory. diff --git a/Help/variable/CMAKE_ANDROID_STL_TYPE.rst b/Help/variable/CMAKE_ANDROID_STL_TYPE.rst index 766b2c8..cfb76aa 100644 --- a/Help/variable/CMAKE_ANDROID_STL_TYPE.rst +++ b/Help/variable/CMAKE_ANDROID_STL_TYPE.rst @@ -1,5 +1,36 @@ CMAKE_ANDROID_STL_TYPE ---------------------- -Default value for the :prop_tgt:`ANDROID_STL_TYPE` target property. -See that target property for additional information. +When :ref:`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio +Edition`, this variable may be set to specify the default value for the +:prop_tgt:`ANDROID_STL_TYPE` target property. See that target property +for additional information. + +When :ref:`Cross Compiling for Android with the NDK`, this variable may be +set to specify the STL variant to be used. The value may be one of: + +``none`` + No C++ Support +``system`` + Minimal C++ without STL +``gabi++_static`` + GAbi++ Static +``gabi++_shared`` + GAbi++ Shared +``gnustl_static`` + GNU libstdc++ Static +``gnustl_shared`` + GNU libstdc++ Shared +``c++_static`` + LLVM libc++ Static +``c++_shared`` + LLVM libc++ Shared +``stlport_static`` + STLport Static +``stlport_shared`` + STLport Shared + +The default value is ``gnustl_static``. Note that this default differs from +the native NDK build system because CMake may be used to build projects for +Android that are not natively implemented for it and use the C++ standard +library. diff --git a/Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_PREFIX.rst b/Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_PREFIX.rst new file mode 100644 index 0000000..b51422f --- /dev/null +++ b/Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_PREFIX.rst @@ -0,0 +1,11 @@ +CMAKE__ANDROID_TOOLCHAIN_PREFIX +------------------------------------- + +When :ref:`Cross Compiling for Android` this variable contains the absolute +path prefixing the toolchain GNU compiler and its binutils. + +See also :variable:`CMAKE__ANDROID_TOOLCHAIN_SUFFIX`. + +For example, the path to the linker is:: + + ${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}ld${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX} diff --git a/Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_SUFFIX.rst b/Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_SUFFIX.rst new file mode 100644 index 0000000..a4af640 --- /dev/null +++ b/Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_SUFFIX.rst @@ -0,0 +1,7 @@ +CMAKE__ANDROID_TOOLCHAIN_SUFFIX +------------------------------------- + +When :ref:`Cross Compiling for Android` this variable contains the +host platform suffix of the toolchain GNU compiler and its binutils. + +See also :variable:`CMAKE__ANDROID_TOOLCHAIN_PREFIX`. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d7d4083025f3007b862dd500c8f5fc64e105055b commit d7d4083025f3007b862dd500c8f5fc64e105055b Author: Brad King AuthorDate: Thu Jun 2 15:19:20 2016 -0400 Commit: Brad King CommitDate: Tue Aug 23 12:53:10 2016 -0400 Android: Select the STL type for NDK builds Populate standard include directories and link libraries for the platform. Select the STL corresponding to CMAKE_ANDROID_STL_TYPE and matching the current ABI and toolchain to be used. Refer to the NDK sources/cxx-stl/*/Android.mk files for the needed file locations. diff --git a/Modules/Platform/Android-Common.cmake b/Modules/Platform/Android-Common.cmake index e77d2d8..6e86c10 100644 --- a/Modules/Platform/Android-Common.cmake +++ b/Modules/Platform/Android-Common.cmake @@ -17,6 +17,92 @@ if(__ANDROID_COMPILER_COMMON) endif() set(__ANDROID_COMPILER_COMMON 1) +if(CMAKE_ANDROID_NDK) + # /build/core/definitions.mk + + set(_ANDROID_STL_TYPES + none + system + c++_static + c++_shared + gabi++_static + gabi++_shared + gnustl_static + gnustl_shared + stlport_static + stlport_shared + ) + + if(CMAKE_ANDROID_STL_TYPE) + list(FIND _ANDROID_STL_TYPES "${CMAKE_ANDROID_STL_TYPE}" _ANDROID_STL_TYPE_FOUND) + if(_ANDROID_STL_TYPE_FOUND EQUAL -1) + string(REPLACE ";" "\n " _msg ";${_ANDROID_STL_TYPES}") + message(FATAL_ERROR + "The CMAKE_ANDROID_STL_TYPE '${CMAKE_ANDROID_STL_TYPE}' is not one of the allowed values:${_msg}\n" + ) + endif() + unset(_ANDROID_STL_TYPE_FOUND) + else() + set(CMAKE_ANDROID_STL_TYPE "gnustl_static") + endif() + + unset(_ANDROID_STL_TYPES) + + # Forward Android-specific platform variables to try_compile projects. + list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES + CMAKE_ANDROID_STL_TYPE + ) +endif() + +if(CMAKE_ANDROID_STL_TYPE) + if(CMAKE_ANDROID_NDK) + + macro(__android_stl_inc lang dir req) + if(EXISTS "${dir}") + list(APPEND CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES "${dir}") + elseif(${req}) + message(FATAL_ERROR + "Android: STL '${CMAKE_ANDROID_STL_TYPE}' include directory not found:\n" + " ${dir}" + ) + endif() + endmacro() + + macro(__android_stl_lib lang lib req) + if(CMAKE_ANDROID_ARCH_ABI MATCHES "^armeabi" AND NOT CMAKE_ANDROID_ARM_MODE) + get_filename_component(_ANDROID_STL_LIBDIR "${lib}" DIRECTORY) + get_filename_component(_ANDROID_STL_LIBNAME "${lib}" NAME) + set(_ANDROID_STL_LIBTHUMB "${_ANDROID_STL_LIBDIR}/thumb/${_ANDROID_STL_LIBNAME}") + unset(_ANDROID_STL_LIBDIR) + unset(_ANDROID_STL_LIBNAME) + else() + set(_ANDROID_STL_LIBTHUMB "") + endif() + + if(_ANDROID_STL_LIBTHUMB AND EXISTS "${_ANDROID_STL_LIBTHUMB}") + string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " \"${_ANDROID_STL_LIBTHUMB}\"") + elseif(EXISTS "${lib}") + string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " \"${lib}\"") + elseif(${req}) + message(FATAL_ERROR + "Android: STL '${CMAKE_ANDROID_STL_TYPE}' library file not found:\n" + " ${lib}" + ) + endif() + + unset(_ANDROID_STL_LIBTHUMB) + endmacro() + + include(Platform/Android/ndk-stl-${CMAKE_ANDROID_STL_TYPE}) + else() + macro(__android_stl lang) + endmacro() + endif() +else() + macro(__android_stl lang) + endmacro() +endif() + # The NDK toolchain configuration files at: # # /[build/core/]toolchains/*/setup.mk @@ -49,4 +135,24 @@ macro(__android_compiler_common lang) string(APPEND CMAKE_${t}_LINKER_FLAGS_INIT " ${_ANDROID_ABI_INIT_LDFLAGS}") endforeach() endif() + + if(DEFINED _ANDROID_STL_EXCEPTIONS) + if(_ANDROID_STL_EXCEPTIONS) + string(APPEND CMAKE_${lang}_FLAGS_INIT " -fexceptions") + else() + string(APPEND CMAKE_${lang}_FLAGS_INIT " -fno-exceptions") + endif() + endif() + + if("x${lang}" STREQUAL "xCXX" AND DEFINED _ANDROID_STL_RTTI) + if(_ANDROID_STL_RTTI) + string(APPEND CMAKE_${lang}_FLAGS_INIT " -frtti") + else() + string(APPEND CMAKE_${lang}_FLAGS_INIT " -fno-rtti") + endif() + endif() + + if("x${lang}" STREQUAL "xCXX") + __android_stl(CXX) + endif() endmacro() diff --git a/Modules/Platform/Android/ndk-stl-c++.cmake b/Modules/Platform/Android/ndk-stl-c++.cmake new file mode 100644 index 0000000..14748a1 --- /dev/null +++ b/Modules/Platform/Android/ndk-stl-c++.cmake @@ -0,0 +1,13 @@ +# /sources/cxx-stl/llvm-libc++/Android.mk +set(_ANDROID_STL_RTTI 1) +set(_ANDROID_STL_EXCEPTIONS 1) +macro(__android_stl_cxx lang filename) + # Add the include directory. + __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libcxx/include" 1) + + # Add a secondary include directory if it exists. + __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/android/support/include" 0) + + # Add the library file. + __android_stl_lib(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/${CMAKE_ANDROID_ARCH_ABI}/${filename}" 1) +endmacro() diff --git a/Modules/Platform/Android/ndk-stl-c++_shared.cmake b/Modules/Platform/Android/ndk-stl-c++_shared.cmake new file mode 100644 index 0000000..f585adb --- /dev/null +++ b/Modules/Platform/Android/ndk-stl-c++_shared.cmake @@ -0,0 +1,4 @@ +include(Platform/Android/ndk-stl-c++) +macro(__android_stl lang) + __android_stl_cxx(${lang} libc++_shared.so) +endmacro() diff --git a/Modules/Platform/Android/ndk-stl-c++_static.cmake b/Modules/Platform/Android/ndk-stl-c++_static.cmake new file mode 100644 index 0000000..8e562f8 --- /dev/null +++ b/Modules/Platform/Android/ndk-stl-c++_static.cmake @@ -0,0 +1,6 @@ +include(Platform/Android/ndk-stl-c++) +macro(__android_stl lang) + __android_stl_cxx(${lang} libc++_static.a) + __android_stl_lib(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/${CMAKE_ANDROID_ARCH_ABI}/libc++abi.a" 0) + __android_stl_lib(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/${CMAKE_ANDROID_ARCH_ABI}/libandroid_support.a" 0) +endmacro() diff --git a/Modules/Platform/Android/ndk-stl-gabi++.cmake b/Modules/Platform/Android/ndk-stl-gabi++.cmake new file mode 100644 index 0000000..850a47a --- /dev/null +++ b/Modules/Platform/Android/ndk-stl-gabi++.cmake @@ -0,0 +1,7 @@ +# /sources/cxx-stl/gabi++/Android.mk +set(_ANDROID_STL_RTTI 1) +set(_ANDROID_STL_EXCEPTIONS 1) +macro(__android_stl_gabixx lang filename) + __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/gabi++/include" 1) + __android_stl_lib(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/gabi++/libs/${CMAKE_ANDROID_ARCH_ABI}/${filename}" 1) +endmacro() diff --git a/Modules/Platform/Android/ndk-stl-gabi++_shared.cmake b/Modules/Platform/Android/ndk-stl-gabi++_shared.cmake new file mode 100644 index 0000000..314c1e0 --- /dev/null +++ b/Modules/Platform/Android/ndk-stl-gabi++_shared.cmake @@ -0,0 +1,4 @@ +include(Platform/Android/ndk-stl-gabi++) +macro(__android_stl lang) + __android_stl_gabixx(${lang} libgabi++_shared.so) +endmacro() diff --git a/Modules/Platform/Android/ndk-stl-gabi++_static.cmake b/Modules/Platform/Android/ndk-stl-gabi++_static.cmake new file mode 100644 index 0000000..f4a1d3c --- /dev/null +++ b/Modules/Platform/Android/ndk-stl-gabi++_static.cmake @@ -0,0 +1,4 @@ +include(Platform/Android/ndk-stl-gabi++) +macro(__android_stl lang) + __android_stl_gabixx(${lang} libgabi++_static.a) +endmacro() diff --git a/Modules/Platform/Android/ndk-stl-gnustl.cmake b/Modules/Platform/Android/ndk-stl-gnustl.cmake new file mode 100644 index 0000000..b3226ee --- /dev/null +++ b/Modules/Platform/Android/ndk-stl-gnustl.cmake @@ -0,0 +1,9 @@ +# /sources/cxx-stl/gnu-libstdc++/Android.mk +set(_ANDROID_STL_RTTI 1) +set(_ANDROID_STL_EXCEPTIONS 1) +macro(__android_stl_gnustl lang filename) + __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${CMAKE_${lang}_ANDROID_TOOLCHAIN_VERSION}/include" 1) + __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${CMAKE_${lang}_ANDROID_TOOLCHAIN_VERSION}/libs/${CMAKE_ANDROID_ARCH_ABI}/include" 1) + __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${CMAKE_${lang}_ANDROID_TOOLCHAIN_VERSION}/include/backward" 1) + __android_stl_lib(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${CMAKE_${lang}_ANDROID_TOOLCHAIN_VERSION}/libs/${CMAKE_ANDROID_ARCH_ABI}/${filename}" 1) +endmacro() diff --git a/Modules/Platform/Android/ndk-stl-gnustl_shared.cmake b/Modules/Platform/Android/ndk-stl-gnustl_shared.cmake new file mode 100644 index 0000000..f20cc4d --- /dev/null +++ b/Modules/Platform/Android/ndk-stl-gnustl_shared.cmake @@ -0,0 +1,4 @@ +include(Platform/Android/ndk-stl-gnustl) +macro(__android_stl lang) + __android_stl_gnustl(${lang} libgnustl_shared.so) +endmacro() diff --git a/Modules/Platform/Android/ndk-stl-gnustl_static.cmake b/Modules/Platform/Android/ndk-stl-gnustl_static.cmake new file mode 100644 index 0000000..af4cc2a --- /dev/null +++ b/Modules/Platform/Android/ndk-stl-gnustl_static.cmake @@ -0,0 +1,4 @@ +include(Platform/Android/ndk-stl-gnustl) +macro(__android_stl lang) + __android_stl_gnustl(${lang} libgnustl_static.a) +endmacro() diff --git a/Modules/Platform/Android/ndk-stl-none.cmake b/Modules/Platform/Android/ndk-stl-none.cmake new file mode 100644 index 0000000..9049c91 --- /dev/null +++ b/Modules/Platform/Android/ndk-stl-none.cmake @@ -0,0 +1,2 @@ +macro(__android_stl lang) +endmacro() diff --git a/Modules/Platform/Android/ndk-stl-stlport.cmake b/Modules/Platform/Android/ndk-stl-stlport.cmake new file mode 100644 index 0000000..eab6b94 --- /dev/null +++ b/Modules/Platform/Android/ndk-stl-stlport.cmake @@ -0,0 +1,7 @@ +# /sources/cxx-stl/stlport/Android.mk +set(_ANDROID_STL_RTTI 1) +set(_ANDROID_STL_EXCEPTIONS 1) +macro(__android_stl_stlport lang filename) + __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/stlport/stlport" 1) + __android_stl_lib(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/stlport/libs/${CMAKE_ANDROID_ARCH_ABI}/${filename}" 1) +endmacro() diff --git a/Modules/Platform/Android/ndk-stl-stlport_shared.cmake b/Modules/Platform/Android/ndk-stl-stlport_shared.cmake new file mode 100644 index 0000000..2b5846b --- /dev/null +++ b/Modules/Platform/Android/ndk-stl-stlport_shared.cmake @@ -0,0 +1,4 @@ +include(Platform/Android/ndk-stl-stlport) +macro(__android_stl lang) + __android_stl_stlport(${lang} libstlport_shared.so) +endmacro() diff --git a/Modules/Platform/Android/ndk-stl-stlport_static.cmake b/Modules/Platform/Android/ndk-stl-stlport_static.cmake new file mode 100644 index 0000000..bf60307 --- /dev/null +++ b/Modules/Platform/Android/ndk-stl-stlport_static.cmake @@ -0,0 +1,4 @@ +include(Platform/Android/ndk-stl-stlport) +macro(__android_stl lang) + __android_stl_stlport(${lang} libstlport_static.a) +endmacro() diff --git a/Modules/Platform/Android/ndk-stl-system.cmake b/Modules/Platform/Android/ndk-stl-system.cmake new file mode 100644 index 0000000..dd554fe --- /dev/null +++ b/Modules/Platform/Android/ndk-stl-system.cmake @@ -0,0 +1,6 @@ +# /android-ndk-r11c/sources/cxx-stl/system/Android.mk +set(_ANDROID_STL_RTTI 0) +set(_ANDROID_STL_EXCEPTIONS 0) +macro(__android_stl lang) + __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/system/include" 1) +endmacro() https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b22294bc41c3ce62e561c7123c3f489a750dcb66 commit b22294bc41c3ce62e561c7123c3f489a750dcb66 Author: Brad King AuthorDate: Thu Jun 2 15:11:42 2016 -0400 Commit: Brad King CommitDate: Tue Aug 23 12:51:58 2016 -0400 Android: Populate compiler flags for current ABI Initialize the CMAKE_{C,CXX}_FLAGS{,_} cache entries with flags for each ABI as specified by NDK toolchain `setup.mk` files. diff --git a/Modules/Platform/Android-Common.cmake b/Modules/Platform/Android-Common.cmake index 0ef9512..e77d2d8 100644 --- a/Modules/Platform/Android-Common.cmake +++ b/Modules/Platform/Android-Common.cmake @@ -17,5 +17,36 @@ if(__ANDROID_COMPILER_COMMON) endif() set(__ANDROID_COMPILER_COMMON 1) +# The NDK toolchain configuration files at: +# +# /[build/core/]toolchains/*/setup.mk +# +# contain logic to set TARGET_CFLAGS and TARGET_LDFLAGS (and debug/release +# variants) to tell their build system what flags to pass for each ABI. +# We need to produce the same flags here to produce compatible binaries. +# We initialize these variables here and set them in the compiler-specific +# modules that include this one. Then we use them in the macro below when +# it is called. +set(_ANDROID_ABI_INIT_CFLAGS "") +set(_ANDROID_ABI_INIT_CFLAGS_DEBUG "") +set(_ANDROID_ABI_INIT_CFLAGS_RELEASE "") +set(_ANDROID_ABI_INIT_LDFLAGS "") + macro(__android_compiler_common lang) + if(_ANDROID_ABI_INIT_CFLAGS) + string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_ANDROID_ABI_INIT_CFLAGS}") + endif() + if(_ANDROID_ABI_INIT_CFLAGS_DEBUG) + string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " ${_ANDROID_ABI_INIT_CFLAGS_DEBUG}") + endif() + if(_ANDROID_ABI_INIT_CFLAGS_RELEASE) + string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " ${_ANDROID_ABI_INIT_CFLAGS_RELEASE}") + string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " ${_ANDROID_ABI_INIT_CFLAGS_RELEASE}") + string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " ${_ANDROID_ABI_INIT_CFLAGS_RELEASE}") + endif() + if(_ANDROID_ABI_INIT_LDFLAGS) + foreach(t EXE SHARED MODULE) + string(APPEND CMAKE_${t}_LINKER_FLAGS_INIT " ${_ANDROID_ABI_INIT_LDFLAGS}") + endforeach() + endif() endmacro() diff --git a/Modules/Platform/Android/abi-arm64-v8a-Clang.cmake b/Modules/Platform/Android/abi-arm64-v8a-Clang.cmake index 60fe3e5..3ff1fe5 100644 --- a/Modules/Platform/Android/abi-arm64-v8a-Clang.cmake +++ b/Modules/Platform/Android/abi-arm64-v8a-Clang.cmake @@ -1,3 +1,8 @@ # /build/core/toolchains/aarch64-linux-android-clang/setup.mk set(_ANDROID_ABI_CLANG_TARGET "aarch64-none-linux-android") + +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -fpic" + ) + include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-arm64-v8a-GNU.cmake b/Modules/Platform/Android/abi-arm64-v8a-GNU.cmake index a25a0dd..538ec2f 100644 --- a/Modules/Platform/Android/abi-arm64-v8a-GNU.cmake +++ b/Modules/Platform/Android/abi-arm64-v8a-GNU.cmake @@ -1,2 +1,6 @@ # /build/core/toolchains/aarch64-linux-android-4.9/setup.mk +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -fpic" + ) + include(Platform/Android/abi-common-GNU) diff --git a/Modules/Platform/Android/abi-armeabi-Clang.cmake b/Modules/Platform/Android/abi-armeabi-Clang.cmake index eb703f5..4fc3009 100644 --- a/Modules/Platform/Android/abi-armeabi-Clang.cmake +++ b/Modules/Platform/Android/abi-armeabi-Clang.cmake @@ -1,3 +1,20 @@ # /build/core/toolchains/arm-linux-androideabi-clang/setup.mk set(_ANDROID_ABI_CLANG_TARGET "armv5te-none-linux-androideabi") + +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -march=armv5te" + ) + +if(CMAKE_ANDROID_ARM_MODE) + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -marm") +else() + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mthumb") +endif() + +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -msoft-float" + " -mtune=xscale" + " -fpic" + ) + include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-armeabi-GNU.cmake b/Modules/Platform/Android/abi-armeabi-GNU.cmake index d621e72..10cac00 100644 --- a/Modules/Platform/Android/abi-armeabi-GNU.cmake +++ b/Modules/Platform/Android/abi-armeabi-GNU.cmake @@ -1,2 +1,18 @@ # /build/core/toolchains/arm-linux-androideabi-4.9/setup.mk +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -march=armv5te" + ) + +if(CMAKE_ANDROID_ARM_MODE) + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -marm") +else() + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mthumb") +endif() + +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -msoft-float" + " -mtune=xscale" + " -fpic" + ) + include(Platform/Android/abi-common-GNU) diff --git a/Modules/Platform/Android/abi-armeabi-v6-Clang.cmake b/Modules/Platform/Android/abi-armeabi-v6-Clang.cmake index b58b558..15f1d4a 100644 --- a/Modules/Platform/Android/abi-armeabi-v6-Clang.cmake +++ b/Modules/Platform/Android/abi-armeabi-v6-Clang.cmake @@ -1,3 +1,19 @@ # /build/core/toolchains/arm-linux-androideabi-clang/setup.mk set(_ANDROID_ABI_CLANG_TARGET "armv6-none-linux-androideabi") + +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -march=armv6" + ) + +if(CMAKE_ANDROID_ARM_MODE) + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -marm") +else() + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mthumb") +endif() + +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -mfloat-abi=softfp" + " -fpic" + ) + include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-armeabi-v6-GNU.cmake b/Modules/Platform/Android/abi-armeabi-v6-GNU.cmake index d621e72..7492de0 100644 --- a/Modules/Platform/Android/abi-armeabi-v6-GNU.cmake +++ b/Modules/Platform/Android/abi-armeabi-v6-GNU.cmake @@ -1,2 +1,17 @@ # /build/core/toolchains/arm-linux-androideabi-4.9/setup.mk +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -march=armv6" + ) + +if(CMAKE_ANDROID_ARM_MODE) + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -marm") +else() + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mthumb") +endif() + +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -mfloat-abi=softfp" + " -fpic" + ) + include(Platform/Android/abi-common-GNU) diff --git a/Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake b/Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake index e7c311c..3a3efb3 100644 --- a/Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake +++ b/Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake @@ -1,3 +1,29 @@ # /build/core/toolchains/arm-linux-androideabi-clang/setup.mk set(_ANDROID_ABI_CLANG_TARGET "armv7-none-linux-androideabi") + +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -march=armv7-a" + ) + +if(CMAKE_ANDROID_ARM_MODE) + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -marm") +else() + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mthumb") +endif() + +if(CMAKE_ANDROID_ARM_NEON) + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mfpu=neon") +else() + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mfpu=vfpv3-d16") +endif() + +string(APPEND _ANDROID_ABI_INIT_LDFLAGS + " -Wl,--fix-cortex-a8" + ) + +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -mfloat-abi=softfp" + " -fpic" + ) + include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-armeabi-v7a-GNU.cmake b/Modules/Platform/Android/abi-armeabi-v7a-GNU.cmake index d621e72..d27e37e 100644 --- a/Modules/Platform/Android/abi-armeabi-v7a-GNU.cmake +++ b/Modules/Platform/Android/abi-armeabi-v7a-GNU.cmake @@ -1,2 +1,27 @@ # /build/core/toolchains/arm-linux-androideabi-4.9/setup.mk +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -march=armv7-a" + ) + +if(CMAKE_ANDROID_ARM_MODE) + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -marm") +else() + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mthumb") +endif() + +if(CMAKE_ANDROID_ARM_NEON) + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mfpu=neon") +else() + string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mfpu=vfpv3-d16") +endif() + +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -mfloat-abi=softfp" + " -fpic" + ) + +string(APPEND _ANDROID_ABI_INIT_LDFLAGS + " -Wl,--fix-cortex-a8" + ) + include(Platform/Android/abi-common-GNU) diff --git a/Modules/Platform/Android/abi-common-Clang.cmake b/Modules/Platform/Android/abi-common-Clang.cmake index 40d829f..6025170 100644 --- a/Modules/Platform/Android/abi-common-Clang.cmake +++ b/Modules/Platform/Android/abi-common-Clang.cmake @@ -1 +1,6 @@ +string(APPEND _ANDROID_ABI_INIT_CFLAGS + #" -Wno-invalid-command-line-argument" + #" -Wno-unused-command-line-argument" + ) + include(Platform/Android/abi-common) diff --git a/Modules/Platform/Android/abi-common.cmake b/Modules/Platform/Android/abi-common.cmake index e69de29..12d8e5c 100644 --- a/Modules/Platform/Android/abi-common.cmake +++ b/Modules/Platform/Android/abi-common.cmake @@ -0,0 +1,4 @@ +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -funwind-tables" + " -no-canonical-prefixes" + ) diff --git a/Modules/Platform/Android/abi-mips-Clang.cmake b/Modules/Platform/Android/abi-mips-Clang.cmake index 2991a93..bf6b9fc 100644 --- a/Modules/Platform/Android/abi-mips-Clang.cmake +++ b/Modules/Platform/Android/abi-mips-Clang.cmake @@ -1,3 +1,8 @@ # /build/core/toolchains/mipsel-linux-android-clang/setup.mk set(_ANDROID_ABI_CLANG_TARGET "mipsel-none-linux-android") + +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -fpic" + ) + include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-mips-GNU.cmake b/Modules/Platform/Android/abi-mips-GNU.cmake index 675f9ca..d380440 100644 --- a/Modules/Platform/Android/abi-mips-GNU.cmake +++ b/Modules/Platform/Android/abi-mips-GNU.cmake @@ -1,2 +1,6 @@ # /build/core/toolchains/mipsel-linux-android-4.9/setup.mk +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -fpic" + ) + include(Platform/Android/abi-common-GNU) diff --git a/Modules/Platform/Android/abi-mips64-Clang.cmake b/Modules/Platform/Android/abi-mips64-Clang.cmake index 24b8db5..1a94107 100644 --- a/Modules/Platform/Android/abi-mips64-Clang.cmake +++ b/Modules/Platform/Android/abi-mips64-Clang.cmake @@ -1,3 +1,8 @@ # /build/core/toolchains/mips64el-linux-android-clang/setup.mk set(_ANDROID_ABI_CLANG_TARGET "mips64el-none-linux-android") + +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -fpic" + ) + include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-mips64-GNU.cmake b/Modules/Platform/Android/abi-mips64-GNU.cmake index 3f9fbc3..4525d40 100644 --- a/Modules/Platform/Android/abi-mips64-GNU.cmake +++ b/Modules/Platform/Android/abi-mips64-GNU.cmake @@ -1,2 +1,6 @@ # /build/core/toolchains/mips64el-linux-android-4.9/setup.mk +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -fpic" + ) + include(Platform/Android/abi-common-GNU) diff --git a/Modules/Platform/Android/abi-x86-Clang.cmake b/Modules/Platform/Android/abi-x86-Clang.cmake index ec79790..f63ed36 100644 --- a/Modules/Platform/Android/abi-x86-Clang.cmake +++ b/Modules/Platform/Android/abi-x86-Clang.cmake @@ -1,3 +1,8 @@ # /build/core/toolchains/x86-clang/setup.mk set(_ANDROID_ABI_CLANG_TARGET "i686-none-linux-android") + +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -fPIC" + ) + include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-x86_64-Clang.cmake b/Modules/Platform/Android/abi-x86_64-Clang.cmake index dd386bf..c15042b 100644 --- a/Modules/Platform/Android/abi-x86_64-Clang.cmake +++ b/Modules/Platform/Android/abi-x86_64-Clang.cmake @@ -1,3 +1,8 @@ # /build/core/toolchains/x86_64-clang/setup.mk set(_ANDROID_ABI_CLANG_TARGET "x86_64-none-linux-android") + +string(APPEND _ANDROID_ABI_INIT_CFLAGS + " -fPIC" + ) + include(Platform/Android/abi-common-Clang) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b6a3102a9f8da05b50d4f4e96dd9f42ace37aa9b commit b6a3102a9f8da05b50d4f4e96dd9f42ace37aa9b Author: Brad King AuthorDate: Wed Jun 8 13:48:19 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:54 2016 -0400 Android: Add a CMAKE_BUILD_TYPE default Android NDK builds are always `debug` or `release`. We may populate flags for these configurations that are needed to produce compatible binaries. Ensure they are used by default. diff --git a/Modules/Platform/Android-Initialize.cmake b/Modules/Platform/Android-Initialize.cmake index c0354c7..353dd0d 100644 --- a/Modules/Platform/Android-Initialize.cmake +++ b/Modules/Platform/Android-Initialize.cmake @@ -47,3 +47,5 @@ else() "Android: No CMAKE_SYSROOT was selected." ) endif() + +set(CMAKE_BUILD_TYPE_INIT Debug) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d1e3cec2aa17a2f07f22c64c3bd29c765d69d9d2 commit d1e3cec2aa17a2f07f22c64c3bd29c765d69d9d2 Author: Brad King AuthorDate: Thu Jun 2 15:10:05 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:54 2016 -0400 Android: Add Clang -target option for current ABI diff --git a/Modules/Platform/Android-Clang.cmake b/Modules/Platform/Android-Clang.cmake index b33f376..7ed5046 100644 --- a/Modules/Platform/Android-Clang.cmake +++ b/Modules/Platform/Android-Clang.cmake @@ -36,8 +36,17 @@ endif() include(Platform/Android-Common) +# The NDK toolchain configuration files at: +# +# /[build/core/]toolchains/*-clang*/setup.mk +# +# contain logic to set LLVM_TRIPLE for Clang-based toolchains for each target. +# We need to produce the same target here to produce compatible binaries. include(Platform/Android/abi-${CMAKE_ANDROID_ARCH_ABI}-Clang) macro(__android_compiler_clang lang) __android_compiler_common(${lang}) + if(NOT CMAKE_${lang}_COMPILER_TARGET) + set(CMAKE_${lang}_COMPILER_TARGET "${_ANDROID_ABI_CLANG_TARGET}") + endif() endmacro() diff --git a/Modules/Platform/Android/abi-arm64-v8a-Clang.cmake b/Modules/Platform/Android/abi-arm64-v8a-Clang.cmake index 364c179..60fe3e5 100644 --- a/Modules/Platform/Android/abi-arm64-v8a-Clang.cmake +++ b/Modules/Platform/Android/abi-arm64-v8a-Clang.cmake @@ -1,2 +1,3 @@ # /build/core/toolchains/aarch64-linux-android-clang/setup.mk +set(_ANDROID_ABI_CLANG_TARGET "aarch64-none-linux-android") include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-armeabi-Clang.cmake b/Modules/Platform/Android/abi-armeabi-Clang.cmake index 407d685..eb703f5 100644 --- a/Modules/Platform/Android/abi-armeabi-Clang.cmake +++ b/Modules/Platform/Android/abi-armeabi-Clang.cmake @@ -1,2 +1,3 @@ # /build/core/toolchains/arm-linux-androideabi-clang/setup.mk +set(_ANDROID_ABI_CLANG_TARGET "armv5te-none-linux-androideabi") include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-armeabi-v6-Clang.cmake b/Modules/Platform/Android/abi-armeabi-v6-Clang.cmake index 407d685..b58b558 100644 --- a/Modules/Platform/Android/abi-armeabi-v6-Clang.cmake +++ b/Modules/Platform/Android/abi-armeabi-v6-Clang.cmake @@ -1,2 +1,3 @@ # /build/core/toolchains/arm-linux-androideabi-clang/setup.mk +set(_ANDROID_ABI_CLANG_TARGET "armv6-none-linux-androideabi") include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake b/Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake index 407d685..e7c311c 100644 --- a/Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake +++ b/Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake @@ -1,2 +1,3 @@ # /build/core/toolchains/arm-linux-androideabi-clang/setup.mk +set(_ANDROID_ABI_CLANG_TARGET "armv7-none-linux-androideabi") include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-mips-Clang.cmake b/Modules/Platform/Android/abi-mips-Clang.cmake index 3da0c69..2991a93 100644 --- a/Modules/Platform/Android/abi-mips-Clang.cmake +++ b/Modules/Platform/Android/abi-mips-Clang.cmake @@ -1,2 +1,3 @@ # /build/core/toolchains/mipsel-linux-android-clang/setup.mk +set(_ANDROID_ABI_CLANG_TARGET "mipsel-none-linux-android") include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-mips64-Clang.cmake b/Modules/Platform/Android/abi-mips64-Clang.cmake index 2623bbb..24b8db5 100644 --- a/Modules/Platform/Android/abi-mips64-Clang.cmake +++ b/Modules/Platform/Android/abi-mips64-Clang.cmake @@ -1,2 +1,3 @@ # /build/core/toolchains/mips64el-linux-android-clang/setup.mk +set(_ANDROID_ABI_CLANG_TARGET "mips64el-none-linux-android") include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-x86-Clang.cmake b/Modules/Platform/Android/abi-x86-Clang.cmake index 4a20a15..ec79790 100644 --- a/Modules/Platform/Android/abi-x86-Clang.cmake +++ b/Modules/Platform/Android/abi-x86-Clang.cmake @@ -1,2 +1,3 @@ # /build/core/toolchains/x86-clang/setup.mk +set(_ANDROID_ABI_CLANG_TARGET "i686-none-linux-android") include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-x86_64-Clang.cmake b/Modules/Platform/Android/abi-x86_64-Clang.cmake index b90c939..dd386bf 100644 --- a/Modules/Platform/Android/abi-x86_64-Clang.cmake +++ b/Modules/Platform/Android/abi-x86_64-Clang.cmake @@ -1,2 +1,3 @@ # /build/core/toolchains/x86_64-clang/setup.mk +set(_ANDROID_ABI_CLANG_TARGET "x86_64-none-linux-android") include(Platform/Android/abi-common-Clang) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=504db72d99fc2302de605fd9c2f845c1b8865500 commit 504db72d99fc2302de605fd9c2f845c1b8865500 Author: Brad King AuthorDate: Thu Jun 23 15:18:13 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:54 2016 -0400 Android: Add placeholders for compiler/abi-specific settings The Android NDK source repository at https://android.googlesource.com/platform/ndk.git has `/build/core/toolchains/*/setup.mk` files that store tables of information for their build system. Add an equivalent file for each compiler/abi combination. diff --git a/Modules/Platform/Android-Clang.cmake b/Modules/Platform/Android-Clang.cmake index d16d342..b33f376 100644 --- a/Modules/Platform/Android-Clang.cmake +++ b/Modules/Platform/Android-Clang.cmake @@ -36,6 +36,8 @@ endif() include(Platform/Android-Common) +include(Platform/Android/abi-${CMAKE_ANDROID_ARCH_ABI}-Clang) + macro(__android_compiler_clang lang) __android_compiler_common(${lang}) endmacro() diff --git a/Modules/Platform/Android-GNU.cmake b/Modules/Platform/Android-GNU.cmake index 8c3ea1d..58943d0 100644 --- a/Modules/Platform/Android-GNU.cmake +++ b/Modules/Platform/Android-GNU.cmake @@ -36,6 +36,8 @@ endif() include(Platform/Android-Common) +include(Platform/Android/abi-${CMAKE_ANDROID_ARCH_ABI}-GNU) + macro(__android_compiler_gnu lang) __android_compiler_common(${lang}) endmacro() diff --git a/Modules/Platform/Android/abi-arm64-v8a-Clang.cmake b/Modules/Platform/Android/abi-arm64-v8a-Clang.cmake new file mode 100644 index 0000000..364c179 --- /dev/null +++ b/Modules/Platform/Android/abi-arm64-v8a-Clang.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/aarch64-linux-android-clang/setup.mk +include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-arm64-v8a-GNU.cmake b/Modules/Platform/Android/abi-arm64-v8a-GNU.cmake new file mode 100644 index 0000000..a25a0dd --- /dev/null +++ b/Modules/Platform/Android/abi-arm64-v8a-GNU.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/aarch64-linux-android-4.9/setup.mk +include(Platform/Android/abi-common-GNU) diff --git a/Modules/Platform/Android/abi-armeabi-Clang.cmake b/Modules/Platform/Android/abi-armeabi-Clang.cmake new file mode 100644 index 0000000..407d685 --- /dev/null +++ b/Modules/Platform/Android/abi-armeabi-Clang.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/arm-linux-androideabi-clang/setup.mk +include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-armeabi-GNU.cmake b/Modules/Platform/Android/abi-armeabi-GNU.cmake new file mode 100644 index 0000000..d621e72 --- /dev/null +++ b/Modules/Platform/Android/abi-armeabi-GNU.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/arm-linux-androideabi-4.9/setup.mk +include(Platform/Android/abi-common-GNU) diff --git a/Modules/Platform/Android/abi-armeabi-v6-Clang.cmake b/Modules/Platform/Android/abi-armeabi-v6-Clang.cmake new file mode 100644 index 0000000..407d685 --- /dev/null +++ b/Modules/Platform/Android/abi-armeabi-v6-Clang.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/arm-linux-androideabi-clang/setup.mk +include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-armeabi-v6-GNU.cmake b/Modules/Platform/Android/abi-armeabi-v6-GNU.cmake new file mode 100644 index 0000000..d621e72 --- /dev/null +++ b/Modules/Platform/Android/abi-armeabi-v6-GNU.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/arm-linux-androideabi-4.9/setup.mk +include(Platform/Android/abi-common-GNU) diff --git a/Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake b/Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake new file mode 100644 index 0000000..407d685 --- /dev/null +++ b/Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/arm-linux-androideabi-clang/setup.mk +include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-armeabi-v7a-GNU.cmake b/Modules/Platform/Android/abi-armeabi-v7a-GNU.cmake new file mode 100644 index 0000000..d621e72 --- /dev/null +++ b/Modules/Platform/Android/abi-armeabi-v7a-GNU.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/arm-linux-androideabi-4.9/setup.mk +include(Platform/Android/abi-common-GNU) diff --git a/Modules/Platform/Android/abi-common-Clang.cmake b/Modules/Platform/Android/abi-common-Clang.cmake new file mode 100644 index 0000000..40d829f --- /dev/null +++ b/Modules/Platform/Android/abi-common-Clang.cmake @@ -0,0 +1 @@ +include(Platform/Android/abi-common) diff --git a/Modules/Platform/Android/abi-common-GNU.cmake b/Modules/Platform/Android/abi-common-GNU.cmake new file mode 100644 index 0000000..40d829f --- /dev/null +++ b/Modules/Platform/Android/abi-common-GNU.cmake @@ -0,0 +1 @@ +include(Platform/Android/abi-common) diff --git a/Modules/Platform/Android/abi-common.cmake b/Modules/Platform/Android/abi-common.cmake new file mode 100644 index 0000000..e69de29 diff --git a/Modules/Platform/Android/abi-mips-Clang.cmake b/Modules/Platform/Android/abi-mips-Clang.cmake new file mode 100644 index 0000000..3da0c69 --- /dev/null +++ b/Modules/Platform/Android/abi-mips-Clang.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/mipsel-linux-android-clang/setup.mk +include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-mips-GNU.cmake b/Modules/Platform/Android/abi-mips-GNU.cmake new file mode 100644 index 0000000..675f9ca --- /dev/null +++ b/Modules/Platform/Android/abi-mips-GNU.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/mipsel-linux-android-4.9/setup.mk +include(Platform/Android/abi-common-GNU) diff --git a/Modules/Platform/Android/abi-mips64-Clang.cmake b/Modules/Platform/Android/abi-mips64-Clang.cmake new file mode 100644 index 0000000..2623bbb --- /dev/null +++ b/Modules/Platform/Android/abi-mips64-Clang.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/mips64el-linux-android-clang/setup.mk +include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-mips64-GNU.cmake b/Modules/Platform/Android/abi-mips64-GNU.cmake new file mode 100644 index 0000000..3f9fbc3 --- /dev/null +++ b/Modules/Platform/Android/abi-mips64-GNU.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/mips64el-linux-android-4.9/setup.mk +include(Platform/Android/abi-common-GNU) diff --git a/Modules/Platform/Android/abi-x86-Clang.cmake b/Modules/Platform/Android/abi-x86-Clang.cmake new file mode 100644 index 0000000..4a20a15 --- /dev/null +++ b/Modules/Platform/Android/abi-x86-Clang.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/x86-clang/setup.mk +include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-x86-GNU.cmake b/Modules/Platform/Android/abi-x86-GNU.cmake new file mode 100644 index 0000000..76ea5ca --- /dev/null +++ b/Modules/Platform/Android/abi-x86-GNU.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/x86-4.9/setup.mk +include(Platform/Android/abi-common-GNU) diff --git a/Modules/Platform/Android/abi-x86_64-Clang.cmake b/Modules/Platform/Android/abi-x86_64-Clang.cmake new file mode 100644 index 0000000..b90c939 --- /dev/null +++ b/Modules/Platform/Android/abi-x86_64-Clang.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/x86_64-clang/setup.mk +include(Platform/Android/abi-common-Clang) diff --git a/Modules/Platform/Android/abi-x86_64-GNU.cmake b/Modules/Platform/Android/abi-x86_64-GNU.cmake new file mode 100644 index 0000000..441bdcd --- /dev/null +++ b/Modules/Platform/Android/abi-x86_64-GNU.cmake @@ -0,0 +1,2 @@ +# /build/core/toolchains/x86_64-4.9/setup.mk +include(Platform/Android/abi-common-GNU) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=fa6325782112063b5d425714a37c8ebd01b90d7c commit fa6325782112063b5d425714a37c8ebd01b90d7c Author: Brad King AuthorDate: Mon Jun 6 13:56:21 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:54 2016 -0400 Android: Avoid interfering with common pre-existing toolchain files Commonly used Android toolchain files that pre-date CMake upstream support may need to be updated to work with our new functionality. They typically set CMAKE_SYSTEM_VERSION to 1, so detect that and skip our upstream Android settings. When such toolchain files are updated to account for our upstream support, they can then set CMAKE_SYSTEM_VERSION to a valid Android API and get new behavior. diff --git a/Modules/Platform/Android-Clang.cmake b/Modules/Platform/Android-Clang.cmake index dc398bb..d16d342 100644 --- a/Modules/Platform/Android-Clang.cmake +++ b/Modules/Platform/Android-Clang.cmake @@ -26,6 +26,14 @@ if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android") return() endif() +# Commonly used Android toolchain files that pre-date CMake upstream support +# set CMAKE_SYSTEM_VERSION to 1. Avoid interfering with them. +if(CMAKE_SYSTEM_VERSION EQUAL 1) + macro(__android_compiler_clang lang) + endmacro() + return() +endif() + include(Platform/Android-Common) macro(__android_compiler_clang lang) diff --git a/Modules/Platform/Android-Determine.cmake b/Modules/Platform/Android-Determine.cmake index d2d5aaa..0a89c58 100644 --- a/Modules/Platform/Android-Determine.cmake +++ b/Modules/Platform/Android-Determine.cmake @@ -22,6 +22,12 @@ if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android") return() endif() +# Commonly used Android toolchain files that pre-date CMake upstream support +# set CMAKE_SYSTEM_VERSION to 1. Avoid interfering with them. +if(CMAKE_SYSTEM_VERSION EQUAL 1) + return() +endif() + # If the user provided CMAKE_SYSROOT for us, extract information from it. set(_ANDROID_SYSROOT_NDK "") set(_ANDROID_SYSROOT_API "") diff --git a/Modules/Platform/Android-GNU.cmake b/Modules/Platform/Android-GNU.cmake index 4f25bf3..8c3ea1d 100644 --- a/Modules/Platform/Android-GNU.cmake +++ b/Modules/Platform/Android-GNU.cmake @@ -26,6 +26,14 @@ if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android") return() endif() +# Commonly used Android toolchain files that pre-date CMake upstream support +# set CMAKE_SYSTEM_VERSION to 1. Avoid interfering with them. +if(CMAKE_SYSTEM_VERSION EQUAL 1) + macro(__android_compiler_gnu lang) + endmacro() + return() +endif() + include(Platform/Android-Common) macro(__android_compiler_gnu lang) diff --git a/Modules/Platform/Android-Initialize.cmake b/Modules/Platform/Android-Initialize.cmake index 625490e..c0354c7 100644 --- a/Modules/Platform/Android-Initialize.cmake +++ b/Modules/Platform/Android-Initialize.cmake @@ -21,6 +21,12 @@ if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android") return() endif() +# Commonly used Android toolchain files that pre-date CMake upstream support +# set CMAKE_SYSTEM_VERSION to 1. Avoid interfering with them. +if(CMAKE_SYSTEM_VERSION EQUAL 1) + return() +endif() + if(NOT CMAKE_SYSROOT) if(CMAKE_ANDROID_NDK) set(CMAKE_SYSROOT "${CMAKE_ANDROID_NDK}/platforms/android-${CMAKE_SYSTEM_VERSION}/arch-${CMAKE_ANDROID_ARCH}") diff --git a/Modules/Platform/Android/Determine-Compiler.cmake b/Modules/Platform/Android/Determine-Compiler.cmake index 613ce32..65223dc 100644 --- a/Modules/Platform/Android/Determine-Compiler.cmake +++ b/Modules/Platform/Android/Determine-Compiler.cmake @@ -26,6 +26,14 @@ if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android") return() endif() +# Commonly used Android toolchain files that pre-date CMake upstream support +# set CMAKE_SYSTEM_VERSION to 1. Avoid interfering with them. +if(CMAKE_SYSTEM_VERSION EQUAL 1) + macro(__android_determine_compiler lang) + endmacro() + return() +endif() + # Identify the host platform. if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") set(_ANDROID_HOST_EXT "") https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6299693f8aa5f5a61cec82215b73a2040a8d8603 commit 6299693f8aa5f5a61cec82215b73a2040a8d8603 Author: Brad King AuthorDate: Mon Jun 6 14:55:48 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:53 2016 -0400 Android: Search for NDK and standalone toolchain in more places Commonly used Android toolchain files that pre-date CMake upstream support use a few environment and CMake variables as search locations. Use them too to aid transition. diff --git a/Modules/Platform/Android-Determine.cmake b/Modules/Platform/Android-Determine.cmake index 50ab40b..d2d5aaa 100644 --- a/Modules/Platform/Android-Determine.cmake +++ b/Modules/Platform/Android-Determine.cmake @@ -88,8 +88,16 @@ else() set(CMAKE_ANDROID_NDK "${_ANDROID_SYSROOT_NDK}") elseif(IS_DIRECTORY "${_ANDROID_SYSROOT_STANDALONE_TOOLCHAIN}") set(CMAKE_ANDROID_STANDALONE_TOOLCHAIN "${_ANDROID_SYSROOT_STANDALONE_TOOLCHAIN}") + elseif(IS_DIRECTORY "${ANDROID_NDK}") + file(TO_CMAKE_PATH "${ANDROID_NDK}" CMAKE_ANDROID_NDK) + elseif(IS_DIRECTORY "${ANDROID_STANDALONE_TOOLCHAIN}") + file(TO_CMAKE_PATH "${ANDROID_STANDALONE_TOOLCHAIN}" CMAKE_ANDROID_STANDALONE_TOOLCHAIN) elseif(IS_DIRECTORY "$ENV{ANDROID_NDK_ROOT}") file(TO_CMAKE_PATH "$ENV{ANDROID_NDK_ROOT}" CMAKE_ANDROID_NDK) + elseif(IS_DIRECTORY "$ENV{ANDROID_NDK}") + file(TO_CMAKE_PATH "$ENV{ANDROID_NDK}" CMAKE_ANDROID_NDK) + elseif(IS_DIRECTORY "$ENV{ANDROID_STANDALONE_TOOLCHAIN}") + file(TO_CMAKE_PATH "$ENV{ANDROID_STANDALONE_TOOLCHAIN}" CMAKE_ANDROID_STANDALONE_TOOLCHAIN) endif() # TODO: Search harder for the NDK or standalone toolchain. endif() https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=29b51379de352980dd453243bea7ed37ed300c62 commit 29b51379de352980dd453243bea7ed37ed300c62 Author: Brad King AuthorDate: Fri Jun 3 15:06:58 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:53 2016 -0400 Android: Detect and save a standalone toolchain without the NDK diff --git a/Modules/Platform/Android-Determine.cmake b/Modules/Platform/Android-Determine.cmake index 0055ecb..50ab40b 100644 --- a/Modules/Platform/Android-Determine.cmake +++ b/Modules/Platform/Android-Determine.cmake @@ -26,6 +26,7 @@ endif() set(_ANDROID_SYSROOT_NDK "") set(_ANDROID_SYSROOT_API "") set(_ANDROID_SYSROOT_ARCH "") +set(_ANDROID_SYSROOT_STANDALONE_TOOLCHAIN "") if(CMAKE_SYSROOT) if(NOT IS_DIRECTORY "${CMAKE_SYSROOT}") message(FATAL_ERROR @@ -38,16 +39,20 @@ if(CMAKE_SYSROOT) set(_ANDROID_SYSROOT_NDK "${CMAKE_MATCH_1}") set(_ANDROID_SYSROOT_API "${CMAKE_MATCH_2}") set(_ANDROID_SYSROOT_ARCH "${CMAKE_MATCH_3}") + elseif(CMAKE_SYSROOT MATCHES "^([^\\\n]*)/sysroot$") + set(_ANDROID_SYSROOT_STANDALONE_TOOLCHAIN "${CMAKE_MATCH_1}") else() message(FATAL_ERROR "The value of CMAKE_SYSROOT:\n" " ${CMAKE_SYSROOT}\n" - "does not match the form:\n" + "does not match any of the forms:\n" " /platforms/android-/arch-\n" + " /sysroot\n" "where:\n" " = Android NDK directory (with forward slashes)\n" " = Android API version number (decimal digits)\n" - " = Android ARCH name (lower case)" + " = Android ARCH name (lower case)\n" + " = Path to standalone toolchain prefix\n" ) endif() endif() @@ -61,17 +66,46 @@ if(CMAKE_ANDROID_NDK) "does not exist." ) endif() +elseif(CMAKE_ANDROID_STANDALONE_TOOLCHAIN) + if(NOT IS_DIRECTORY "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}") + message(FATAL_ERROR + "Android: The standalone toolchain directory specified by CMAKE_ANDROID_STANDALONE_TOOLCHAIN:\n" + " ${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}\n" + "does not exist." + ) + endif() + if(NOT EXISTS "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h") + message(FATAL_ERROR + "Android: The standalone toolchain directory specified by CMAKE_ANDROID_STANDALONE_TOOLCHAIN:\n" + " ${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}\n" + "does not contain a sysroot with a known layout. The file:\n" + " ${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h\n" + "does not exist." + ) + endif() else() if(IS_DIRECTORY "${_ANDROID_SYSROOT_NDK}") set(CMAKE_ANDROID_NDK "${_ANDROID_SYSROOT_NDK}") + elseif(IS_DIRECTORY "${_ANDROID_SYSROOT_STANDALONE_TOOLCHAIN}") + set(CMAKE_ANDROID_STANDALONE_TOOLCHAIN "${_ANDROID_SYSROOT_STANDALONE_TOOLCHAIN}") elseif(IS_DIRECTORY "$ENV{ANDROID_NDK_ROOT}") file(TO_CMAKE_PATH "$ENV{ANDROID_NDK_ROOT}" CMAKE_ANDROID_NDK) endif() - # TODO: Search harder for the NDK. + # TODO: Search harder for the NDK or standalone toolchain. +endif() + +set(_ANDROID_STANDALONE_TOOLCHAIN_API "") +if(CMAKE_ANDROID_STANDALONE_TOOLCHAIN) + set(_ANDROID_API_LEVEL_H_REGEX "^[\t ]*#[\t ]*define[\t ]+__ANDROID_API__[\t ]+([0-9]+)") + file(STRINGS "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h" + _ANDROID_API_LEVEL_H_CONTENT REGEX "${_ANDROID_API_LEVEL_H_REGEX}") + if(_ANDROID_API_LEVEL_H_CONTENT MATCHES "${_ANDROID_API_LEVEL_H_REGEX}") + set(_ANDROID_STANDALONE_TOOLCHAIN_API "${CMAKE_MATCH_1}") + endif() endif() -if(NOT CMAKE_ANDROID_NDK) - message(FATAL_ERROR "Android: The NDK root directory was not found.") +if(NOT CMAKE_ANDROID_NDK AND NOT CMAKE_ANDROID_STANDALONE_TOOLCHAIN) + message(FATAL_ERROR "Android: Neither the NDK or a standalone toolchain was found.") endif() # Select an API. @@ -83,6 +117,8 @@ elseif(CMAKE_ANDROID_API) elseif(_ANDROID_SYSROOT_API) set(CMAKE_SYSTEM_VERSION "${_ANDROID_SYSROOT_API}") set(_ANDROID_API_VAR CMAKE_SYSROOT) +elseif(_ANDROID_STANDALONE_TOOLCHAIN_API) + set(CMAKE_SYSTEM_VERSION "${_ANDROID_STANDALONE_TOOLCHAIN_API}") endif() if(CMAKE_SYSTEM_VERSION) if(CMAKE_ANDROID_API AND NOT "x${CMAKE_ANDROID_API}" STREQUAL "x${CMAKE_SYSTEM_VERSION}") @@ -215,6 +251,7 @@ endif() # Save the Android-specific information in CMakeSystem.cmake. set(CMAKE_SYSTEM_CUSTOM_CODE " set(CMAKE_ANDROID_NDK \"${CMAKE_ANDROID_NDK}\") +set(CMAKE_ANDROID_STANDALONE_TOOLCHAIN \"${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}\") set(CMAKE_ANDROID_ARCH \"${CMAKE_ANDROID_ARCH}\") set(CMAKE_ANDROID_ARCH_ABI \"${CMAKE_ANDROID_ARCH_ABI}\") ") diff --git a/Modules/Platform/Android-Initialize.cmake b/Modules/Platform/Android-Initialize.cmake index f05357c..625490e 100644 --- a/Modules/Platform/Android-Initialize.cmake +++ b/Modules/Platform/Android-Initialize.cmake @@ -24,6 +24,8 @@ endif() if(NOT CMAKE_SYSROOT) if(CMAKE_ANDROID_NDK) set(CMAKE_SYSROOT "${CMAKE_ANDROID_NDK}/platforms/android-${CMAKE_SYSTEM_VERSION}/arch-${CMAKE_ANDROID_ARCH}") + elseif(CMAKE_ANDROID_STANDALONE_TOOLCHAIN) + set(CMAKE_SYSROOT "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/sysroot") endif() endif() diff --git a/Modules/Platform/Android/Determine-Compiler-Standalone.cmake b/Modules/Platform/Android/Determine-Compiler-Standalone.cmake new file mode 100644 index 0000000..64d4ccf --- /dev/null +++ b/Modules/Platform/Android/Determine-Compiler-Standalone.cmake @@ -0,0 +1,69 @@ +#============================================================================= +# Copyright 2015-2016 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +set(_ANDROID_TOOL_C_COMPILER "") +set(_ANDROID_TOOL_CXX_COMPILER "") +set(_ANDROID_TOOL_PREFIX "") +file(GLOB _gcc "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/*-gcc${_ANDROID_HOST_EXT}") +foreach(gcc IN LISTS _gcc) + if("${gcc}" MATCHES "/bin/([^/]*)gcc${_ANDROID_HOST_EXT}$") + set(_ANDROID_TOOL_PREFIX "${CMAKE_MATCH_1}") + break() + endif() +endforeach() + +if(NOT _ANDROID_TOOL_PREFIX) + message(FATAL_ERROR + "Android: No '*-gcc' compiler found in CMAKE_ANDROID_STANDALONE_TOOLCHAIN:\n" + " ${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}" + ) +endif() + +# Help CMakeFindBinUtils locate things. +set(_CMAKE_TOOLCHAIN_PREFIX "${_ANDROID_TOOL_PREFIX}") + +execute_process( + COMMAND "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/${_ANDROID_TOOL_PREFIX}gcc${_ANDROID_HOST_EXT}" -dumpversion + OUTPUT_VARIABLE _gcc_version + ERROR_VARIABLE _gcc_error + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +if(_gcc_version MATCHES "^([0-9]+\\.[0-9]+)") + set(_ANDROID_TOOL_C_TOOLCHAIN_VERSION "${CMAKE_MATCH_1}") +else() + message(FATAL_ERROR + "Android: Failed to extract the standalone toolchain version. The command:\n" + " '${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/${_ANDROID_TOOL_PREFIX}gcc${_ANDROID_HOST_EXT}' '-dumpversion'\n" + "produced output:\n" + " ${_gcc_version}\n" + ) +endif() + +set(_ANDROID_TOOL_C_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/${_ANDROID_TOOL_PREFIX}") +set(_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX "${_ANDROID_HOST_EXT}") + +set(_ANDROID_TOOL_CXX_TOOLCHAIN_VERSION "${_ANDROID_TOOL_C_TOOLCHAIN_VERSION}") +set(_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX "${_ANDROID_TOOL_C_TOOLCHAIN_PREFIX}") +set(_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX "${_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX}") + +if(EXISTS "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/clang${_ANDROID_HOST_EXT}") + set(_ANDROID_TOOL_C_COMPILER "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/clang${_ANDROID_HOST_EXT}") + set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}") + set(_ANDROID_TOOL_CXX_COMPILER "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/clang++${_ANDROID_HOST_EXT}") + set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}") +else() + set(_ANDROID_TOOL_C_COMPILER "${_ANDROID_TOOL_C_TOOLCHAIN_PREFIX}gcc${_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX}") + set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN "") + set(_ANDROID_TOOL_CXX_COMPILER "${_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX}g++${_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX}") + set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "") +endif() diff --git a/Modules/Platform/Android/Determine-Compiler.cmake b/Modules/Platform/Android/Determine-Compiler.cmake index 9649b35..613ce32 100644 --- a/Modules/Platform/Android/Determine-Compiler.cmake +++ b/Modules/Platform/Android/Determine-Compiler.cmake @@ -39,6 +39,8 @@ endif() if(CMAKE_ANDROID_NDK) include(Platform/Android/Determine-Compiler-NDK) +elseif(CMAKE_ANDROID_STANDALONE_TOOLCHAIN) + include(Platform/Android/Determine-Compiler-Standalone) else() set(_ANDROID_TOOL_C_COMPILER "") set(_ANDROID_TOOL_C_TOOLCHAIN_VERSION "") https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7d9b49fbdf55b28d2979af89a8192607df487ca1 commit 7d9b49fbdf55b28d2979af89a8192607df487ca1 Author: Brad King AuthorDate: Thu Jun 2 16:21:36 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:53 2016 -0400 Android: Detect settings from the CMAKE_SYSROOT if it is set diff --git a/Modules/Platform/Android-Determine.cmake b/Modules/Platform/Android-Determine.cmake index dbbdbf2..0055ecb 100644 --- a/Modules/Platform/Android-Determine.cmake +++ b/Modules/Platform/Android-Determine.cmake @@ -22,6 +22,36 @@ if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android") return() endif() +# If the user provided CMAKE_SYSROOT for us, extract information from it. +set(_ANDROID_SYSROOT_NDK "") +set(_ANDROID_SYSROOT_API "") +set(_ANDROID_SYSROOT_ARCH "") +if(CMAKE_SYSROOT) + if(NOT IS_DIRECTORY "${CMAKE_SYSROOT}") + message(FATAL_ERROR + "Android: The specified CMAKE_SYSROOT:\n" + " ${CMAKE_SYSROOT}\n" + "is not an existing directory." + ) + endif() + if(CMAKE_SYSROOT MATCHES "^([^\\\n]*)/platforms/android-([0-9]+)/arch-([a-z0-9_]+)$") + set(_ANDROID_SYSROOT_NDK "${CMAKE_MATCH_1}") + set(_ANDROID_SYSROOT_API "${CMAKE_MATCH_2}") + set(_ANDROID_SYSROOT_ARCH "${CMAKE_MATCH_3}") + else() + message(FATAL_ERROR + "The value of CMAKE_SYSROOT:\n" + " ${CMAKE_SYSROOT}\n" + "does not match the form:\n" + " /platforms/android-/arch-\n" + "where:\n" + " = Android NDK directory (with forward slashes)\n" + " = Android API version number (decimal digits)\n" + " = Android ARCH name (lower case)" + ) + endif() +endif() + # Find the Android NDK. if(CMAKE_ANDROID_NDK) if(NOT IS_DIRECTORY "${CMAKE_ANDROID_NDK}") @@ -32,7 +62,9 @@ if(CMAKE_ANDROID_NDK) ) endif() else() - if(IS_DIRECTORY "$ENV{ANDROID_NDK_ROOT}") + if(IS_DIRECTORY "${_ANDROID_SYSROOT_NDK}") + set(CMAKE_ANDROID_NDK "${_ANDROID_SYSROOT_NDK}") + elseif(IS_DIRECTORY "$ENV{ANDROID_NDK_ROOT}") file(TO_CMAKE_PATH "$ENV{ANDROID_NDK_ROOT}" CMAKE_ANDROID_NDK) endif() # TODO: Search harder for the NDK. @@ -48,6 +80,9 @@ if(CMAKE_SYSTEM_VERSION) elseif(CMAKE_ANDROID_API) set(CMAKE_SYSTEM_VERSION "${CMAKE_ANDROID_API}") set(_ANDROID_API_VAR CMAKE_ANDROID_API) +elseif(_ANDROID_SYSROOT_API) + set(CMAKE_SYSTEM_VERSION "${_ANDROID_SYSROOT_API}") + set(_ANDROID_API_VAR CMAKE_SYSROOT) endif() if(CMAKE_SYSTEM_VERSION) if(CMAKE_ANDROID_API AND NOT "x${CMAKE_ANDROID_API}" STREQUAL "x${CMAKE_SYSTEM_VERSION}") @@ -55,6 +90,16 @@ if(CMAKE_SYSTEM_VERSION) "Android: The API specified by CMAKE_ANDROID_API='${CMAKE_ANDROID_API}' is not consistent with CMAKE_SYSTEM_VERSION='${CMAKE_SYSTEM_VERSION}'." ) endif() + if(_ANDROID_SYSROOT_API) + foreach(v CMAKE_ANDROID_API CMAKE_SYSTEM_VERSION) + if(${v} AND NOT "x${_ANDROID_SYSROOT_API}" STREQUAL "x${${v}}") + message(FATAL_ERROR + "Android: The API specified by ${v}='${${v}}' is not consistent with CMAKE_SYSROOT:\n" + " ${CMAKE_SYSROOT}" + ) + endif() + endforeach() + endif() if(CMAKE_ANDROID_NDK AND NOT IS_DIRECTORY "${CMAKE_ANDROID_NDK}/platforms/android-${CMAKE_SYSTEM_VERSION}") message(FATAL_ERROR "Android: The API specified by ${_ANDROID_API_VAR}='${${_ANDROID_API_VAR}}' does not exist in the NDK. " @@ -115,6 +160,13 @@ set(_ANDROID_PROC_mips_ARCH_ABI "mips") set(_ANDROID_PROC_mips64_ARCH_ABI "mips64") set(_ANDROID_PROC_x86_64_ARCH_ABI "x86_64") +set(_ANDROID_ARCH_arm64_ABI "arm64-v8a") +set(_ANDROID_ARCH_arm_ABI "armeabi") +set(_ANDROID_ARCH_mips_ABI "mips") +set(_ANDROID_ARCH_mips64_ABI "mips64") +set(_ANDROID_ARCH_x86_ABI "x86") +set(_ANDROID_ARCH_x86_64_ABI "x86_64") + # Validate inputs. if(CMAKE_ANDROID_ARCH_ABI AND NOT DEFINED "_ANDROID_ABI_${CMAKE_ANDROID_ARCH_ABI}_PROC") message(FATAL_ERROR "Android: Unknown ABI CMAKE_ANDROID_ARCH_ABI='${CMAKE_ANDROID_ARCH_ABI}'.") @@ -122,11 +174,19 @@ endif() if(CMAKE_SYSTEM_PROCESSOR AND NOT DEFINED "_ANDROID_PROC_${CMAKE_SYSTEM_PROCESSOR}_ARCH_ABI") message(FATAL_ERROR "Android: Unknown processor CMAKE_SYSTEM_PROCESSOR='${CMAKE_SYSTEM_PROCESSOR}'.") endif() +if(_ANDROID_SYSROOT_ARCH AND NOT DEFINED "_ANDROID_ARCH_${_ANDROID_SYSROOT_ARCH}_ABI") + message(FATAL_ERROR + "Android: Unknown architecture '${_ANDROID_SYSROOT_ARCH}' specified in CMAKE_SYSROOT:\n" + " ${CMAKE_SYSROOT}" + ) +endif() # Select an ABI. if(NOT CMAKE_ANDROID_ARCH_ABI) if(CMAKE_SYSTEM_PROCESSOR) set(CMAKE_ANDROID_ARCH_ABI "${_ANDROID_PROC_${CMAKE_SYSTEM_PROCESSOR}_ARCH_ABI}") + elseif(_ANDROID_SYSROOT_ARCH) + set(CMAKE_ANDROID_ARCH_ABI "${_ANDROID_ARCH_${_ANDROID_SYSROOT_ARCH}_ABI}") else() # https://developer.android.com/ndk/guides/application_mk.html # Default is the oldest ARM ABI. @@ -134,6 +194,13 @@ if(NOT CMAKE_ANDROID_ARCH_ABI) endif() endif() set(CMAKE_ANDROID_ARCH "${_ANDROID_ABI_${CMAKE_ANDROID_ARCH_ABI}_ARCH}") +if(_ANDROID_SYSROOT_ARCH AND NOT "x${_ANDROID_SYSROOT_ARCH}" STREQUAL "x${CMAKE_ANDROID_ARCH}") + message(FATAL_ERROR + "Android: Architecture '${_ANDROID_SYSROOT_ARCH}' specified in CMAKE_SYSROOT:\n" + " ${CMAKE_SYSROOT}\n" + "does not match architecture '${CMAKE_ANDROID_ARCH}' for the ABI '${CMAKE_ANDROID_ARCH_ABI}'." + ) +endif() # Select a processor. if(NOT CMAKE_SYSTEM_PROCESSOR) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4389664a26be4d1f96a55c34e5fac9ac1248e5f0 commit 4389664a26be4d1f96a55c34e5fac9ac1248e5f0 Author: Brad King AuthorDate: Thu Jun 2 15:07:02 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:53 2016 -0400 Android: Detect and save a toolchain from the NDK diff --git a/Modules/Platform/Android/Determine-Compiler-NDK.cmake b/Modules/Platform/Android/Determine-Compiler-NDK.cmake new file mode 100644 index 0000000..8bd0de9 --- /dev/null +++ b/Modules/Platform/Android/Determine-Compiler-NDK.cmake @@ -0,0 +1,256 @@ +#============================================================================= +# Copyright 2015-2016 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# In Android NDK releases there is build system toolchain selection logic in +# these files: +# +# * /build/core/init.mk +# * /build/core/setup-toolchain.mk +# * /[build/core/]toolchains//{config.mk,setup.mk} +# +# We parse information out of the ``config.mk`` and ``setup.mk`` files below. +# +# There is also a "toolchains" directory with the prebuilt toolchains themselves: +# +# * -/prebuilt//bin/-gcc(.exe)? +# The gcc compiler to be invoked. +# +# * llvm*/prebuilt//bin/clang +# The clang compiler to be invoked with flags: +# -target +# -gcc-toolchain /toolchains/- + +# Glob available toolchains in the NDK, restricted by any version request. +if(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION STREQUAL "clang") + set(_ANDROID_TOOL_PATTERNS "*-clang" "*-clang[0-9].[0-9]") +elseif(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION) + if(NOT CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION MATCHES "^(clang)?[0-9]\\.[0-9]$") + message(FATAL_ERROR + "Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value '${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}' " + "is not one of the allowed forms:\n" + " . = GCC of specified version\n" + " clang. = Clang of specified version\n" + " clang = Clang of most recent available version\n" + ) + endif() + set(_ANDROID_TOOL_PATTERNS "*-${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}") +else() + set(_ANDROID_TOOL_PATTERNS "*-[0-9].[0-9]") +endif() +set(_ANDROID_CONFIG_MK_PATTERNS) +foreach(base "build/core/toolchains" "toolchains") + foreach(pattern IN LISTS _ANDROID_TOOL_PATTERNS) + list(APPEND _ANDROID_CONFIG_MK_PATTERNS + "${CMAKE_ANDROID_NDK}/${base}/${pattern}/config.mk" + ) + endforeach() +endforeach() +unset(_ANDROID_TOOL_PATTERNS) +file(GLOB _ANDROID_CONFIG_MKS ${_ANDROID_CONFIG_MK_PATTERNS}) +unset(_ANDROID_CONFIG_MK_PATTERNS) + +# Find the newest toolchain version matching the ABI. +set(_ANDROID_TOOL_NAME "") +set(_ANDROID_TOOL_VERS 0) +set(_ANDROID_TOOL_SETUP_MK "") +foreach(config_mk IN LISTS _ANDROID_CONFIG_MKS) + # Check that the toolchain matches the ABI. + file(STRINGS "${config_mk}" _ANDROID_TOOL_ABIS REGEX "^TOOLCHAIN_ABIS :=.* ${CMAKE_ANDROID_ARCH_ABI}( |$)") + if(NOT _ANDROID_TOOL_ABIS) + continue() + endif() + unset(_ANDROID_TOOL_ABIS) + + # Check the version. + if("${config_mk}" MATCHES [[/([^/]+-(clang)?([0-9]\.[0-9]|))/config.mk$]]) + set(_ANDROID_CUR_NAME "${CMAKE_MATCH_1}") + set(_ANDROID_CUR_VERS "${CMAKE_MATCH_3}") + if(_ANDROID_TOOL_VERS STREQUAL "") + # already the latest possible + elseif(_ANDROID_CUR_VERS STREQUAL "" OR _ANDROID_CUR_VERS VERSION_GREATER _ANDROID_TOOL_VERS) + set(_ANDROID_TOOL_NAME "${_ANDROID_CUR_NAME}") + set(_ANDROID_TOOL_VERS "${_ANDROID_CUR_VERS}") + string(REPLACE "/config.mk" "/setup.mk" _ANDROID_TOOL_SETUP_MK "${config_mk}") + endif() + unset(_ANDROID_CUR_TOOL) + unset(_ANDROID_CUR_VERS) + endif() +endforeach() + +# Verify that we have a suitable toolchain. +if(NOT _ANDROID_TOOL_NAME) + if(_ANDROID_CONFIG_MKS) + string(REPLACE ";" "\n " _ANDROID_TOOLS_MSG "after considering:;${_ANDROID_CONFIG_MKS}") + else() + set(_ANDROID_TOOLS_MSG "") + endif() + if(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION) + string(CONCAT _ANDROID_TOOLS_MSG + "of the version specified by CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION:\n" + " ${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}\n" + "${_ANDROID_TOOLS_MSG}") + endif() + message(FATAL_ERROR + "Android: No toolchain for ABI '${CMAKE_ANDROID_ARCH_ABI}' found in the NDK:\n" + " ${CMAKE_ANDROID_NDK}\n" + "${_ANDROID_TOOLS_MSG}" + ) +endif() +unset(_ANDROID_CONFIG_MKS) + +# For clang toolchains we still need to find a gcc toolchain. +if(_ANDROID_TOOL_NAME MATCHES "-clang") + set(_ANDROID_TOOL_CLANG_NAME "${_ANDROID_TOOL_NAME}") + set(_ANDROID_TOOL_CLANG_VERS "${_ANDROID_TOOL_VERS}") + set(_ANDROID_TOOL_NAME "") + set(_ANDROID_TOOL_VERS "") +else() + set(_ANDROID_TOOL_CLANG_NAME "") + set(_ANDROID_TOOL_CLANG_VERS "") +endif() + +# Parse the toolchain setup.mk file to extract information we need. +# Their content is not standardized across toolchains or NDK versions, +# so we match known cases. Note that the parsing is stateful across +# lines because we need to substitute for some Make variable references. +if(CMAKE_ANDROID_NDK_TOOLCHAIN_DEBUG) + message(STATUS "loading: ${_ANDROID_TOOL_SETUP_MK}") +endif() +file(STRINGS "${_ANDROID_TOOL_SETUP_MK}" _ANDROID_TOOL_SETUP REGEX "^(LLVM|TOOLCHAIN)_[A-Z_]+ +:= +.*$") +unset(_ANDROID_TOOL_SETUP_MK) +set(_ANDROID_TOOL_PREFIX "") +set(_ANDROID_TOOL_NAME_ONLY "") +set(_ANDROID_TOOL_LLVM_NAME "") +set(_ANDROID_TOOL_LLVM_VERS "") +foreach(line IN LISTS _ANDROID_TOOL_SETUP) + if(CMAKE_ANDROID_NDK_TOOLCHAIN_DEBUG) + message(STATUS "setup.mk: ${line}") + endif() + + if(line MATCHES [[^TOOLCHAIN_PREFIX +:= +.*/bin/([^$/ ]*) *$]]) + # We just matched the toolchain prefix with no Make variable references. + set(_ANDROID_TOOL_PREFIX "${CMAKE_MATCH_1}") + elseif(_ANDROID_TOOL_CLANG_NAME) + # For clang toolchains we need to find more information. + if(line MATCHES [[^TOOLCHAIN_VERSION +:= +([0-9.]+) *$]]) + # We just matched the gcc toolchain version number. Save it for later. + set(_ANDROID_TOOL_VERS "${CMAKE_MATCH_1}") + elseif(line MATCHES [[^TOOLCHAIN_NAME +:= +(.*\$\(TOOLCHAIN_VERSION\)) *$]]) + # We just matched the gcc toolchain name with a version number placeholder, so substitute it. + # The gcc toolchain version number will have already been extracted from a TOOLCHAIN_VERSION line. + string(REPLACE "$(TOOLCHAIN_VERSION)" "${_ANDROID_TOOL_VERS}" _ANDROID_TOOL_NAME "${CMAKE_MATCH_1}") + elseif(line MATCHES [[^TOOLCHAIN_NAME +:= +([^$/ ]+) *$]]) + # We just matched the gcc toolchain name without version number. Save it for later. + set(_ANDROID_TOOL_NAME_ONLY "${CMAKE_MATCH_1}") + elseif(line MATCHES [[^TOOLCHAIN_PREFIX +:= +.*/bin/(\$\(TOOLCHAIN_NAME\)-) *$]]) + # We just matched the toolchain prefix with a name placholder, so substitute it. + # The gcc toolchain name will have already been extracted without version number from a TOOLCHAIN_NAME line. + string(REPLACE "$(TOOLCHAIN_NAME)" "${_ANDROID_TOOL_NAME_ONLY}" _ANDROID_TOOL_PREFIX "${CMAKE_MATCH_1}") + elseif(line MATCHES [[^LLVM_VERSION +:= +([0-9.]+)$]]) + # We just matched the llvm prebuilt binary toolchain version number. Save it for later. + set(_ANDROID_TOOL_LLVM_VERS "${CMAKE_MATCH_1}") + elseif(line MATCHES [[^LLVM_NAME +:= +(llvm-\$\(LLVM_VERSION\)) *$]]) + # We just matched the llvm prebuilt binary toolchain directory name with a version number placeholder, + # so substitute it. The llvm prebuilt binary toolchain version number will have already been extracted + # from a LLVM_VERSION line. + string(REPLACE "$(LLVM_VERSION)" "${_ANDROID_TOOL_LLVM_VERS}" _ANDROID_TOOL_LLVM_NAME "${CMAKE_MATCH_1}") + elseif(line MATCHES [[^LLVM_TOOLCHAIN_PREBUILT_ROOT +:= +\$\(call get-toolchain-root.*,([^$ ]+)\) *$]]) + # We just matched the llvm prebuilt binary toolchain directory name. + set(_ANDROID_TOOL_LLVM_NAME "${CMAKE_MATCH_1}") + elseif(line MATCHES [[^TOOLCHAIN_ROOT +:= +\$\(call get-toolchain-root.*,(\$\(TOOLCHAIN_NAME\)-[0-9.]+)\) *$]]) + # We just matched a placeholder for the name followed by a version number. + # The gcc toolchain name will have already been extracted without version number from a TOOLCHAIN_NAME line. + # Substitute for the placeholder to get the full gcc toolchain name. + string(REPLACE "$(TOOLCHAIN_NAME)" "${_ANDROID_TOOL_NAME_ONLY}" _ANDROID_TOOL_NAME "${CMAKE_MATCH_1}") + elseif(line MATCHES [[^TOOLCHAIN_ROOT +:= +\$\(call get-toolchain-root.*,([^$ ]+)\) *$]]) + # We just matched the full gcc toolchain name without placeholder. + set(_ANDROID_TOOL_NAME "${CMAKE_MATCH_1}") + endif() + endif() +endforeach() +unset(_ANDROID_TOOL_NAME_ONLY) +unset(_ANDROID_TOOL_LLVM_VERS) +unset(_ANDROID_TOOL_SETUP) + +# Fall back to parsing the version and prefix from the tool name. +if(NOT _ANDROID_TOOL_VERS AND "${_ANDROID_TOOL_NAME}" MATCHES "-([0-9.]+)$") + set(_ANDROID_TOOL_VERS "${CMAKE_MATCH_1}") +endif() +if(NOT _ANDROID_TOOL_PREFIX AND "${_ANDROID_TOOL_NAME}" MATCHES "^(.*-)[0-9.]+$") + set(_ANDROID_TOOL_PREFIX "${CMAKE_MATCH_1}") +endif() + +# Identify the host platform. +if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") + if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64") + set(_ANDROID_HOST_DIR "darwin-x86_64") + else() + set(_ANDROID_HOST_DIR "darwin-x86") + endif() +elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64") + set(_ANDROID_HOST_DIR "linux-x86_64") + else() + set(_ANDROID_HOST_DIR "linux-x86") + endif() +elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") + if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") + set(_ANDROID_HOST_DIR "windows-x86_64") + else() + set(_ANDROID_HOST_DIR "windows") + endif() +else() + message(FATAL_ERROR "Android: Builds hosted on '${CMAKE_HOST_SYSTEM_NAME}' not supported.") +endif() + +# Help CMakeFindBinUtils locate things. +set(_CMAKE_TOOLCHAIN_PREFIX "${_ANDROID_TOOL_PREFIX}") + +set(_ANDROID_TOOL_C_TOOLCHAIN_VERSION "${_ANDROID_TOOL_VERS}") +set(_ANDROID_TOOL_C_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_NAME}/prebuilt/${_ANDROID_HOST_DIR}/bin/${_ANDROID_TOOL_PREFIX}") +set(_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX "${_ANDROID_HOST_EXT}") + +set(_ANDROID_TOOL_CXX_TOOLCHAIN_VERSION "${_ANDROID_TOOL_C_TOOLCHAIN_VERSION}") +set(_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX "${_ANDROID_TOOL_C_TOOLCHAIN_PREFIX}") +set(_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX "${_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX}") + +if(_ANDROID_TOOL_CLANG_NAME) + message(STATUS "Android: Selected Clang toolchain '${_ANDROID_TOOL_CLANG_NAME}' with GCC toolchain '${_ANDROID_TOOL_NAME}'") + set(_ANDROID_TOOL_C_COMPILER "${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_LLVM_NAME}/prebuilt/${_ANDROID_HOST_DIR}/bin/clang${_ANDROID_HOST_EXT}") + set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN ${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_NAME}/prebuilt/${_ANDROID_HOST_DIR}) + set(_ANDROID_TOOL_CXX_COMPILER "${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_LLVM_NAME}/prebuilt/${_ANDROID_HOST_DIR}/bin/clang++${_ANDROID_HOST_EXT}") + set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "${_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN}") +else() + message(STATUS "Android: Selected GCC toolchain '${_ANDROID_TOOL_NAME}'") + set(_ANDROID_TOOL_C_COMPILER "${_ANDROID_TOOL_C_TOOLCHAIN_PREFIX}gcc${_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX}") + set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN "") + set(_ANDROID_TOOL_CXX_COMPILER "${_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX}g++${_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX}") + set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "") +endif() + +if(CMAKE_ANDROID_NDK_TOOLCHAIN_DEBUG) + message(STATUS "_ANDROID_TOOL_NAME=${_ANDROID_TOOL_NAME}") + message(STATUS "_ANDROID_TOOL_VERS=${_ANDROID_TOOL_VERS}") + message(STATUS "_ANDROID_TOOL_PREFIX=${_ANDROID_TOOL_PREFIX}") + message(STATUS "_ANDROID_TOOL_CLANG_NAME=${_ANDROID_TOOL_CLANG_NAME}") + message(STATUS "_ANDROID_TOOL_CLANG_VERS=${_ANDROID_TOOL_CLANG_VERS}") + message(STATUS "_ANDROID_TOOL_LLVM_NAME=${_ANDROID_TOOL_LLVM_NAME}") +endif() + +unset(_ANDROID_TOOL_NAME) +unset(_ANDROID_TOOL_VERS) +unset(_ANDROID_TOOL_PREFIX) +unset(_ANDROID_TOOL_CLANG_NAME) +unset(_ANDROID_TOOL_CLANG_VERS) +unset(_ANDROID_TOOL_LLVM_NAME) +unset(_ANDROID_HOST_DIR) diff --git a/Modules/Platform/Android/Determine-Compiler.cmake b/Modules/Platform/Android/Determine-Compiler.cmake index 67cb671..9649b35 100644 --- a/Modules/Platform/Android/Determine-Compiler.cmake +++ b/Modules/Platform/Android/Determine-Compiler.cmake @@ -26,5 +26,45 @@ if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android") return() endif() +# Identify the host platform. +if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") + set(_ANDROID_HOST_EXT "") +elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + set(_ANDROID_HOST_EXT "") +elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") + set(_ANDROID_HOST_EXT ".exe") +else() + message(FATAL_ERROR "Android: Builds hosted on '${CMAKE_HOST_SYSTEM_NAME}' not supported.") +endif() + +if(CMAKE_ANDROID_NDK) + include(Platform/Android/Determine-Compiler-NDK) +else() + set(_ANDROID_TOOL_C_COMPILER "") + set(_ANDROID_TOOL_C_TOOLCHAIN_VERSION "") + set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN "") + set(_ANDROID_TOOL_C_TOOLCHAIN_PREFIX "") + set(_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX "") + set(_ANDROID_TOOL_CXX_COMPILER "") + set(_ANDROID_TOOL_CXX_TOOLCHAIN_VERSION "") + set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "") + set(_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX "") + set(_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX "") +endif() + +unset(_ANDROID_HOST_EXT) + macro(__android_determine_compiler lang) + if(_ANDROID_TOOL_${lang}_COMPILER) + set(CMAKE_${lang}_COMPILER "${_ANDROID_TOOL_${lang}_COMPILER}") + set(CMAKE_${lang}_COMPILER_EXTERNAL_TOOLCHAIN "${_ANDROID_TOOL_${lang}_COMPILER_EXTERNAL_TOOLCHAIN}") + + # Save the Android-specific information in CMake${lang}Compiler.cmake. + set(CMAKE_${lang}_COMPILER_CUSTOM_CODE " +set(CMAKE_${lang}_ANDROID_TOOLCHAIN_VERSION \"${_ANDROID_TOOL_${lang}_TOOLCHAIN_VERSION}\") +set(CMAKE_${lang}_COMPILER_EXTERNAL_TOOLCHAIN \"${_ANDROID_TOOL_${lang}_COMPILER_EXTERNAL_TOOLCHAIN}\") +set(CMAKE_${lang}_ANDROID_TOOLCHAIN_PREFIX \"${_ANDROID_TOOL_${lang}_TOOLCHAIN_PREFIX}\") +set(CMAKE_${lang}_ANDROID_TOOLCHAIN_SUFFIX \"${_ANDROID_TOOL_${lang}_TOOLCHAIN_SUFFIX}\") +") + endif() endmacro() https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=328191f65f7fb58ece6f749fbfc3462539c7afc1 commit 328191f65f7fb58ece6f749fbfc3462539c7afc1 Author: Brad King AuthorDate: Thu Jun 2 14:46:49 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:52 2016 -0400 Android: Set CMAKE_SYSROOT automatically Compute CMAKE_SYSROOT automatically for the current API and architecture selection. This causes the --sysroot option to be passed to GNU and Clang compilers. diff --git a/Modules/Platform/Android-Initialize.cmake b/Modules/Platform/Android-Initialize.cmake index f12b796..f05357c 100644 --- a/Modules/Platform/Android-Initialize.cmake +++ b/Modules/Platform/Android-Initialize.cmake @@ -20,3 +20,22 @@ if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android") return() endif() + +if(NOT CMAKE_SYSROOT) + if(CMAKE_ANDROID_NDK) + set(CMAKE_SYSROOT "${CMAKE_ANDROID_NDK}/platforms/android-${CMAKE_SYSTEM_VERSION}/arch-${CMAKE_ANDROID_ARCH}") + endif() +endif() + +if(CMAKE_SYSROOT) + if(NOT IS_DIRECTORY "${CMAKE_SYSROOT}") + message(FATAL_ERROR + "Android: The system root directory needed for the selected Android version and architecture does not exist:\n" + " ${CMAKE_SYSROOT}\n" + ) + endif() +else() + message(FATAL_ERROR + "Android: No CMAKE_SYSROOT was selected." + ) +endif() https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9e032304ea4133dd6c59b2c0f3b686d4a7aac2a5 commit 9e032304ea4133dd6c59b2c0f3b686d4a7aac2a5 Author: Brad King AuthorDate: Thu Jun 2 11:29:57 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:52 2016 -0400 Android: Detect and save the architecture, ABI, and processor Add new CMakeSystem.cmake entries for the architecture and ABI. Store the processor in CMAKE_SYSTEM_PROCESSOR. diff --git a/Modules/Platform/Android-Determine.cmake b/Modules/Platform/Android-Determine.cmake index 4dee822..dbbdbf2 100644 --- a/Modules/Platform/Android-Determine.cmake +++ b/Modules/Platform/Android-Determine.cmake @@ -87,10 +87,97 @@ if(NOT CMAKE_SYSTEM_VERSION MATCHES "^[0-9]+$") message(FATAL_ERROR "Android: The API specified by CMAKE_SYSTEM_VERSION='${CMAKE_SYSTEM_VERSION}' is not an integer.") endif() +# https://developer.android.com/ndk/guides/abis.html + +set(_ANDROID_ABI_arm64-v8a_PROC "aarch64") +set(_ANDROID_ABI_arm64-v8a_ARCH "arm64") +set(_ANDROID_ABI_armeabi-v7a_PROC "armv7-a") +set(_ANDROID_ABI_armeabi-v7a_ARCH "arm") +set(_ANDROID_ABI_armeabi-v6_PROC "armv6") +set(_ANDROID_ABI_armeabi-v6_ARCH "arm") +set(_ANDROID_ABI_armeabi_PROC "armv5te") +set(_ANDROID_ABI_armeabi_ARCH "arm") +set(_ANDROID_ABI_mips_PROC "mips") +set(_ANDROID_ABI_mips_ARCH "mips") +set(_ANDROID_ABI_mips64_PROC "mips64") +set(_ANDROID_ABI_mips64_ARCH "mips64") +set(_ANDROID_ABI_x86_PROC "i686") +set(_ANDROID_ABI_x86_ARCH "x86") +set(_ANDROID_ABI_x86_64_PROC "x86_64") +set(_ANDROID_ABI_x86_64_ARCH "x86_64") + +set(_ANDROID_PROC_aarch64_ARCH_ABI "arm64-v8a") +set(_ANDROID_PROC_armv7-a_ARCH_ABI "armeabi-v7a") +set(_ANDROID_PROC_armv6_ARCH_ABI "armeabi-v6") +set(_ANDROID_PROC_armv5te_ARCH_ABI "armeabi") +set(_ANDROID_PROC_i686_ARCH_ABI "x86") +set(_ANDROID_PROC_mips_ARCH_ABI "mips") +set(_ANDROID_PROC_mips64_ARCH_ABI "mips64") +set(_ANDROID_PROC_x86_64_ARCH_ABI "x86_64") + +# Validate inputs. +if(CMAKE_ANDROID_ARCH_ABI AND NOT DEFINED "_ANDROID_ABI_${CMAKE_ANDROID_ARCH_ABI}_PROC") + message(FATAL_ERROR "Android: Unknown ABI CMAKE_ANDROID_ARCH_ABI='${CMAKE_ANDROID_ARCH_ABI}'.") +endif() +if(CMAKE_SYSTEM_PROCESSOR AND NOT DEFINED "_ANDROID_PROC_${CMAKE_SYSTEM_PROCESSOR}_ARCH_ABI") + message(FATAL_ERROR "Android: Unknown processor CMAKE_SYSTEM_PROCESSOR='${CMAKE_SYSTEM_PROCESSOR}'.") +endif() + +# Select an ABI. +if(NOT CMAKE_ANDROID_ARCH_ABI) + if(CMAKE_SYSTEM_PROCESSOR) + set(CMAKE_ANDROID_ARCH_ABI "${_ANDROID_PROC_${CMAKE_SYSTEM_PROCESSOR}_ARCH_ABI}") + else() + # https://developer.android.com/ndk/guides/application_mk.html + # Default is the oldest ARM ABI. + set(CMAKE_ANDROID_ARCH_ABI "armeabi") + endif() +endif() +set(CMAKE_ANDROID_ARCH "${_ANDROID_ABI_${CMAKE_ANDROID_ARCH_ABI}_ARCH}") + +# Select a processor. +if(NOT CMAKE_SYSTEM_PROCESSOR) + set(CMAKE_SYSTEM_PROCESSOR "${_ANDROID_ABI_${CMAKE_ANDROID_ARCH_ABI}_PROC}") +endif() + +# If the user specified both an ABI and a processor then they might not match. +if(NOT _ANDROID_ABI_${CMAKE_ANDROID_ARCH_ABI}_PROC STREQUAL CMAKE_SYSTEM_PROCESSOR) + message(FATAL_ERROR "Android: The specified CMAKE_ANDROID_ARCH_ABI='${CMAKE_ANDROID_ARCH_ABI}' and CMAKE_SYSTEM_PROCESSOR='${CMAKE_SYSTEM_PROCESSOR}' is not a valid combination.") +endif() + # Save the Android-specific information in CMakeSystem.cmake. set(CMAKE_SYSTEM_CUSTOM_CODE " set(CMAKE_ANDROID_NDK \"${CMAKE_ANDROID_NDK}\") +set(CMAKE_ANDROID_ARCH \"${CMAKE_ANDROID_ARCH}\") +set(CMAKE_ANDROID_ARCH_ABI \"${CMAKE_ANDROID_ARCH_ABI}\") ") +# Select an ARM variant. +if(CMAKE_ANDROID_ARCH_ABI MATCHES "^armeabi") + if(CMAKE_ANDROID_ARM_MODE) + set(CMAKE_ANDROID_ARM_MODE 1) + else() + set(CMAKE_ANDROID_ARM_MODE 0) + endif() + string(APPEND CMAKE_SYSTEM_CUSTOM_CODE + "set(CMAKE_ANDROID_ARM_MODE \"${CMAKE_ANDROID_ARM_MODE}\")\n" + ) +elseif(DEFINED CMAKE_ANDROID_ARM_MODE) + message(FATAL_ERROR "Android: CMAKE_ANDROID_ARM_MODE is set but is valid only for 'armeabi' architectures.") +endif() + +if(CMAKE_ANDROID_ARCH_ABI STREQUAL "armeabi-v7a") + if(CMAKE_ANDROID_ARM_NEON) + set(CMAKE_ANDROID_ARM_NEON 1) + else() + set(CMAKE_ANDROID_ARM_NEON 0) + endif() + string(APPEND CMAKE_SYSTEM_CUSTOM_CODE + "set(CMAKE_ANDROID_ARM_NEON \"${CMAKE_ANDROID_ARM_NEON}\")\n" + ) +elseif(DEFINED CMAKE_ANDROID_ARM_NEON) + message(FATAL_ERROR "Android: CMAKE_ANDROID_ARM_NEON is set but is valid only for 'armeabi-v7a' architecture.") +endif() + # Report the chosen architecture. -message(STATUS "Android: Targeting API '${CMAKE_SYSTEM_VERSION}'") +message(STATUS "Android: Targeting API '${CMAKE_SYSTEM_VERSION}' with architecture '${CMAKE_ANDROID_ARCH}', ABI '${CMAKE_ANDROID_ARCH_ABI}', and processor '${CMAKE_SYSTEM_PROCESSOR}'") https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=fde59c4d882e104459dbdf8a07a22899427b6657 commit fde59c4d882e104459dbdf8a07a22899427b6657 Author: Brad King AuthorDate: Thu Jun 2 11:26:32 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:52 2016 -0400 Android: Detect and save the API level Store the Android API level in CMAKE_SYSTEM_VERSION. If it is not provided by the user, initialize it from CMAKE_ANDROID_API or fall back to finding the latest available in the NDK. diff --git a/Modules/Platform/Android-Determine.cmake b/Modules/Platform/Android-Determine.cmake index 7e7acd4..4dee822 100644 --- a/Modules/Platform/Android-Determine.cmake +++ b/Modules/Platform/Android-Determine.cmake @@ -42,7 +42,55 @@ if(NOT CMAKE_ANDROID_NDK) message(FATAL_ERROR "Android: The NDK root directory was not found.") endif() +# Select an API. +if(CMAKE_SYSTEM_VERSION) + set(_ANDROID_API_VAR CMAKE_SYSTEM_VERSION) +elseif(CMAKE_ANDROID_API) + set(CMAKE_SYSTEM_VERSION "${CMAKE_ANDROID_API}") + set(_ANDROID_API_VAR CMAKE_ANDROID_API) +endif() +if(CMAKE_SYSTEM_VERSION) + if(CMAKE_ANDROID_API AND NOT "x${CMAKE_ANDROID_API}" STREQUAL "x${CMAKE_SYSTEM_VERSION}") + message(FATAL_ERROR + "Android: The API specified by CMAKE_ANDROID_API='${CMAKE_ANDROID_API}' is not consistent with CMAKE_SYSTEM_VERSION='${CMAKE_SYSTEM_VERSION}'." + ) + endif() + if(CMAKE_ANDROID_NDK AND NOT IS_DIRECTORY "${CMAKE_ANDROID_NDK}/platforms/android-${CMAKE_SYSTEM_VERSION}") + message(FATAL_ERROR + "Android: The API specified by ${_ANDROID_API_VAR}='${${_ANDROID_API_VAR}}' does not exist in the NDK. " + "The directory:\n" + " ${CMAKE_ANDROID_NDK}/platforms/android-${CMAKE_SYSTEM_VERSION}\n" + "does not exist." + ) + endif() +elseif(CMAKE_ANDROID_NDK) + file(GLOB _ANDROID_APIS_1 RELATIVE "${CMAKE_ANDROID_NDK}/platforms" "${CMAKE_ANDROID_NDK}/platforms/android-[0-9]") + file(GLOB _ANDROID_APIS_2 RELATIVE "${CMAKE_ANDROID_NDK}/platforms" "${CMAKE_ANDROID_NDK}/platforms/android-[0-9][0-9]") + list(SORT _ANDROID_APIS_1) + list(SORT _ANDROID_APIS_2) + set(_ANDROID_APIS ${_ANDROID_APIS_1} ${_ANDROID_APIS_2}) + unset(_ANDROID_APIS_1) + unset(_ANDROID_APIS_2) + if(_ANDROID_APIS STREQUAL "") + message(FATAL_ERROR + "Android: No APIs found in the NDK. No\n" + " ${CMAKE_ANDROID_NDK}/platforms/android-*\n" + "directories exist." + ) + endif() + string(REPLACE "android-" "" _ANDROID_APIS "${_ANDROID_APIS}") + list(REVERSE _ANDROID_APIS) + list(GET _ANDROID_APIS 0 CMAKE_SYSTEM_VERSION) + unset(_ANDROID_APIS) +endif() +if(NOT CMAKE_SYSTEM_VERSION MATCHES "^[0-9]+$") + message(FATAL_ERROR "Android: The API specified by CMAKE_SYSTEM_VERSION='${CMAKE_SYSTEM_VERSION}' is not an integer.") +endif() + # Save the Android-specific information in CMakeSystem.cmake. set(CMAKE_SYSTEM_CUSTOM_CODE " set(CMAKE_ANDROID_NDK \"${CMAKE_ANDROID_NDK}\") ") + +# Report the chosen architecture. +message(STATUS "Android: Targeting API '${CMAKE_SYSTEM_VERSION}'") https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=52b6effd817ae44577f86df4f382b0c98df7402a commit 52b6effd817ae44577f86df4f382b0c98df7402a Author: Brad King AuthorDate: Thu Jun 2 11:16:21 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:52 2016 -0400 Android: Detect and save the NDK directory Add a new CMakeSystem.cmake entry for the NDK location. diff --git a/Modules/Platform/Android-Determine.cmake b/Modules/Platform/Android-Determine.cmake index 6a33290..7e7acd4 100644 --- a/Modules/Platform/Android-Determine.cmake +++ b/Modules/Platform/Android-Determine.cmake @@ -12,6 +12,8 @@ # License text for the above reference.) # When CMAKE_SYSTEM_NAME is "Android", CMakeDetermineSystem loads this module. +# This module detects platform-wide information about the Android target +# in order to store it in "CMakeSystem.cmake". # Support for NVIDIA Nsight Tegra Visual Studio Edition was previously # implemented in the CMake VS IDE generators. Avoid interfering with @@ -19,3 +21,28 @@ if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android") return() endif() + +# Find the Android NDK. +if(CMAKE_ANDROID_NDK) + if(NOT IS_DIRECTORY "${CMAKE_ANDROID_NDK}") + message(FATAL_ERROR + "Android: The NDK root directory specified by CMAKE_ANDROID_NDK:\n" + " ${CMAKE_ANDROID_NDK}\n" + "does not exist." + ) + endif() +else() + if(IS_DIRECTORY "$ENV{ANDROID_NDK_ROOT}") + file(TO_CMAKE_PATH "$ENV{ANDROID_NDK_ROOT}" CMAKE_ANDROID_NDK) + endif() + # TODO: Search harder for the NDK. +endif() + +if(NOT CMAKE_ANDROID_NDK) + message(FATAL_ERROR "Android: The NDK root directory was not found.") +endif() + +# Save the Android-specific information in CMakeSystem.cmake. +set(CMAKE_SYSTEM_CUSTOM_CODE " +set(CMAKE_ANDROID_NDK \"${CMAKE_ANDROID_NDK}\") +") https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8e0cb45e5591cc778b054780f9e6290c3f239815 commit 8e0cb45e5591cc778b054780f9e6290c3f239815 Author: Brad King AuthorDate: Thu Jun 2 10:24:44 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:52 2016 -0400 Android: Suppress new functionality with Nsight Tegra in VS IDE builds Support for NVIDIA Nsight Tegra Visual Studio Edition was previously implemented in the CMake VS IDE generators. Avoid interfering with that functionality for now. Later we may try to integrate this. diff --git a/Modules/Platform/Android-Clang.cmake b/Modules/Platform/Android-Clang.cmake index b354b4c..dc398bb 100644 --- a/Modules/Platform/Android-Clang.cmake +++ b/Modules/Platform/Android-Clang.cmake @@ -17,6 +17,15 @@ if(__ANDROID_COMPILER_CLANG) endif() set(__ANDROID_COMPILER_CLANG 1) +# Support for NVIDIA Nsight Tegra Visual Studio Edition was previously +# implemented in the CMake VS IDE generators. Avoid interfering with +# that functionality for now. Later we may try to integrate this. +if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android") + macro(__android_compiler_clang lang) + endmacro() + return() +endif() + include(Platform/Android-Common) macro(__android_compiler_clang lang) diff --git a/Modules/Platform/Android-Determine.cmake b/Modules/Platform/Android-Determine.cmake index d93377e..6a33290 100644 --- a/Modules/Platform/Android-Determine.cmake +++ b/Modules/Platform/Android-Determine.cmake @@ -12,3 +12,10 @@ # License text for the above reference.) # When CMAKE_SYSTEM_NAME is "Android", CMakeDetermineSystem loads this module. + +# Support for NVIDIA Nsight Tegra Visual Studio Edition was previously +# implemented in the CMake VS IDE generators. Avoid interfering with +# that functionality for now. Later we may try to integrate this. +if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android") + return() +endif() diff --git a/Modules/Platform/Android-GNU.cmake b/Modules/Platform/Android-GNU.cmake index 13369d0..4f25bf3 100644 --- a/Modules/Platform/Android-GNU.cmake +++ b/Modules/Platform/Android-GNU.cmake @@ -17,6 +17,15 @@ if(__ANDROID_COMPILER_GNU) endif() set(__ANDROID_COMPILER_GNU 1) +# Support for NVIDIA Nsight Tegra Visual Studio Edition was previously +# implemented in the CMake VS IDE generators. Avoid interfering with +# that functionality for now. Later we may try to integrate this. +if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android") + macro(__android_compiler_gnu lang) + endmacro() + return() +endif() + include(Platform/Android-Common) macro(__android_compiler_gnu lang) diff --git a/Modules/Platform/Android-Initialize.cmake b/Modules/Platform/Android-Initialize.cmake index e1e57a3..f12b796 100644 --- a/Modules/Platform/Android-Initialize.cmake +++ b/Modules/Platform/Android-Initialize.cmake @@ -13,3 +13,10 @@ # When CMAKE_SYSTEM_NAME is "Android", CMakeSystemSpecificInitialize loads this # module. + +# Support for NVIDIA Nsight Tegra Visual Studio Edition was previously +# implemented in the CMake VS IDE generators. Avoid interfering with +# that functionality for now. Later we may try to integrate this. +if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android") + return() +endif() diff --git a/Modules/Platform/Android/Determine-Compiler.cmake b/Modules/Platform/Android/Determine-Compiler.cmake index a036481..67cb671 100644 --- a/Modules/Platform/Android/Determine-Compiler.cmake +++ b/Modules/Platform/Android/Determine-Compiler.cmake @@ -17,5 +17,14 @@ if(__ANDROID_DETERMINE_COMPILER) endif() set(__ANDROID_DETERMINE_COMPILER 1) +# Support for NVIDIA Nsight Tegra Visual Studio Edition was previously +# implemented in the CMake VS IDE generators. Avoid interfering with +# that functionality for now. Later we may try to integrate this. +if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android") + macro(__android_determine_compiler lang) + endmacro() + return() +endif() + macro(__android_determine_compiler lang) endmacro() https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d5e7d5f3ebb42e1a8b38e4bd30f717cdac81ed77 commit d5e7d5f3ebb42e1a8b38e4bd30f717cdac81ed77 Author: Brad King AuthorDate: Thu Jun 2 10:23:20 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:51 2016 -0400 Android: Add placeholders for platform-specific initialization Add infrastructure modules to be loaded when initializing builds targeting Android platforms. diff --git a/Modules/Platform/Android-Determine.cmake b/Modules/Platform/Android-Determine.cmake new file mode 100644 index 0000000..d93377e --- /dev/null +++ b/Modules/Platform/Android-Determine.cmake @@ -0,0 +1,14 @@ +#============================================================================= +# Copyright 2015-2016 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# When CMAKE_SYSTEM_NAME is "Android", CMakeDetermineSystem loads this module. diff --git a/Modules/Platform/Android-Initialize.cmake b/Modules/Platform/Android-Initialize.cmake new file mode 100644 index 0000000..e1e57a3 --- /dev/null +++ b/Modules/Platform/Android-Initialize.cmake @@ -0,0 +1,15 @@ +#============================================================================= +# Copyright 2015-2016 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# When CMAKE_SYSTEM_NAME is "Android", CMakeSystemSpecificInitialize loads this +# module. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=64be1ae4a3ae98e63cf35d495f0ca06c77cdf923 commit 64be1ae4a3ae98e63cf35d495f0ca06c77cdf923 Author: Brad King AuthorDate: Thu Jun 2 10:19:59 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:51 2016 -0400 Android: Add placeholders for platform-specific compiler selection Add infrastructure modules to be loaded for determining a compiler selection when targeting Android platforms. diff --git a/Modules/Platform/Android-Determine-C.cmake b/Modules/Platform/Android-Determine-C.cmake new file mode 100644 index 0000000..c7d1d15 --- /dev/null +++ b/Modules/Platform/Android-Determine-C.cmake @@ -0,0 +1,2 @@ +include(Platform/Android/Determine-Compiler) +__android_determine_compiler(C) diff --git a/Modules/Platform/Android-Determine-CXX.cmake b/Modules/Platform/Android-Determine-CXX.cmake new file mode 100644 index 0000000..3a3de88 --- /dev/null +++ b/Modules/Platform/Android-Determine-CXX.cmake @@ -0,0 +1,2 @@ +include(Platform/Android/Determine-Compiler) +__android_determine_compiler(CXX) diff --git a/Modules/Platform/Android/Determine-Compiler.cmake b/Modules/Platform/Android/Determine-Compiler.cmake new file mode 100644 index 0000000..a036481 --- /dev/null +++ b/Modules/Platform/Android/Determine-Compiler.cmake @@ -0,0 +1,21 @@ +#============================================================================= +# Copyright 2015-2016 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# This module is shared by multiple languages; use include blocker. +if(__ANDROID_DETERMINE_COMPILER) + return() +endif() +set(__ANDROID_DETERMINE_COMPILER 1) + +macro(__android_determine_compiler lang) +endmacro() https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=47866770cee381851ccc8070f64459909a838288 commit 47866770cee381851ccc8070f64459909a838288 Author: Brad King AuthorDate: Thu Jun 2 10:16:11 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:51 2016 -0400 Android: Add placeholders for platform-specific compiler settings Add infrastructure modules to be loaded for Clang and GNU compilers when targeting Android platforms. diff --git a/Modules/Platform/Android-Clang-C.cmake b/Modules/Platform/Android-Clang-C.cmake new file mode 100644 index 0000000..9e16911 --- /dev/null +++ b/Modules/Platform/Android-Clang-C.cmake @@ -0,0 +1,2 @@ +include(Platform/Android-Clang) +__android_compiler_clang(C) diff --git a/Modules/Platform/Android-Clang-CXX.cmake b/Modules/Platform/Android-Clang-CXX.cmake new file mode 100644 index 0000000..7111836 --- /dev/null +++ b/Modules/Platform/Android-Clang-CXX.cmake @@ -0,0 +1,2 @@ +include(Platform/Android-Clang) +__android_compiler_clang(CXX) diff --git a/Modules/Platform/Android-Clang.cmake b/Modules/Platform/Android-Clang.cmake new file mode 100644 index 0000000..b354b4c --- /dev/null +++ b/Modules/Platform/Android-Clang.cmake @@ -0,0 +1,24 @@ +#============================================================================= +# Copyright 2015-2016 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# This module is shared by multiple languages; use include blocker. +if(__ANDROID_COMPILER_CLANG) + return() +endif() +set(__ANDROID_COMPILER_CLANG 1) + +include(Platform/Android-Common) + +macro(__android_compiler_clang lang) + __android_compiler_common(${lang}) +endmacro() diff --git a/Modules/Platform/Android-Common.cmake b/Modules/Platform/Android-Common.cmake new file mode 100644 index 0000000..0ef9512 --- /dev/null +++ b/Modules/Platform/Android-Common.cmake @@ -0,0 +1,21 @@ +#============================================================================= +# Copyright 2015-2016 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# This module is shared by multiple languages; use include blocker. +if(__ANDROID_COMPILER_COMMON) + return() +endif() +set(__ANDROID_COMPILER_COMMON 1) + +macro(__android_compiler_common lang) +endmacro() diff --git a/Modules/Platform/Android-GNU-C.cmake b/Modules/Platform/Android-GNU-C.cmake new file mode 100644 index 0000000..78a6a50 --- /dev/null +++ b/Modules/Platform/Android-GNU-C.cmake @@ -0,0 +1,2 @@ +include(Platform/Android-GNU) +__android_compiler_gnu(C) diff --git a/Modules/Platform/Android-GNU-CXX.cmake b/Modules/Platform/Android-GNU-CXX.cmake new file mode 100644 index 0000000..41279d1 --- /dev/null +++ b/Modules/Platform/Android-GNU-CXX.cmake @@ -0,0 +1,2 @@ +include(Platform/Android-GNU) +__android_compiler_gnu(CXX) diff --git a/Modules/Platform/Android-GNU.cmake b/Modules/Platform/Android-GNU.cmake new file mode 100644 index 0000000..13369d0 --- /dev/null +++ b/Modules/Platform/Android-GNU.cmake @@ -0,0 +1,24 @@ +#============================================================================= +# Copyright 2015-2016 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# This module is shared by multiple languages; use include blocker. +if(__ANDROID_COMPILER_GNU) + return() +endif() +set(__ANDROID_COMPILER_GNU 1) + +include(Platform/Android-Common) + +macro(__android_compiler_gnu lang) + __android_compiler_common(${lang}) +endmacro() https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=735f168bf08a4fdf1d9e245035d2dbcadbed652f commit 735f168bf08a4fdf1d9e245035d2dbcadbed652f Author: Brad King AuthorDate: Thu Jun 2 10:07:10 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:51 2016 -0400 CMakeDetermine*Compiler: Add hook to save custom compiler information Provide a way for Platform/-Determine-.cmake modules to save platform-specific information about the compiler in the configured CMakeCompiler.cmake modules. diff --git a/Modules/CMakeCCompiler.cmake.in b/Modules/CMakeCCompiler.cmake.in index f109a14..50b12f2 100644 --- a/Modules/CMakeCCompiler.cmake.in +++ b/Modules/CMakeCCompiler.cmake.in @@ -59,6 +59,7 @@ if(CMAKE_C_CL_SHOWINCLUDES_PREFIX) set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_C_CL_SHOWINCLUDES_PREFIX}") endif() + at CMAKE_C_COMPILER_CUSTOM_CODE@ @CMAKE_C_SYSROOT_FLAG_CODE@ @CMAKE_C_OSX_DEPLOYMENT_TARGET_FLAG_CODE@ diff --git a/Modules/CMakeCXXCompiler.cmake.in b/Modules/CMakeCXXCompiler.cmake.in index 9e90aea..c295b74 100644 --- a/Modules/CMakeCXXCompiler.cmake.in +++ b/Modules/CMakeCXXCompiler.cmake.in @@ -60,6 +60,7 @@ if(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX) set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_CXX_CL_SHOWINCLUDES_PREFIX}") endif() + at CMAKE_CXX_COMPILER_CUSTOM_CODE@ @CMAKE_CXX_SYSROOT_FLAG_CODE@ @CMAKE_CXX_OSX_DEPLOYMENT_TARGET_FLAG_CODE@ diff --git a/Modules/CMakeFortranCompiler.cmake.in b/Modules/CMakeFortranCompiler.cmake.in index 2a4bea4..8e92f65 100644 --- a/Modules/CMakeFortranCompiler.cmake.in +++ b/Modules/CMakeFortranCompiler.cmake.in @@ -54,6 +54,8 @@ if(CMAKE_Fortran_LIBRARY_ARCHITECTURE) set(CMAKE_LIBRARY_ARCHITECTURE "@CMAKE_Fortran_LIBRARY_ARCHITECTURE@") endif() + at CMAKE_Fortran_COMPILER_CUSTOM_CODE@ + set(CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES "@CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES@") set(CMAKE_Fortran_IMPLICIT_LINK_DIRECTORIES "@CMAKE_Fortran_IMPLICIT_LINK_DIRECTORIES@") set(CMAKE_Fortran_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_Fortran_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@") https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c148803a575ed1c3639123190b1d6a5d31578f34 commit c148803a575ed1c3639123190b1d6a5d31578f34 Author: Brad King AuthorDate: Thu Jun 2 10:01:12 2016 -0400 Commit: Brad King CommitDate: Fri Aug 12 10:40:51 2016 -0400 CMakeDetermineSystem: Load platform-specific helper modules Once CMAKE_SYSTEM_NAME is known, load a platform-specific Platform/-Determine module in order to enable custom determination of the other settings needed for the CMakeSystem module (e.g. CMAKE_SYSTEM_PROCESSOR). Also add a hook in Modules/CMakeSystem.cmake.in to allow platform-specific information to be saved. diff --git a/Modules/CMakeDetermineSystem.cmake b/Modules/CMakeDetermineSystem.cmake index d9f7579..f7a32b7 100644 --- a/Modules/CMakeDetermineSystem.cmake +++ b/Modules/CMakeDetermineSystem.cmake @@ -131,6 +131,7 @@ else() set(PRESET_CMAKE_SYSTEM_NAME FALSE) endif() +include(Platform/${CMAKE_SYSTEM_NAME}-Determine OPTIONAL) macro(ADJUST_CMAKE_SYSTEM_VARIABLES _PREFIX) if(NOT ${_PREFIX}_NAME) diff --git a/Modules/CMakeSystem.cmake.in b/Modules/CMakeSystem.cmake.in index 70c98d5..ef8aaa0 100644 --- a/Modules/CMakeSystem.cmake.in +++ b/Modules/CMakeSystem.cmake.in @@ -9,7 +9,7 @@ set(CMAKE_SYSTEM "@CMAKE_SYSTEM@") set(CMAKE_SYSTEM_NAME "@CMAKE_SYSTEM_NAME@") set(CMAKE_SYSTEM_VERSION "@CMAKE_SYSTEM_VERSION@") set(CMAKE_SYSTEM_PROCESSOR "@CMAKE_SYSTEM_PROCESSOR@") - + at CMAKE_SYSTEM_CUSTOM_CODE@ set(CMAKE_CROSSCOMPILING "@CMAKE_CROSSCOMPILING@") set(CMAKE_SYSTEM_LOADED 1) ----------------------------------------------------------------------- Summary of changes: Help/manual/cmake-toolchains.7.rst | 204 ++++++++++++- Help/manual/cmake-variables.7.rst | 9 + Help/prop_tgt/ANDROID_API.rst | 9 +- Help/prop_tgt/ANDROID_ARCH.rst | 3 +- Help/prop_tgt/ANDROID_GUI.rst | 4 +- Help/prop_tgt/ANDROID_STL_TYPE.rst | 32 ++- Help/release/dev/android-platform-modules.rst | 5 + Help/variable/ANDROID.rst | 5 + Help/variable/CMAKE_ANDROID_API.rst | 10 +- Help/variable/CMAKE_ANDROID_ARCH.rst | 18 +- Help/variable/CMAKE_ANDROID_ARCH_ABI.rst | 17 ++ Help/variable/CMAKE_ANDROID_ARM_MODE.rst | 7 + Help/variable/CMAKE_ANDROID_ARM_NEON.rst | 6 + Help/variable/CMAKE_ANDROID_NDK.rst | 7 + .../CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION.rst | 13 + .../CMAKE_ANDROID_STANDALONE_TOOLCHAIN.rst | 6 + Help/variable/CMAKE_ANDROID_STL_TYPE.rst | 35 ++- .../CMAKE_LANG_ANDROID_TOOLCHAIN_PREFIX.rst | 11 + .../CMAKE_LANG_ANDROID_TOOLCHAIN_SUFFIX.rst | 7 + Modules/CMakeCCompiler.cmake.in | 1 + Modules/CMakeCXXCompiler.cmake.in | 1 + Modules/CMakeDetermineSystem.cmake | 1 + Modules/CMakeFortranCompiler.cmake.in | 2 + Modules/CMakeSystem.cmake.in | 2 +- Modules/Platform/Android-Clang-C.cmake | 2 + Modules/Platform/Android-Clang-CXX.cmake | 2 + Modules/Platform/Android-Clang.cmake | 52 ++++ Modules/Platform/Android-Common.cmake | 158 ++++++++++ Modules/Platform/Android-Determine-C.cmake | 2 + Modules/Platform/Android-Determine-CXX.cmake | 2 + Modules/Platform/Android-Determine.cmake | 301 ++++++++++++++++++++ Modules/Platform/Android-GNU-C.cmake | 2 + Modules/Platform/Android-GNU-CXX.cmake | 2 + Modules/Platform/Android-GNU.cmake | 43 +++ Modules/Platform/Android-Initialize.cmake | 51 ++++ Modules/Platform/Android.cmake | 2 + .../Platform/Android/Determine-Compiler-NDK.cmake | 256 +++++++++++++++++ .../Android/Determine-Compiler-Standalone.cmake | 69 +++++ Modules/Platform/Android/Determine-Compiler.cmake | 80 ++++++ Modules/Platform/Android/abi-arm64-v8a-Clang.cmake | 8 + Modules/Platform/Android/abi-arm64-v8a-GNU.cmake | 6 + Modules/Platform/Android/abi-armeabi-Clang.cmake | 20 ++ Modules/Platform/Android/abi-armeabi-GNU.cmake | 18 ++ .../Platform/Android/abi-armeabi-v6-Clang.cmake | 19 ++ Modules/Platform/Android/abi-armeabi-v6-GNU.cmake | 17 ++ .../Platform/Android/abi-armeabi-v7a-Clang.cmake | 29 ++ Modules/Platform/Android/abi-armeabi-v7a-GNU.cmake | 27 ++ Modules/Platform/Android/abi-common-Clang.cmake | 6 + Modules/Platform/Android/abi-common-GNU.cmake | 1 + Modules/Platform/Android/abi-common.cmake | 4 + Modules/Platform/Android/abi-mips-Clang.cmake | 8 + Modules/Platform/Android/abi-mips-GNU.cmake | 6 + Modules/Platform/Android/abi-mips64-Clang.cmake | 8 + Modules/Platform/Android/abi-mips64-GNU.cmake | 6 + Modules/Platform/Android/abi-x86-Clang.cmake | 8 + Modules/Platform/Android/abi-x86-GNU.cmake | 2 + Modules/Platform/Android/abi-x86_64-Clang.cmake | 8 + Modules/Platform/Android/abi-x86_64-GNU.cmake | 2 + Modules/Platform/Android/ndk-stl-c++.cmake | 13 + Modules/Platform/Android/ndk-stl-c++_shared.cmake | 4 + Modules/Platform/Android/ndk-stl-c++_static.cmake | 6 + Modules/Platform/Android/ndk-stl-gabi++.cmake | 7 + .../Platform/Android/ndk-stl-gabi++_shared.cmake | 4 + .../Platform/Android/ndk-stl-gabi++_static.cmake | 4 + Modules/Platform/Android/ndk-stl-gnustl.cmake | 9 + .../Platform/Android/ndk-stl-gnustl_shared.cmake | 4 + .../Platform/Android/ndk-stl-gnustl_static.cmake | 4 + Modules/Platform/Android/ndk-stl-none.cmake | 2 + Modules/Platform/Android/ndk-stl-stlport.cmake | 7 + .../Platform/Android/ndk-stl-stlport_shared.cmake | 4 + .../Platform/Android/ndk-stl-stlport_static.cmake | 4 + Modules/Platform/Android/ndk-stl-system.cmake | 6 + .../BadSYSROOT-result.txt} | 0 Tests/RunCMake/Android/BadSYSROOT-stderr.txt | 20 ++ .../RunCMake/Android/BadSYSROOT.cmake | 0 Tests/RunCMake/Android/CMakeLists.txt | 3 + Tests/RunCMake/Android/RunCMakeTest.cmake | 218 ++++++++++++++ Tests/RunCMake/Android/android.c | 6 + Tests/RunCMake/Android/android.cxx | 45 +++ Tests/RunCMake/Android/android.h | 103 +++++++ Tests/RunCMake/Android/common.cmake | 60 ++++ Tests/RunCMake/Android/ndk-arm64-v8a-stdout.txt | 2 + Tests/RunCMake/Android/ndk-arm64-v8a.cmake | 1 + Tests/RunCMake/Android/ndk-armeabi-arm-stdout.txt | 3 + Tests/RunCMake/Android/ndk-armeabi-arm.cmake | 1 + .../RunCMake/Android/ndk-armeabi-thumb-stdout.txt | 3 + Tests/RunCMake/Android/ndk-armeabi-thumb.cmake | 1 + .../Android/ndk-armeabi-v7a-neon-stdout.txt | 3 + Tests/RunCMake/Android/ndk-armeabi-v7a-neon.cmake | 1 + Tests/RunCMake/Android/ndk-armeabi-v7a-stdout.txt | 3 + Tests/RunCMake/Android/ndk-armeabi-v7a.cmake | 1 + .../ndk-badabi-result.txt} | 0 Tests/RunCMake/Android/ndk-badabi-stderr.txt | 5 + .../RunCMake/Android/ndk-badabi.cmake | 0 .../ndk-badarm-result.txt} | 0 Tests/RunCMake/Android/ndk-badarm-stderr.txt | 6 + .../RunCMake/Android/ndk-badarm.cmake | 0 .../ndk-badneon-result.txt} | 0 Tests/RunCMake/Android/ndk-badneon-stderr.txt | 6 + .../RunCMake/Android/ndk-badneon.cmake | 0 .../ndk-badstl-result.txt} | 0 Tests/RunCMake/Android/ndk-badstl-stderr.txt | 9 + Tests/RunCMake/Android/ndk-badstl.cmake | 1 + .../ndk-badver-result.txt} | 0 Tests/RunCMake/Android/ndk-badver-stderr.txt | 12 + Tests/RunCMake/Android/ndk-badver.cmake | 1 + .../ndk-badvernum-result.txt} | 0 Tests/RunCMake/Android/ndk-badvernum-stderr.txt | 13 + Tests/RunCMake/Android/ndk-badvernum.cmake | 1 + Tests/RunCMake/Android/ndk-mips-stdout.txt | 2 + Tests/RunCMake/Android/ndk-mips.cmake | 1 + Tests/RunCMake/Android/ndk-mips64-stdout.txt | 2 + Tests/RunCMake/Android/ndk-mips64.cmake | 1 + .../Android/ndk-sysroot-armeabi-stdout.txt | 1 + .../RunCMake/Android/ndk-sysroot-armeabi.cmake | 0 Tests/RunCMake/Android/ndk-x86-stdout.txt | 2 + Tests/RunCMake/Android/ndk-x86.cmake | 1 + Tests/RunCMake/Android/ndk-x86_64-stdout.txt | 2 + Tests/RunCMake/Android/ndk-x86_64.cmake | 1 + Tests/RunCMake/Android/standalone-stdout.txt | 1 + .../RunCMake/Android/standalone-sysroot-stdout.txt | 1 + .../RunCMake/Android/standalone-sysroot.cmake | 0 Tests/RunCMake/Android/standalone.cmake | 1 + Tests/RunCMake/CMakeLists.txt | 21 ++ 124 files changed, 2257 insertions(+), 28 deletions(-) create mode 100644 Help/release/dev/android-platform-modules.rst create mode 100644 Help/variable/ANDROID.rst create mode 100644 Help/variable/CMAKE_ANDROID_ARCH_ABI.rst create mode 100644 Help/variable/CMAKE_ANDROID_ARM_MODE.rst create mode 100644 Help/variable/CMAKE_ANDROID_ARM_NEON.rst create mode 100644 Help/variable/CMAKE_ANDROID_NDK.rst create mode 100644 Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION.rst create mode 100644 Help/variable/CMAKE_ANDROID_STANDALONE_TOOLCHAIN.rst create mode 100644 Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_PREFIX.rst create mode 100644 Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_SUFFIX.rst create mode 100644 Modules/Platform/Android-Clang-C.cmake create mode 100644 Modules/Platform/Android-Clang-CXX.cmake create mode 100644 Modules/Platform/Android-Clang.cmake create mode 100644 Modules/Platform/Android-Common.cmake create mode 100644 Modules/Platform/Android-Determine-C.cmake create mode 100644 Modules/Platform/Android-Determine-CXX.cmake create mode 100644 Modules/Platform/Android-Determine.cmake create mode 100644 Modules/Platform/Android-GNU-C.cmake create mode 100644 Modules/Platform/Android-GNU-CXX.cmake create mode 100644 Modules/Platform/Android-GNU.cmake create mode 100644 Modules/Platform/Android-Initialize.cmake create mode 100644 Modules/Platform/Android/Determine-Compiler-NDK.cmake create mode 100644 Modules/Platform/Android/Determine-Compiler-Standalone.cmake create mode 100644 Modules/Platform/Android/Determine-Compiler.cmake create mode 100644 Modules/Platform/Android/abi-arm64-v8a-Clang.cmake create mode 100644 Modules/Platform/Android/abi-arm64-v8a-GNU.cmake create mode 100644 Modules/Platform/Android/abi-armeabi-Clang.cmake create mode 100644 Modules/Platform/Android/abi-armeabi-GNU.cmake create mode 100644 Modules/Platform/Android/abi-armeabi-v6-Clang.cmake create mode 100644 Modules/Platform/Android/abi-armeabi-v6-GNU.cmake create mode 100644 Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake create mode 100644 Modules/Platform/Android/abi-armeabi-v7a-GNU.cmake create mode 100644 Modules/Platform/Android/abi-common-Clang.cmake create mode 100644 Modules/Platform/Android/abi-common-GNU.cmake create mode 100644 Modules/Platform/Android/abi-common.cmake create mode 100644 Modules/Platform/Android/abi-mips-Clang.cmake create mode 100644 Modules/Platform/Android/abi-mips-GNU.cmake create mode 100644 Modules/Platform/Android/abi-mips64-Clang.cmake create mode 100644 Modules/Platform/Android/abi-mips64-GNU.cmake create mode 100644 Modules/Platform/Android/abi-x86-Clang.cmake create mode 100644 Modules/Platform/Android/abi-x86-GNU.cmake create mode 100644 Modules/Platform/Android/abi-x86_64-Clang.cmake create mode 100644 Modules/Platform/Android/abi-x86_64-GNU.cmake create mode 100644 Modules/Platform/Android/ndk-stl-c++.cmake create mode 100644 Modules/Platform/Android/ndk-stl-c++_shared.cmake create mode 100644 Modules/Platform/Android/ndk-stl-c++_static.cmake create mode 100644 Modules/Platform/Android/ndk-stl-gabi++.cmake create mode 100644 Modules/Platform/Android/ndk-stl-gabi++_shared.cmake create mode 100644 Modules/Platform/Android/ndk-stl-gabi++_static.cmake create mode 100644 Modules/Platform/Android/ndk-stl-gnustl.cmake create mode 100644 Modules/Platform/Android/ndk-stl-gnustl_shared.cmake create mode 100644 Modules/Platform/Android/ndk-stl-gnustl_static.cmake create mode 100644 Modules/Platform/Android/ndk-stl-none.cmake create mode 100644 Modules/Platform/Android/ndk-stl-stlport.cmake create mode 100644 Modules/Platform/Android/ndk-stl-stlport_shared.cmake create mode 100644 Modules/Platform/Android/ndk-stl-stlport_static.cmake create mode 100644 Modules/Platform/Android/ndk-stl-system.cmake copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => Android/BadSYSROOT-result.txt} (100%) create mode 100644 Tests/RunCMake/Android/BadSYSROOT-stderr.txt copy Modules/IntelVSImplicitPath/hello.f => Tests/RunCMake/Android/BadSYSROOT.cmake (100%) create mode 100644 Tests/RunCMake/Android/CMakeLists.txt create mode 100644 Tests/RunCMake/Android/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/Android/android.c create mode 100644 Tests/RunCMake/Android/android.cxx create mode 100644 Tests/RunCMake/Android/android.h create mode 100644 Tests/RunCMake/Android/common.cmake create mode 100644 Tests/RunCMake/Android/ndk-arm64-v8a-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-arm64-v8a.cmake create mode 100644 Tests/RunCMake/Android/ndk-armeabi-arm-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-armeabi-arm.cmake create mode 100644 Tests/RunCMake/Android/ndk-armeabi-thumb-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-armeabi-thumb.cmake create mode 100644 Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-armeabi-v7a-neon.cmake create mode 100644 Tests/RunCMake/Android/ndk-armeabi-v7a-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-armeabi-v7a.cmake copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => Android/ndk-badabi-result.txt} (100%) create mode 100644 Tests/RunCMake/Android/ndk-badabi-stderr.txt copy Modules/IntelVSImplicitPath/hello.f => Tests/RunCMake/Android/ndk-badabi.cmake (100%) copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => Android/ndk-badarm-result.txt} (100%) create mode 100644 Tests/RunCMake/Android/ndk-badarm-stderr.txt copy Modules/IntelVSImplicitPath/hello.f => Tests/RunCMake/Android/ndk-badarm.cmake (100%) copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => Android/ndk-badneon-result.txt} (100%) create mode 100644 Tests/RunCMake/Android/ndk-badneon-stderr.txt copy Modules/IntelVSImplicitPath/hello.f => Tests/RunCMake/Android/ndk-badneon.cmake (100%) copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => Android/ndk-badstl-result.txt} (100%) create mode 100644 Tests/RunCMake/Android/ndk-badstl-stderr.txt create mode 100644 Tests/RunCMake/Android/ndk-badstl.cmake copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => Android/ndk-badver-result.txt} (100%) create mode 100644 Tests/RunCMake/Android/ndk-badver-stderr.txt create mode 100644 Tests/RunCMake/Android/ndk-badver.cmake copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => Android/ndk-badvernum-result.txt} (100%) create mode 100644 Tests/RunCMake/Android/ndk-badvernum-stderr.txt create mode 100644 Tests/RunCMake/Android/ndk-badvernum.cmake create mode 100644 Tests/RunCMake/Android/ndk-mips-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-mips.cmake create mode 100644 Tests/RunCMake/Android/ndk-mips64-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-mips64.cmake create mode 100644 Tests/RunCMake/Android/ndk-sysroot-armeabi-stdout.txt copy Modules/IntelVSImplicitPath/hello.f => Tests/RunCMake/Android/ndk-sysroot-armeabi.cmake (100%) create mode 100644 Tests/RunCMake/Android/ndk-x86-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-x86.cmake create mode 100644 Tests/RunCMake/Android/ndk-x86_64-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-x86_64.cmake create mode 100644 Tests/RunCMake/Android/standalone-stdout.txt create mode 100644 Tests/RunCMake/Android/standalone-sysroot-stdout.txt copy Modules/IntelVSImplicitPath/hello.f => Tests/RunCMake/Android/standalone-sysroot.cmake (100%) create mode 100644 Tests/RunCMake/Android/standalone.cmake hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 23 13:24:10 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 23 Aug 2016 13:24:10 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1367-g4f3bc56 Message-ID: <20160823172410.3FF76F5518@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 4f3bc561c7c08a06ecab628d5492212a399ac6a3 (commit) via b4556b47a82f09d2dc40118e1e6cb41b69ece529 (commit) via 25c01cf0b0b940bbfb2d27410efdb4091479bcda (commit) via e3ac68cfbf04e48a089b6d3cb4f4091e559dc5a0 (commit) via 4a22c06e7fe8bcfb3c7243c5b8d98cc34df13f06 (commit) via f21a823598c672efd73de09b826acaeba231946c (commit) via 0966f1c5489591ba049b43f9e56a9f4e34778789 (commit) from 8a5c096810ffeed47062c20555f3e138459a76ed (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4f3bc561c7c08a06ecab628d5492212a399ac6a3 commit 4f3bc561c7c08a06ecab628d5492212a399ac6a3 Merge: 8a5c096 b4556b4 Author: Brad King AuthorDate: Tue Aug 23 13:24:07 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 23 13:24:07 2016 -0400 Merge topic 'import-vim-syntax' into next b4556b47 Help: Add release notes for 'vim-cmake-syntax' import 25c01cf0 Aux: Install vim-cmake-syntax files with CMake e3ac68cf Merge branch 'upstream-vim-cmake-syntax' into import-vim-syntax 4a22c06e vim-cmake-syntax 2016-08-16 (e782679c) f21a8235 Aux: Drop vim files prior to import of third-party version 0966f1c5 Add script to update vim-cmake-syntax from upstream https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b4556b47a82f09d2dc40118e1e6cb41b69ece529 commit b4556b47a82f09d2dc40118e1e6cb41b69ece529 Author: Brad King AuthorDate: Wed Aug 17 09:20:07 2016 -0400 Commit: Brad King CommitDate: Wed Aug 17 09:24:29 2016 -0400 Help: Add release notes for 'vim-cmake-syntax' import diff --git a/Help/release/dev/vim-cmake-syntax.rst b/Help/release/dev/vim-cmake-syntax.rst new file mode 100644 index 0000000..1757f9c --- /dev/null +++ b/Help/release/dev/vim-cmake-syntax.rst @@ -0,0 +1,11 @@ +vim-cmake-syntax +---------------- + +* Vim support files ``indent/cmake.vim`` and ``syntax/cmake.vim`` + from the `vim-cmake-syntax`_ project are now distributed with CMake. + +* Vim support files ``cmake-indent.vim``, ``cmake-syntax.vim``, and + ``cmake-help.vim`` have been removed in favor of the files now provided + from the `vim-cmake-syntax`_ project. + +.. _`vim-cmake-syntax`: https://github.com/pboettch/vim-cmake-syntax https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=25c01cf0b0b940bbfb2d27410efdb4091479bcda commit 25c01cf0b0b940bbfb2d27410efdb4091479bcda Author: Brad King AuthorDate: Wed Aug 17 09:11:47 2016 -0400 Commit: Brad King CommitDate: Wed Aug 17 09:11:47 2016 -0400 Aux: Install vim-cmake-syntax files with CMake diff --git a/Auxiliary/CMakeLists.txt b/Auxiliary/CMakeLists.txt index 4567d10..8eb74b7 100644 --- a/Auxiliary/CMakeLists.txt +++ b/Auxiliary/CMakeLists.txt @@ -1,3 +1,4 @@ +install(DIRECTORY vim/indent vim/syntax DESTINATION ${CMAKE_DATA_DIR}/editors/vim) install(FILES cmake-mode.el DESTINATION ${CMAKE_DATA_DIR}/editors/emacs) install(FILES cmake.m4 DESTINATION share/aclocal) add_subdirectory (bash-completion) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e3ac68cfbf04e48a089b6d3cb4f4091e559dc5a0 commit e3ac68cfbf04e48a089b6d3cb4f4091e559dc5a0 Merge: f21a823 4a22c06 Author: Brad King AuthorDate: Wed Aug 17 09:11:19 2016 -0400 Commit: Brad King CommitDate: Wed Aug 17 09:11:19 2016 -0400 Merge branch 'upstream-vim-cmake-syntax' into import-vim-syntax * upstream-vim-cmake-syntax: vim-cmake-syntax 2016-08-16 (e782679c) diff --cc Auxiliary/vim/cmake.vim.in index 0000000,89ece66..89ece66 mode 000000,100644..100644 --- a/Auxiliary/vim/cmake.vim.in +++ b/Auxiliary/vim/cmake.vim.in diff --cc Auxiliary/vim/extract-upper-case.pl index 0000000,e945d52..e945d52 mode 000000,100755..100755 --- a/Auxiliary/vim/extract-upper-case.pl +++ b/Auxiliary/vim/extract-upper-case.pl diff --cc Auxiliary/vim/indent/cmake.vim index 0000000,76aff64..76aff64 mode 000000,100644..100644 --- a/Auxiliary/vim/indent/cmake.vim +++ b/Auxiliary/vim/indent/cmake.vim diff --cc Auxiliary/vim/syntax/cmake.vim index 0000000,715676d..715676d mode 000000,100644..100644 --- a/Auxiliary/vim/syntax/cmake.vim +++ b/Auxiliary/vim/syntax/cmake.vim https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4a22c06e7fe8bcfb3c7243c5b8d98cc34df13f06 commit 4a22c06e7fe8bcfb3c7243c5b8d98cc34df13f06 Author: vim-cmake-syntax upstream AuthorDate: Tue Aug 16 22:30:01 2016 +0200 Commit: Brad King CommitDate: Wed Aug 17 09:11:18 2016 -0400 vim-cmake-syntax 2016-08-16 (e782679c) Code extracted from: https://github.com/pboettch/vim-cmake-syntax.git at commit e782679cb93a4ccb419cffbc1c076db0d524d43e (master). diff --git a/cmake.vim.in b/cmake.vim.in new file mode 100644 index 0000000..89ece66 --- /dev/null +++ b/cmake.vim.in @@ -0,0 +1,91 @@ +" vim: set nowrap: +" Vim syntax file +" Language: CMake +" Author: Andy Cedilnik , Nicholas Hutchinson , Patrick Boettcher +" Maintainer: Karthik Krishnan +" Last Change: $Date$ +" Version: $Revision$ +" +" Licence: The CMake license applies to this file. See +" https://cmake.org/licensing +" This implies that distribution with Vim is allowed + +if exists("b:current_syntax") + finish +endif + +syn match cmakeEscaped /\(\\\\\|\\"\|\\n\|\\t\)/ contained +syn region cmakeComment start="#" end="$" contains=cmakeTodo, at Spell +syn region cmakeLuaComment start="\[\z(=*\)\[" end="\]\z1\]" contains=cmakeTodo, at Spell +syn region cmakeGeneratorExpression start=/$/ + \ contained oneline contains=CONTAINED,cmakeTodo,cmakeVariable,cmakeProperty,cmakeGeneratorExpressions +syn region cmakeRegistry start=/\[/ end=/]/ + \ contained oneline contains=CONTAINED,cmakeTodo,cmakeEscaped +syn region cmakeVariableValue start=/\${/ end=/}/ + \ contained oneline contains=CONTAINED,cmakeTodo,cmakeVariable +syn region cmakeEnvironment start=/\$ENV{/ end=/}/ + \ contained oneline contains=CONTAINED,cmakeTodo +syn region cmakeString start=/"/ end=/"/ + \ contains=CONTAINED,cmakeTodo +syn region cmakeArguments start=/(/ end=/)/ + \ contains=ALLBUT,cmakeArguments,cmakeTodo + +syn case match +syn keyword cmakeProperty + \ ABSTRACT ADDITIONAL_MAKE_CLEAN_FILES ADVANCED ALIASED_TARGET ALLOW_DUPLICATE_CUSTOM_TARGETS ANDROID_ANT_ADDITIONAL_OPTIONS ANDROID_API ANDROID_API_MIN ANDROID_ARCH ANDROID_ASSETS_DIRECTORIES ANDROID_GUI ANDROID_JAR_DEPENDENCIES ANDROID_JAR_DIRECTORIES ANDROID_JAVA_SOURCE_DIR ANDROID_NATIVE_LIB_DEPENDENCIES ANDROID_NATIVE_LIB_DIRECTORIES ANDROID_PROCESS_MAX ANDROID_PROGUARD ANDROID_PROGUARD_CONFIG_PATH ANDROID_SECURE_PROPS_PATH ANDROID_SKIP_ANT_STEP ANDROID_STL_TYPE ARCHIVE_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY_DEBUG ARCHIVE_OUTPUT_DIRECTORY_RELEASE ARCHIVE_OUTPUT_NAME ARCHIVE_OUTPUT_NAME_DEBUG ARCHIVE_OUTPUT_NAME_RELEASE ATTACHED_FILES ATTACHED_FILES_ON_FAIL AUTOGEN_TARGETS_FOLDER AUTOGEN_TARGET_DEPENDS AUTOMOC AUTOMOC_MOC_OPTIONS AUTOMOC_TARGETS_FOLDER AUTORCC AUTORCC_OPTIONS AUTOUIC AUTOUIC_OPTIONS BINARY_DIR BUILD_WITH_INSTALL_RPATH BUNDLE BUNDLE_EXTENSION CACHE_VARIABLES CLEAN_NO_CUSTOM CMAKE_CONFIGURE_DEPENDS CMAKE_CXX_KNOWN_FEATURES CMAKE_C_KNOWN_FEATURES COMPATIBLE_INTERFACE_BOOL COMPATIBLE_INTERFACE_NUMBER_MAX COMPATIBLE_INTERFACE_NUMBER_MIN COMPATIBLE_INTERFACE_STRING COMPILE_DEFINITIONS COMPILE_DEFINITIONS_DEBUG COMPILE_DEFINITIONS_RELEASE COMPILE_FEATURES COMPILE_FLAGS COMPILE_OPTIONS COMPILE_PDB_NAME COMPILE_PDB_NAME_DEBUG COMPILE_PDB_NAME_RELEASE COMPILE_PDB_OUTPUT_DIRECTORY COMPILE_PDB_OUTPUT_DIRECTORY_DEBUG COMPILE_PDB_OUTPUT_DIRECTORY_RELEASE COST CPACK_DESKTOP_SHORTCUTS CPACK_NEVER_OVERWRITE CPACK_PERMANENT CPACK_STARTUP_SHORTCUTS CPACK_START_MENU_SHORTCUTS CPACK_WIX_ACL CROSSCOMPILING_EMULATOR CXX_EXTENSIONS CXX_STANDARD CXX_STANDARD_REQUIRED C_EXTENSIONS C_STANDARD C_STANDARD_REQUIRED DEBUG_CONFIGURATIONS DEBUG_POSTFIX DEFINE_SYMBOL DEFINITIONS DEPENDS DISABLED_FEATURES ECLIPSE_EXTRA_NATURES ENABLED_FEATURES ENABLED_LANGUAGES ENABLE_EXPORTS ENVIRONMENT EXCLUDE_FROM_ALL EXCLUDE_FROM_DEFAULT_BUILD EXCLUDE_FROM_DEFAULT_BUILD_DEBUG EXCLUDE_FROM_DEFAULT_BUILD_RELEASE EXPORT_NAME EXTERNAL_OBJECT EchoString FAIL_REGULAR_EXPRESSION FIND_LIBRARY_USE_LIB64_PATHS FIND_LIBRARY_USE_OPENBSD_VERSIONING FOLDER FRAMEWORK FRAMEWORK_VERSION Fortran_FORMAT Fortran_MODULE_DIRECTORY GENERATED GENERATOR_FILE_NAME GLOBAL_DEPENDS_DEBUG_MODE GLOBAL_DEPENDS_NO_CYCLES GNUtoMS HAS_CXX HEADER_FILE_ONLY HELPSTRING IMPLICIT_DEPENDS_INCLUDE_TRANSFORM IMPORTED IMPORTED_CONFIGURATIONS IMPORTED_IMPLIB IMPORTED_IMPLIB_DEBUG IMPORTED_IMPLIB_RELEASE IMPORTED_LINK_DEPENDENT_LIBRARIES IMPORTED_LINK_DEPENDENT_LIBRARIES_DEBUG IMPORTED_LINK_DEPENDENT_LIBRARIES_RELEASE IMPORTED_LINK_INTERFACE_LANGUAGES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE IMPORTED_LINK_INTERFACE_LIBRARIES IMPORTED_LINK_INTERFACE_LIBRARIES_DEBUG IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE IMPORTED_LINK_INTERFACE_MULTIPLICITY IMPORTED_LINK_INTERFACE_MULTIPLICITY_DEBUG IMPORTED_LINK_INTERFACE_MULTIPLICITY_RELEASE IMPORTED_LOCATION IMPORTED_LOCATION_DEBUG IMPORTED_LOCATION_RELEASE IMPORTED_NO_SONAME IMPORTED_NO_SONAME_DEBUG IMPORTED_NO_SONAME_RELEASE IMPORTED_SONAME IMPORTED_SONAME_DEBUG IMPORTED_SONAME_RELEASE IMPORT_PREFIX IMPORT_SUFFIX INCLUDE_DIRECTORIES INCLUDE_REGULAR_EXPRESSION INSTALL_NAME_DIR INSTALL_RPATH INSTALL_RPATH_USE_LINK_PATH INTERFACE_AUTOUIC_OPTIONS INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_FEATURES INTERFACE_COMPILE_OPTIONS INTERFACE_INCLUDE_DIRECTORIES INTERFACE_LINK_LIBRARIES INTERFACE_POSITION_INDEPENDENT_CODE INTERFACE_SOURCES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES INTERPROCEDURAL_OPTIMIZATION INTERPROCEDURAL_OPTIMIZATION_DEBUG INTERPROCEDURAL_OPTIMIZATION_RELEASE IN_TRY_COMPILE JOB_POOLS JOB_POOL_COMPILE JOB_POOL_LINK KEEP_EXTENSION LABELS LANGUAGE LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_DEBUG LIBRARY_OUTPUT_DIRECTORY_RELEASE LIBRARY_OUTPUT_NAME LIBRARY_OUTPUT_NAME_DEBUG LIBRARY_OUTPUT_NAME_RELEASE LINKER_LANGUAGE LINK_DEPENDS LINK_DEPENDS_NO_SHARED LINK_DIRECTORIES LINK_FLAGS LINK_FLAGS_DEBUG LINK_FLAGS_RELEASE LINK_INTERFACE_LIBRARIES LINK_INTERFACE_LIBRARIES_DEBUG LINK_INTERFACE_LIBRARIES_RELEASE LINK_INTERFACE_MULTIPLICITY LINK_INTERFACE_MULTIPLICITY_DEBUG LINK_INTERFACE_MULTIPLICITY_RELEASE LINK_LIBRARIES LINK_SEARCH_END_STATIC LINK_SEARCH_START_STATIC LISTFILE_STACK LOCATION LOCATION_DEBUG LOCATION_RELEASE MACOSX_BUNDLE MACOSX_BUNDLE_INFO_PLIST MACOSX_FRAMEWORK_INFO_PLIST MACOSX_PACKAGE_LOCATION MACOSX_RPATH MACROS MAP_IMPORTED_CONFIG_DEBUG MAP_IMPORTED_CONFIG_RELEASE MEASUREMENT MODIFIED NAME NO_SONAME NO_SYSTEM_FROM_IMPORTED OBJECT_DEPENDS OBJECT_OUTPUTS OSX_ARCHITECTURES OSX_ARCHITECTURES_DEBUG OSX_ARCHITECTURES_RELEASE OUTPUT_NAME OUTPUT_NAME_DEBUG OUTPUT_NAME_RELEASE PACKAGES_FOUND PACKAGES_NOT_FOUND PARENT_DIRECTORY PASS_REGULAR_EXPRESSION PDB_NAME PDB_NAME_DEBUG PDB_NAME_RELEASE PDB_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY_DEBUG PDB_OUTPUT_DIRECTORY_RELEASE POSITION_INDEPENDENT_CODE POST_INSTALL_SCRIPT PREDEFINED_TARGETS_FOLDER PREFIX PRE_INSTALL_SCRIPT PRIVATE_HEADER PROCESSORS PROJECT_LABEL PUBLIC_HEADER REPORT_UNDEFINED_PROPERTIES REQUIRED_FILES RESOURCE RESOURCE_LOCK RULE_LAUNCH_COMPILE RULE_LAUNCH_CUSTOM RULE_LAUNCH_LINK RULE_MESSAGES RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_DEBUG RUNTIME_OUTPUT_DIRECTORY_RELEASE RUNTIME_OUTPUT_NAME RUNTIME_OUTPUT_NAME_DEBUG RUNTIME_OUTPUT_NAME_RELEASE RUN_SERIAL SKIP_BUILD_RPATH SKIP_RETURN_CODE SOURCES SOURCE_DIR SOVERSION STATIC_LIBRARY_FLAGS STATIC_LIBRARY_FLAGS_DEBUG STATIC_LIBRARY_FLAGS_RELEASE STRINGS SUFFIX SYMBOLIC TARGET_ARCHIVES_MAY_BE_SHARED_LIBS TARGET_MESSAGES TARGET_SUPPORTS_SHARED_LIBS TEST_INCLUDE_FILE TIMEOUT TYPE USE_FOLDERS VALUE VARIABLES VERSION VISIBILITY_INLINES_HIDDEN VS_DEPLOYMENT_CONTENT VS_DEPLOYMENT_LOCATION VS_DESKTOP_EXTENSIONS_VERSION VS_DOTNET_REFERENCES VS_DOTNET_TARGET_FRAMEWORK_VERSION VS_GLOBAL_KEYWORD VS_GLOBAL_PROJECT_TYPES VS_GLOBAL_ROOTNAMESPACE VS_IOT_EXTENSIONS_VERSION VS_IOT_STARTUP_TASK VS_KEYWORD VS_MOBILE_EXTENSIONS_VERSION VS_SCC_AUXPATH VS_SCC_LOCALPATH VS_SCC_PROJECTNAME VS_SCC_PROVIDER VS_SHADER_ENTRYPOINT VS_SHADER_FLAGS VS_SHADER_MODEL VS_SHADER_TYPE VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION VS_WINRT_COMPONENT VS_WINRT_EXTENSIONS VS_WINRT_REFERENCES VS_XAML_TYPE WILL_FAIL WIN32_EXECUTABLE WINDOWS_EXPORT_ALL_SYMBOLS WORKING_DIRECTORY WRAP_EXCLUDE XCODE_EXPLICIT_FILE_TYPE XCODE_LAST_KNOWN_FILE_TYPE XCTEST + \ contained + +syn keyword cmakeVariable + at VARIABLE_LIST@ + \ contained + +syn keyword cmakeModule + at MODULES@ + \ contained + + at KEYWORDS@ + +syn keyword cmakeGeneratorExpressions + at GENERATOR_EXPRESSIONS@ + \ contained + +syn case ignore +syn keyword cmakeCommand + at COMMAND_LIST@ + \ nextgroup=cmakeArguments +syn keyword cmakeCommandConditional + at CONDITIONALS@ + \ nextgroup=cmakeArguments +syn keyword cmakeCommandRepeat + at LOOPS@ + \ nextgroup=cmakeArguments +syn keyword cmakeCommandDeprecated + at DEPRECATED@ + \ nextgroup=cmakeArguments +syn case match + +syn keyword cmakeTodo + \ TODO FIXME XXX + \ contained + +hi def link cmakeCommand Function +hi def link cmakeCommandConditional Conditional +hi def link cmakeCommandDeprecated WarningMsg +hi def link cmakeCommandRepeat Repeat +hi def link cmakeComment Comment +hi def link cmakeEnvironment Special +hi def link cmakeEscaped Special +hi def link cmakeGeneratorExpression WarningMsg +hi def link cmakeGeneratorExpressions ModeMsg +hi def link cmakeLuaComment Comment +hi def link cmakeModule Include +hi def link cmakeProperty Constant +hi def link cmakeRegistry Underlined +hi def link cmakeString String +hi def link cmakeTodo TODO +hi def link cmakeVariable Identifier +hi def link cmakeVariableValue Type + + at KEYWORDS_HIGHLIGHT@ + +let b:current_syntax = "cmake" diff --git a/extract-upper-case.pl b/extract-upper-case.pl new file mode 100755 index 0000000..e945d52 --- /dev/null +++ b/extract-upper-case.pl @@ -0,0 +1,141 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +my @variables; +my @commands; +my @properties; +my @modules; +my %keywords; # command => keyword-list + +# unwanted upper-cases +my %unwanted = map { $_ => 1 } qw(VS CXX IDE NOTFOUND NO_ DFOO DBAR); + # cannot remove ALL - exists for add_custom_command + +# control-statements +my %conditional = map { $_ => 1 } qw(if else elseif endif); +my %loop = map { $_ => 1 } qw(foreach while endforeach endwhile); + +# decrecated +my %deprecated = map { $_ => 1 } qw(build_name exec_program export_library_dependencies install_files install_programs install_targets link_libraries make_directory output_required_files remove subdir_depends subdirs use_mangled_mesa utility_source variable_requires write_file); + +# add some (popular) modules +push @modules, "ExternalProject"; + +# variables +open(CMAKE, "cmake --help-variable-list|") or die "could not run cmake"; +while () { + chomp; + push @variables, $_; +} +close(CMAKE); + +# transform all variables in a hash - to be able to use exists later on +my %variables = map { $_ => 1 } @variables; + +# commands +open(CMAKE, "cmake --help-command-list|"); +while (my $cmd = ) { + chomp $cmd; + + push @commands, $cmd; +} +close(CMAKE); + +# now generate a keyword-list per command +foreach my $cmd (@commands) { + my @word = extract_upper("cmake --help-command $cmd|"); + + next if scalar @word == 0; + + $keywords{$cmd} = [ sort keys %{ { map { $_ => 1 } @word } } ]; +} + +# and now for modules +foreach my $mod (@modules) { + my @word = extract_upper("cmake --help-module $mod|"); + + next if scalar @word == 0; + + $keywords{$mod} = [ sort keys %{ { map { $_ => 1 } @word } } ]; +} + +# and now for generator-expressions +my @generator_expr = extract_upper("cmake --help-manual cmake-generator-expressions |"); + +# properties +open(CMAKE, "cmake --help-property-list|"); +while () { + chomp; + push @properties, $_; +} +close(CMAKE); + +# generate cmake.vim +open(IN, "syntax/cmake.vim") or die "could not write to syntax/cmake.vim"; + +my @keyword_hi; + +while() +{ + if (m/\@([A-Z0-9_]+)\@/) { # match for @SOMETHING@ + if ($1 eq "COMMAND_LIST") { + # do not include "special" commands in this list + my @tmp = grep { ! exists $conditional{$_} and + ! exists $loop{$_} and + ! exists $deprecated{$_} } @commands; + print OUT " " x 12 , "\\ ", join(" ", @tmp), "\n"; + } elsif ($1 eq "VARIABLE_LIST") { + print OUT " " x 12 , "\\ ", join(" ", @variables), "\n"; + } elsif ($1 eq "MODULES") { + print OUT " " x 12 , "\\ ", join("\n", @modules), "\n"; + } elsif ($1 eq "GENERATOR_EXPRESSIONS") { + print OUT " " x 12 , "\\ ", join(" ", @generator_expr), "\n"; + } elsif ($1 eq "CONDITIONALS") { + print OUT " " x 12 , "\\ ", join(" ", sort keys %conditional), "\n"; + } elsif ($1 eq "LOOPS") { + print OUT " " x 12 , "\\ ", join(" ", sort keys %loop), "\n"; + } elsif ($1 eq "DEPRECATED") { + print OUT " " x 12 , "\\ ", join(" ", sort keys %deprecated), "\n"; + } elsif ($1 eq "KEYWORDS") { + foreach my $k (sort keys %keywords) { + print OUT "syn keyword cmakeKW$k\n"; + print OUT " " x 12, "\\ ", join(" ", @{$keywords{$k}}), "\n"; + print OUT " " x 12, "\\ contained\n"; + print OUT "\n"; + push @keyword_hi, "hi def link cmakeKW$k ModeMsg"; + } + } elsif ($1 eq "KEYWORDS_HIGHLIGHT") { + print OUT join("\n", @keyword_hi), "\n"; + } else { + print "ERROR do not know how to replace $1\n"; + } + } else { + print OUT $_; + } +} +close(IN); +close(OUT); + +sub extract_upper +{ + my $input = shift; + my @word; + + open(KW, $input); + while () { + + foreach my $w (m/\b([A-Z_]{2,})\b/g) { + next + if exists $variables{$w} or # skip if it is a variable + exists $unwanted{$w}; # skip if not wanted + + push @word, $w; + } + } + close(KW); + + return @word; +} diff --git a/indent/cmake.vim b/indent/cmake.vim new file mode 100644 index 0000000..76aff64 --- /dev/null +++ b/indent/cmake.vim @@ -0,0 +1,83 @@ +" Vim indent file +" Language: CMake (ft=cmake) +" Author: Andy Cedilnik +" Maintainer: Karthik Krishnan +" Last Change: $Date$ +" Version: $Revision$ +" +" Licence: The CMake license applies to this file. See +" https://cmake.org/licensing +" This implies that distribution with Vim is allowed + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal indentexpr=CMakeGetIndent(v:lnum) +setlocal indentkeys+==ENDIF(,ENDFOREACH(,ENDMACRO(,ELSE(,ELSEIF(,ENDWHILE( + +" Only define the function once. +if exists("*CMakeGetIndent") + finish +endif + +fun! CMakeGetIndent(lnum) + let this_line = getline(a:lnum) + + " Find a non-blank line above the current line. + let lnum = a:lnum + let lnum = prevnonblank(lnum - 1) + let previous_line = getline(lnum) + + " Hit the start of the file, use zero indent. + if lnum == 0 + return 0 + endif + + let ind = indent(lnum) + + let or = '\|' + " Regular expressions used by line indentation function. + let cmake_regex_comment = '#.*' + let cmake_regex_identifier = '[A-Za-z][A-Za-z0-9_]*' + let cmake_regex_quoted = '"\([^"\\]\|\\.\)*"' + let cmake_regex_arguments = '\(' . cmake_regex_quoted . + \ or . '\$(' . cmake_regex_identifier . ')' . + \ or . '[^()\\#"]' . or . '\\.' . '\)*' + + let cmake_indent_comment_line = '^\s*' . cmake_regex_comment + let cmake_indent_blank_regex = '^\s*$' + let cmake_indent_open_regex = '^\s*' . cmake_regex_identifier . + \ '\s*(' . cmake_regex_arguments . + \ '\(' . cmake_regex_comment . '\)\?$' + + let cmake_indent_close_regex = '^' . cmake_regex_arguments . + \ ')\s*' . + \ '\(' . cmake_regex_comment . '\)\?$' + + let cmake_indent_begin_regex = '^\s*\(IF\|MACRO\|FOREACH\|ELSE\|ELSEIF\|WHILE\|FUNCTION\)\s*(' + let cmake_indent_end_regex = '^\s*\(ENDIF\|ENDFOREACH\|ENDMACRO\|ELSE\|ELSEIF\|ENDWHILE\|ENDFUNCTION\)\s*(' + + " Add + if previous_line =~? cmake_indent_comment_line " Handle comments + let ind = ind + else + if previous_line =~? cmake_indent_begin_regex + let ind = ind + &sw + endif + if previous_line =~? cmake_indent_open_regex + let ind = ind + &sw + endif + endif + + " Subtract + if this_line =~? cmake_indent_end_regex + let ind = ind - &sw + endif + if previous_line =~? cmake_indent_close_regex + let ind = ind - &sw + endif + + return ind +endfun diff --git a/syntax/cmake.vim b/syntax/cmake.vim new file mode 100644 index 0000000..715676d --- /dev/null +++ b/syntax/cmake.vim @@ -0,0 +1,554 @@ +" vim: set nowrap: +" Vim syntax file +" Language: CMake +" Author: Andy Cedilnik , Nicholas Hutchinson , Patrick Boettcher +" Maintainer: Karthik Krishnan +" Last Change: $Date$ +" Version: $Revision$ +" +" Licence: The CMake license applies to this file. See +" https://cmake.org/licensing +" This implies that distribution with Vim is allowed + +if exists("b:current_syntax") + finish +endif + +syn match cmakeEscaped /\(\\\\\|\\"\|\\n\|\\t\)/ contained +syn region cmakeComment start="#" end="$" contains=cmakeTodo, at Spell +syn region cmakeLuaComment start="\[\z(=*\)\[" end="\]\z1\]" contains=cmakeTodo, at Spell +syn region cmakeGeneratorExpression start=/$/ + \ contained oneline contains=CONTAINED,cmakeTodo,cmakeVariable,cmakeProperty,cmakeGeneratorExpressions +syn region cmakeRegistry start=/\[/ end=/]/ + \ contained oneline contains=CONTAINED,cmakeTodo,cmakeEscaped +syn region cmakeVariableValue start=/\${/ end=/}/ + \ contained oneline contains=CONTAINED,cmakeTodo,cmakeVariable +syn region cmakeEnvironment start=/\$ENV{/ end=/}/ + \ contained oneline contains=CONTAINED,cmakeTodo +syn region cmakeString start=/"/ end=/"/ + \ contains=CONTAINED,cmakeTodo +syn region cmakeArguments start=/(/ end=/)/ + \ contains=ALLBUT,cmakeArguments,cmakeTodo + +syn case match +syn keyword cmakeProperty + \ ABSTRACT ADDITIONAL_MAKE_CLEAN_FILES ADVANCED ALIASED_TARGET ALLOW_DUPLICATE_CUSTOM_TARGETS ANDROID_ANT_ADDITIONAL_OPTIONS ANDROID_API ANDROID_API_MIN ANDROID_ARCH ANDROID_ASSETS_DIRECTORIES ANDROID_GUI ANDROID_JAR_DEPENDENCIES ANDROID_JAR_DIRECTORIES ANDROID_JAVA_SOURCE_DIR ANDROID_NATIVE_LIB_DEPENDENCIES ANDROID_NATIVE_LIB_DIRECTORIES ANDROID_PROCESS_MAX ANDROID_PROGUARD ANDROID_PROGUARD_CONFIG_PATH ANDROID_SECURE_PROPS_PATH ANDROID_SKIP_ANT_STEP ANDROID_STL_TYPE ARCHIVE_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY_DEBUG ARCHIVE_OUTPUT_DIRECTORY_RELEASE ARCHIVE_OUTPUT_NAME ARCHIVE_OUTPUT_NAME_DEBUG ARCHIVE_OUTPUT_NAME_RELEASE ATTACHED_FILES ATTACHED_FILES_ON_FAIL AUTOGEN_TARGETS_FOLDER AUTOGEN_TARGET_DEPENDS AUTOMOC AUTOMOC_MOC_OPTIONS AUTOMOC_TARGETS_FOLDER AUTORCC AUTORCC_OPTIONS AUTOUIC AUTOUIC_OPTIONS BINARY_DIR BUILD_WITH_INSTALL_RPATH BUNDLE BUNDLE_EXTENSION CACHE_VARIABLES CLEAN_NO_CUSTOM CMAKE_CONFIGURE_DEPENDS CMAKE_CXX_KNOWN_FEATURES CMAKE_C_KNOWN_FEATURES COMPATIBLE_INTERFACE_BOOL COMPATIBLE_INTERFACE_NUMBER_MAX COMPATIBLE_INTERFACE_NUMBER_MIN COMPATIBLE_INTERFACE_STRING COMPILE_DEFINITIONS COMPILE_DEFINITIONS_DEBUG COMPILE_DEFINITIONS_RELEASE COMPILE_FEATURES COMPILE_FLAGS COMPILE_OPTIONS COMPILE_PDB_NAME COMPILE_PDB_NAME_DEBUG COMPILE_PDB_NAME_RELEASE COMPILE_PDB_OUTPUT_DIRECTORY COMPILE_PDB_OUTPUT_DIRECTORY_DEBUG COMPILE_PDB_OUTPUT_DIRECTORY_RELEASE COST CPACK_DESKTOP_SHORTCUTS CPACK_NEVER_OVERWRITE CPACK_PERMANENT CPACK_STARTUP_SHORTCUTS CPACK_START_MENU_SHORTCUTS CPACK_WIX_ACL CROSSCOMPILING_EMULATOR CXX_EXTENSIONS CXX_STANDARD CXX_STANDARD_REQUIRED C_EXTENSIONS C_STANDARD C_STANDARD_REQUIRED DEBUG_CONFIGURATIONS DEBUG_POSTFIX DEFINE_SYMBOL DEFINITIONS DEPENDS DISABLED_FEATURES ECLIPSE_EXTRA_NATURES ENABLED_FEATURES ENABLED_LANGUAGES ENABLE_EXPORTS ENVIRONMENT EXCLUDE_FROM_ALL EXCLUDE_FROM_DEFAULT_BUILD EXCLUDE_FROM_DEFAULT_BUILD_DEBUG EXCLUDE_FROM_DEFAULT_BUILD_RELEASE EXPORT_NAME EXTERNAL_OBJECT EchoString FAIL_REGULAR_EXPRESSION FIND_LIBRARY_USE_LIB64_PATHS FIND_LIBRARY_USE_OPENBSD_VERSIONING FOLDER FRAMEWORK FRAMEWORK_VERSION Fortran_FORMAT Fortran_MODULE_DIRECTORY GENERATED GENERATOR_FILE_NAME GLOBAL_DEPENDS_DEBUG_MODE GLOBAL_DEPENDS_NO_CYCLES GNUtoMS HAS_CXX HEADER_FILE_ONLY HELPSTRING IMPLICIT_DEPENDS_INCLUDE_TRANSFORM IMPORTED IMPORTED_CONFIGURATIONS IMPORTED_IMPLIB IMPORTED_IMPLIB_DEBUG IMPORTED_IMPLIB_RELEASE IMPORTED_LINK_DEPENDENT_LIBRARIES IMPORTED_LINK_DEPENDENT_LIBRARIES_DEBUG IMPORTED_LINK_DEPENDENT_LIBRARIES_RELEASE IMPORTED_LINK_INTERFACE_LANGUAGES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE IMPORTED_LINK_INTERFACE_LIBRARIES IMPORTED_LINK_INTERFACE_LIBRARIES_DEBUG IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE IMPORTED_LINK_INTERFACE_MULTIPLICITY IMPORTED_LINK_INTERFACE_MULTIPLICITY_DEBUG IMPORTED_LINK_INTERFACE_MULTIPLICITY_RELEASE IMPORTED_LOCATION IMPORTED_LOCATION_DEBUG IMPORTED_LOCATION_RELEASE IMPORTED_NO_SONAME IMPORTED_NO_SONAME_DEBUG IMPORTED_NO_SONAME_RELEASE IMPORTED_SONAME IMPORTED_SONAME_DEBUG IMPORTED_SONAME_RELEASE IMPORT_PREFIX IMPORT_SUFFIX INCLUDE_DIRECTORIES INCLUDE_REGULAR_EXPRESSION INSTALL_NAME_DIR INSTALL_RPATH INSTALL_RPATH_USE_LINK_PATH INTERFACE_AUTOUIC_OPTIONS INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_FEATURES INTERFACE_COMPILE_OPTIONS INTERFACE_INCLUDE_DIRECTORIES INTERFACE_LINK_LIBRARIES INTERFACE_POSITION_INDEPENDENT_CODE INTERFACE_SOURCES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES INTERPROCEDURAL_OPTIMIZATION INTERPROCEDURAL_OPTIMIZATION_DEBUG INTERPROCEDURAL_OPTIMIZATION_RELEASE IN_TRY_COMPILE JOB_POOLS JOB_POOL_COMPILE JOB_POOL_LINK KEEP_EXTENSION LABELS LANGUAGE LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_DEBUG LIBRARY_OUTPUT_DIRECTORY_RELEASE LIBRARY_OUTPUT_NAME LIBRARY_OUTPUT_NAME_DEBUG LIBRARY_OUTPUT_NAME_RELEASE LINKER_LANGUAGE LINK_DEPENDS LINK_DEPENDS_NO_SHARED LINK_DIRECTORIES LINK_FLAGS LINK_FLAGS_DEBUG LINK_FLAGS_RELEASE LINK_INTERFACE_LIBRARIES LINK_INTERFACE_LIBRARIES_DEBUG LINK_INTERFACE_LIBRARIES_RELEASE LINK_INTERFACE_MULTIPLICITY LINK_INTERFACE_MULTIPLICITY_DEBUG LINK_INTERFACE_MULTIPLICITY_RELEASE LINK_LIBRARIES LINK_SEARCH_END_STATIC LINK_SEARCH_START_STATIC LISTFILE_STACK LOCATION LOCATION_DEBUG LOCATION_RELEASE MACOSX_BUNDLE MACOSX_BUNDLE_INFO_PLIST MACOSX_FRAMEWORK_INFO_PLIST MACOSX_PACKAGE_LOCATION MACOSX_RPATH MACROS MAP_IMPORTED_CONFIG_DEBUG MAP_IMPORTED_CONFIG_RELEASE MEASUREMENT MODIFIED NAME NO_SONAME NO_SYSTEM_FROM_IMPORTED OBJECT_DEPENDS OBJECT_OUTPUTS OSX_ARCHITECTURES OSX_ARCHITECTURES_DEBUG OSX_ARCHITECTURES_RELEASE OUTPUT_NAME OUTPUT_NAME_DEBUG OUTPUT_NAME_RELEASE PACKAGES_FOUND PACKAGES_NOT_FOUND PARENT_DIRECTORY PASS_REGULAR_EXPRESSION PDB_NAME PDB_NAME_DEBUG PDB_NAME_RELEASE PDB_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY_DEBUG PDB_OUTPUT_DIRECTORY_RELEASE POSITION_INDEPENDENT_CODE POST_INSTALL_SCRIPT PREDEFINED_TARGETS_FOLDER PREFIX PRE_INSTALL_SCRIPT PRIVATE_HEADER PROCESSORS PROJECT_LABEL PUBLIC_HEADER REPORT_UNDEFINED_PROPERTIES REQUIRED_FILES RESOURCE RESOURCE_LOCK RULE_LAUNCH_COMPILE RULE_LAUNCH_CUSTOM RULE_LAUNCH_LINK RULE_MESSAGES RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_DEBUG RUNTIME_OUTPUT_DIRECTORY_RELEASE RUNTIME_OUTPUT_NAME RUNTIME_OUTPUT_NAME_DEBUG RUNTIME_OUTPUT_NAME_RELEASE RUN_SERIAL SKIP_BUILD_RPATH SKIP_RETURN_CODE SOURCES SOURCE_DIR SOVERSION STATIC_LIBRARY_FLAGS STATIC_LIBRARY_FLAGS_DEBUG STATIC_LIBRARY_FLAGS_RELEASE STRINGS SUFFIX SYMBOLIC TARGET_ARCHIVES_MAY_BE_SHARED_LIBS TARGET_MESSAGES TARGET_SUPPORTS_SHARED_LIBS TEST_INCLUDE_FILE TIMEOUT TYPE USE_FOLDERS VALUE VARIABLES VERSION VISIBILITY_INLINES_HIDDEN VS_DEPLOYMENT_CONTENT VS_DEPLOYMENT_LOCATION VS_DESKTOP_EXTENSIONS_VERSION VS_DOTNET_REFERENCES VS_DOTNET_TARGET_FRAMEWORK_VERSION VS_GLOBAL_KEYWORD VS_GLOBAL_PROJECT_TYPES VS_GLOBAL_ROOTNAMESPACE VS_IOT_EXTENSIONS_VERSION VS_IOT_STARTUP_TASK VS_KEYWORD VS_MOBILE_EXTENSIONS_VERSION VS_SCC_AUXPATH VS_SCC_LOCALPATH VS_SCC_PROJECTNAME VS_SCC_PROVIDER VS_SHADER_ENTRYPOINT VS_SHADER_FLAGS VS_SHADER_MODEL VS_SHADER_TYPE VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION VS_WINRT_COMPONENT VS_WINRT_EXTENSIONS VS_WINRT_REFERENCES VS_XAML_TYPE WILL_FAIL WIN32_EXECUTABLE WINDOWS_EXPORT_ALL_SYMBOLS WORKING_DIRECTORY WRAP_EXCLUDE XCODE_EXPLICIT_FILE_TYPE XCODE_LAST_KNOWN_FILE_TYPE XCTEST + \ contained + +syn keyword cmakeVariable + \ _BINARY_DIR _SOURCE_DIR _VERSION _VERSION_MAJOR _VERSION_MINOR _VERSION_PATCH _VERSION_TWEAK APPLE BORLAND BUILD_SHARED_LIBS CMAKE__POSTFIX CMAKE__ARCHIVE_APPEND CMAKE__ARCHIVE_CREATE CMAKE__ARCHIVE_FINISH CMAKE__COMPILER CMAKE__COMPILER_ABI CMAKE__COMPILER_EXTERNAL_TOOLCHAIN CMAKE__COMPILER_ID CMAKE__COMPILER_LAUNCHER CMAKE__COMPILER_LOADED CMAKE__COMPILER_TARGET CMAKE__COMPILER_VERSION CMAKE__COMPILE_OBJECT CMAKE__CREATE_SHARED_LIBRARY CMAKE__CREATE_SHARED_MODULE CMAKE__CREATE_STATIC_LIBRARY CMAKE__FLAGS CMAKE__FLAGS_DEBUG CMAKE__FLAGS_MINSIZEREL CMAKE__FLAGS_RELEASE CMAKE__FLAGS_RELWITHDEBINFO CMAKE__GHS_KERNEL_FLAGS_DEBUG CMAKE__GHS_KERNEL_FLAGS_MINSIZEREL CMAKE__GHS_KERNEL_FLAGS_RELEASE CMAKE__GHS_KERNEL_FLAGS_RELWITHDEBINFO CMAKE__IGNORE_EXTENSIONS CMAKE__IMPLICIT_INCLUDE_DIRECTORIES CMAKE__IMPLICIT_LINK_DIRECTORIES CMAKE__IMPLICIT_LINK_FRAMEWORK_DIRECTORIES CMAKE__IMPLICIT_LINK_LIBRARIES CMAKE__INCLUDE_WHAT_YOU_USE CMAKE__LIBRARY_ARCHITECTURE CMAKE__LINKER_PREFERENCE CMAKE__LINKER_PREFERENCE_PROPAGATES CMAKE__LINK_EXECUTABLE CMAKE__OUTPUT_EXTENSION CMAKE__PLATFORM_ID CMAKE__SIMULATE_ID CMAKE__SIMULATE_VERSION CMAKE__SIZEOF_DATA_PTR CMAKE__SOURCE_FILE_EXTENSIONS CMAKE__VISIBILITY_PRESET CMAKE_ABSOLUTE_DESTINATION_FILES CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS CMAKE_ANDROID_API CMAKE_ANDROID_API_MIN CMAKE_ANDROID_ARCH CMAKE_ANDROID_ASSETS_DIRECTORIES CMAKE_ANDROID_GUI CMAKE_ANDROID_JAR_DEPENDENCIES CMAKE_ANDROID_JAR_DIRECTORIES CMAKE_ANDROID_JAVA_SOURCE_DIR CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES CMAKE_ANDROID_PROCESS_MAX CMAKE_ANDROID_PROGUARD CMAKE_ANDROID_PROGUARD_CONFIG_PATH CMAKE_ANDROID_SECURE_PROPS_PATH CMAKE_ANDROID_SKIP_ANT_STEP CMAKE_ANDROID_STL_TYPE CMAKE_APPBUNDLE_PATH CMAKE_AR CMAKE_ARCHIVE_OUTPUT_DIRECTORY CMAKE_ARCHIVE_OUTPUT_DIRECTORY_ CMAKE_ARGC CMAKE_ARGV0 CMAKE_AUTOMOC CMAKE_AUTOMOC_MOC_OPTIONS CMAKE_AUTOMOC_RELAXED_MODE CMAKE_AUTORCC CMAKE_AUTORCC_OPTIONS CMAKE_AUTOUIC CMAKE_AUTOUIC_OPTIONS CMAKE_BACKWARDS_COMPATIBILITY CMAKE_BINARY_DIR CMAKE_BUILD_TOOL CMAKE_BUILD_TYPE CMAKE_BUILD_WITH_INSTALL_RPATH CMAKE_CACHEFILE_DIR CMAKE_CACHE_MAJOR_VERSION CMAKE_CACHE_MINOR_VERSION CMAKE_CACHE_PATCH_VERSION CMAKE_CFG_INTDIR CMAKE_CL_64 CMAKE_COLOR_MAKEFILE CMAKE_COMMAND CMAKE_COMPILER_2005 CMAKE_COMPILER_IS_GNU CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_ CMAKE_CONFIGURATION_TYPES CMAKE_CROSSCOMPILING CMAKE_CROSSCOMPILING_EMULATOR CMAKE_CTEST_COMMAND CMAKE_CURRENT_BINARY_DIR CMAKE_CURRENT_LIST_DIR CMAKE_CURRENT_LIST_FILE CMAKE_CURRENT_LIST_LINE CMAKE_CURRENT_SOURCE_DIR CMAKE_CXX_COMPILE_FEATURES CMAKE_CXX_EXTENSIONS CMAKE_CXX_STANDARD CMAKE_CXX_STANDARD_REQUIRED CMAKE_C_COMPILE_FEATURES CMAKE_C_EXTENSIONS CMAKE_C_STANDARD CMAKE_C_STANDARD_REQUIRED CMAKE_DEBUG_POSTFIX CMAKE_DEBUG_TARGET_PROPERTIES CMAKE_DISABLE_FIND_PACKAGE_ CMAKE_DL_LIBS CMAKE_EDIT_COMMAND CMAKE_ENABLE_EXPORTS CMAKE_ERROR_DEPRECATED CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION CMAKE_EXECUTABLE_SUFFIX CMAKE_EXE_LINKER_FLAGS CMAKE_EXE_LINKER_FLAGS_ CMAKE_EXPORT_COMPILE_COMMANDS CMAKE_EXPORT_NO_PACKAGE_REGISTRY CMAKE_EXTRA_GENERATOR CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES CMAKE_FIND_APPBUNDLE CMAKE_FIND_FRAMEWORK CMAKE_FIND_LIBRARY_PREFIXES CMAKE_FIND_LIBRARY_SUFFIXES CMAKE_FIND_NO_INSTALL_PREFIX CMAKE_FIND_PACKAGE_NAME CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY CMAKE_FIND_PACKAGE_WARN_NO_MODULE CMAKE_FIND_ROOT_PATH CMAKE_FIND_ROOT_PATH_MODE_INCLUDE CMAKE_FIND_ROOT_PATH_MODE_LIBRARY CMAKE_FIND_ROOT_PATH_MODE_PACKAGE CMAKE_FIND_ROOT_PATH_MODE_PROGRAM CMAKE_FRAMEWORK_PATH CMAKE_Fortran_FORMAT CMAKE_Fortran_MODDIR_DEFAULT CMAKE_Fortran_MODDIR_FLAG CMAKE_Fortran_MODOUT_FLAG CMAKE_Fortran_MODULE_DIRECTORY CMAKE_GENERATOR CMAKE_GENERATOR_PLATFORM CMAKE_GENERATOR_TOOLSET CMAKE_GNUtoMS CMAKE_HOME_DIRECTORY CMAKE_HOST_APPLE CMAKE_HOST_SYSTEM CMAKE_HOST_SYSTEM_NAME CMAKE_HOST_SYSTEM_PROCESSOR CMAKE_HOST_SYSTEM_VERSION CMAKE_HOST_UNIX CMAKE_HOST_WIN32 CMAKE_IGNORE_PATH CMAKE_IMPORT_LIBRARY_PREFIX CMAKE_IMPORT_LIBRARY_SUFFIX CMAKE_INCLUDE_CURRENT_DIR CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE CMAKE_INCLUDE_DIRECTORIES_BEFORE CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE CMAKE_INCLUDE_PATH CMAKE_INSTALL_DEFAULT_COMPONENT_NAME CMAKE_INSTALL_MESSAGE CMAKE_INSTALL_NAME_DIR CMAKE_INSTALL_PREFIX CMAKE_INSTALL_RPATH CMAKE_INSTALL_RPATH_USE_LINK_PATH CMAKE_INTERNAL_PLATFORM_ABI CMAKE_IOS_INSTALL_COMBINED CMAKE_JOB_POOL_COMPILE CMAKE_JOB_POOL_LINK CMAKE_LIBRARY_ARCHITECTURE CMAKE_LIBRARY_ARCHITECTURE_REGEX CMAKE_LIBRARY_OUTPUT_DIRECTORY CMAKE_LIBRARY_OUTPUT_DIRECTORY_ CMAKE_LIBRARY_PATH CMAKE_LIBRARY_PATH_FLAG CMAKE_LINK_DEF_FILE_FLAG CMAKE_LINK_DEPENDS_NO_SHARED CMAKE_LINK_INTERFACE_LIBRARIES CMAKE_LINK_LIBRARY_FILE_FLAG CMAKE_LINK_LIBRARY_FLAG CMAKE_LINK_LIBRARY_SUFFIX CMAKE_LINK_SEARCH_END_STATIC CMAKE_LINK_SEARCH_START_STATIC CMAKE_MACOSX_BUNDLE CMAKE_MACOSX_RPATH CMAKE_MAJOR_VERSION CMAKE_MAKE_PROGRAM CMAKE_MAP_IMPORTED_CONFIG_ CMAKE_MATCH_COUNT CMAKE_MFC_FLAG CMAKE_MINIMUM_REQUIRED_VERSION CMAKE_MINOR_VERSION CMAKE_MODULE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS_ CMAKE_MODULE_PATH CMAKE_NOT_USING_CONFIG_FLAGS CMAKE_NO_BUILTIN_CHRPATH CMAKE_NO_SYSTEM_FROM_IMPORTED CMAKE_OBJECT_PATH_MAX CMAKE_OSX_ARCHITECTURES CMAKE_OSX_DEPLOYMENT_TARGET CMAKE_OSX_SYSROOT CMAKE_PARENT_LIST_FILE CMAKE_PATCH_VERSION CMAKE_PDB_OUTPUT_DIRECTORY CMAKE_PDB_OUTPUT_DIRECTORY_ CMAKE_POLICY_DEFAULT_CMP CMAKE_POLICY_WARNING_CMP CMAKE_POSITION_INDEPENDENT_CODE CMAKE_PREFIX_PATH CMAKE_PROGRAM_PATH CMAKE_PROJECT__INCLUDE CMAKE_PROJECT_NAME CMAKE_RANLIB CMAKE_ROOT CMAKE_RUNTIME_OUTPUT_DIRECTORY CMAKE_RUNTIME_OUTPUT_DIRECTORY_ CMAKE_SCRIPT_MODE_FILE CMAKE_SHARED_LIBRARY_PREFIX CMAKE_SHARED_LIBRARY_SUFFIX CMAKE_SHARED_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS_ CMAKE_SHARED_MODULE_PREFIX CMAKE_SHARED_MODULE_SUFFIX CMAKE_SIZEOF_VOID_P CMAKE_SKIP_BUILD_RPATH CMAKE_SKIP_INSTALL_ALL_DEPENDENCY CMAKE_SKIP_INSTALL_RPATH CMAKE_SKIP_INSTALL_RULES CMAKE_SKIP_RPATH CMAKE_SOURCE_DIR CMAKE_STAGING_PREFIX CMAKE_STANDARD_LIBRARIES CMAKE_STATIC_LIBRARY_PREFIX CMAKE_STATIC_LIBRARY_SUFFIX CMAKE_STATIC_LINKER_FLAGS CMAKE_STATIC_LINKER_FLAGS_ CMAKE_SYSROOT CMAKE_SYSTEM CMAKE_SYSTEM_APPBUNDLE_PATH CMAKE_SYSTEM_FRAMEWORK_PATH CMAKE_SYSTEM_IGNORE_PATH CMAKE_SYSTEM_INCLUDE_PATH CMAKE_SYSTEM_LIBRARY_PATH CMAKE_SYSTEM_NAME CMAKE_SYSTEM_PREFIX_PATH CMAKE_SYSTEM_PROCESSOR CMAKE_SYSTEM_PROGRAM_PATH CMAKE_SYSTEM_VERSION CMAKE_TOOLCHAIN_FILE CMAKE_TRY_COMPILE_CONFIGURATION CMAKE_TWEAK_VERSION CMAKE_USER_MAKE_RULES_OVERRIDE CMAKE_USER_MAKE_RULES_OVERRIDE_ CMAKE_USE_RELATIVE_PATHS CMAKE_VERBOSE_MAKEFILE CMAKE_VERSION CMAKE_VISIBILITY_INLINES_HIDDEN CMAKE_VS_DEVENV_COMMAND CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD CMAKE_VS_INTEL_Fortran_PROJECT_VERSION CMAKE_VS_MSBUILD_COMMAND CMAKE_VS_MSDEV_COMMAND CMAKE_VS_NsightTegra_VERSION CMAKE_VS_PLATFORM_NAME CMAKE_VS_PLATFORM_TOOLSET CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION CMAKE_WARN_DEPRECATED CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION CMAKE_WIN32_EXECUTABLE CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS CMAKE_XCODE_ATTRIBUTE_ CMAKE_XCODE_PLATFORM_TOOLSET CPACK_ABSOLUTE_DESTINATION_FILES CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION CPACK_INCLUDE_TOPLEVEL_DIRECTORY CPACK_INSTALL_SCRIPT CPACK_PACKAGING_INSTALL_PREFIX CPACK_SET_DESTDIR CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION CTEST_BINARY_DIRECTORY CTEST_BUILD_COMMAND CTEST_BUILD_NAME CTEST_BZR_COMMAND CTEST_BZR_UPDATE_OPTIONS CTEST_CHANGE_ID CTEST_CHECKOUT_COMMAND CTEST_CONFIGURATION_TYPE CTEST_CONFIGURE_COMMAND CTEST_COVERAGE_COMMAND CTEST_COVERAGE_EXTRA_FLAGS CTEST_CURL_OPTIONS CTEST_CUSTOM_COVERAGE_EXCLUDE CTEST_CUSTOM_ERROR_EXCEPTION CTEST_CUSTOM_ERROR_MATCH CTEST_CUSTOM_ERROR_POST_CONTEXT CTEST_CUSTOM_ERROR_PRE_CONTEXT CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE CTEST_CUSTOM_MEMCHECK_IGNORE CTEST_CUSTOM_POST_MEMCHECK CTEST_CUSTOM_POST_TEST CTEST_CUSTOM_PRE_MEMCHECK CTEST_CUSTOM_PRE_TEST CTEST_CUSTOM_TEST_IGNORE CTEST_CUSTOM_WARNING_EXCEPTION CTEST_CUSTOM_WARNING_MATCH CTEST_CVS_CHECKOUT CTEST_CVS_COMMAND CTEST_CVS_UPDATE_OPTIONS CTEST_DROP_LOCATION CTEST_DROP_METHOD CTEST_DROP_SITE CTEST_DROP_SITE_CDASH CTEST_DROP_SITE_PASSWORD CTEST_DROP_SITE_USER CTEST_EXTRA_COVERAGE_GLOB CTEST_GIT_COMMAND CTEST_GIT_UPDATE_CUSTOM CTEST_GIT_UPDATE_OPTIONS CTEST_HG_COMMAND CTEST_HG_UPDATE_OPTIONS CTEST_MEMORYCHECK_COMMAND CTEST_MEMORYCHECK_COMMAND_OPTIONS CTEST_MEMORYCHECK_SANITIZER_OPTIONS CTEST_MEMORYCHECK_SUPPRESSIONS_FILE CTEST_MEMORYCHECK_TYPE CTEST_NIGHTLY_START_TIME CTEST_P4_CLIENT CTEST_P4_COMMAND CTEST_P4_OPTIONS CTEST_P4_UPDATE_OPTIONS CTEST_SCP_COMMAND CTEST_SITE CTEST_SOURCE_DIRECTORY CTEST_SVN_COMMAND CTEST_SVN_OPTIONS CTEST_SVN_UPDATE_OPTIONS CTEST_TEST_LOAD CTEST_TEST_TIMEOUT CTEST_TRIGGER_SITE CTEST_UPDATE_COMMAND CTEST_UPDATE_OPTIONS CTEST_UPDATE_VERSION_ONLY CTEST_USE_LAUNCHERS CYGWIN ENV EXECUTABLE_OUTPUT_PATH GHS-MULTI LIBRARY_OUTPUT_PATH MINGW MSVC MSVC10 MSVC11 MSVC12 MSVC14 MSVC60 MSVC70 MSVC71 MSVC80 MSVC90 MSVC_IDE MSVC_VERSION PROJECT_BINARY_DIR PROJECT_NAME PROJECT_SOURCE_DIR PROJECT_VERSION PROJECT_VERSION_MAJOR PROJECT_VERSION_MINOR PROJECT_VERSION_PATCH PROJECT_VERSION_TWEAK UNIX WIN32 WINCE WINDOWS_PHONE WINDOWS_STORE XCODE_VERSION + \ contained + +syn keyword cmakeModule + \ ExternalProject + \ contained + +syn keyword cmakeKWExternalProject + \ ALGO ALWAYS BINARY_DIR BUILD_ALWAYS BUILD_BYPRODUCTS BUILD_COMMAND BUILD_IN_SOURCE BYPRODUCTS CMAKE_ARGS CMAKE_CACHE_ARGS CMAKE_CACHE_DEFAULT_ARGS COMMAND COMMENT CONFIGURE_COMMAND CVS CVSROOT CVS_ CVS_MODULE CVS_REPOSITORY CVS_TAG DEPENDEES DEPENDERS DEPENDS DIRECTORY DOWNLOAD_COMMAND DOWNLOAD_DIR DOWNLOAD_NAME DOWNLOAD_NO_PROGRESS EP_BASE EP_INDEPENDENT_STEP_TARGETS EP_PREFIX EP_STEP_TARGETS EP_UPDATE_DISCONNECTED EXCLUDE_FROM_ALL EXCLUDE_FROM_MAIN FORCE GIT_REMOTE_NAME GIT_REPOSITORY GIT_SUBMODULES GIT_TAG HG_REPOSITORY HG_TAG INDEPENDENT INDEPENDENT_STEP_TARGETS INSTALL_COMMAND INSTALL_DIR JOB_POOLS LIST_SEPARATOR LOG LOG_BUILD LOG_CONFIGURE LOG_DOWNLOAD LOG_INSTALL LOG_TEST LOG_UPDATE NO_DEPENDS PATCH_COMMAND PREFIX PROPERTY SOURCE_DIR STAMP_DIR STEP_TARGETS SVN_ SVN_PASSWORD SVN_REPOSITORY SVN_REVISION SVN_TRUST_CERT SVN_USERNAME TEST_AFTER_INSTALL TEST_BEFORE_INSTALL TEST_COMMAND TEST_EXCLUDE_FROM_MAIN TIMEOUT TLS_CAINFO TLS_VERIFY TMP_DIR UPDATE_COMMAND UPDATE_DISCONNECTED URL URL_HASH USES_TERMINAL USES_TERMINAL_BUILD USES_TERMINAL_CONFIGURE USES_TERMINAL_DOWNLOAD USES_TERMINAL_INSTALL USES_TERMINAL_TEST USES_TERMINAL_UPDATE WORKING_DIRECTORY _COMMAND _DIR + \ contained + +syn keyword cmakeKWadd_compile_options + \ COMPILE_OPTIONS + \ contained + +syn keyword cmakeKWadd_custom_command + \ APPEND ARGS BYPRODUCTS COMMAND COMMENT DEPENDS GENERATE GENERATED IMPLICIT_DEPENDS MAIN_DEPENDENCY NOT OUTPUT POST_BUILD PRE_BUILD PRE_LINK SYMBOLIC TARGET TARGET_FILE USES_TERMINAL VERBATIM WORKING_DIRECTORY + \ contained + +syn keyword cmakeKWadd_custom_target + \ ALL BYPRODUCTS COMMAND COMMENT DEPENDS GENERATE GENERATED SOURCES USES_TERMINAL VERBATIM WORKING_DIRECTORY + \ contained + +syn keyword cmakeKWadd_definitions + \ COMPILE_DEFINITIONS + \ contained + +syn keyword cmakeKWadd_dependencies + \ DEPENDS OBJECT_DEPENDS + \ contained + +syn keyword cmakeKWadd_executable + \ ALIAS CONFIG EXCLUDE_FROM_ALL GLOBAL IMPORTED IMPORTED_ IMPORTED_LOCATION IMPORTED_LOCATION_ MACOSX_BUNDLE OUTPUT_NAME RUNTIME_OUTPUT_DIRECTORY TARGET + \ contained + +syn keyword cmakeKWadd_library + \ ALIAS ARCHIVE_OUTPUT_DIRECTORY CLI CONFIG DLL EXCLUDE_FROM_ALL FRAMEWORK GLOBAL IMPORTED IMPORTED_ IMPORTED_LOCATION IMPORTED_LOCATION_ INTERFACE INTERFACE_ LIBRARY_OUTPUT_DIRECTORY MODULE OBJECT ON OS OUTPUT_NAME POSITION_INDEPENDENT_CODE POST_BUILD PRE_BUILD PRE_LINK RUNTIME_OUTPUT_DIRECTORY SHARED STATIC TARGET TARGET_OBJECTS UNKNOWN + \ contained + +syn keyword cmakeKWadd_subdirectory + \ ALL EXCLUDE_FROM_ALL + \ contained + +syn keyword cmakeKWadd_test + \ BUILD_TESTING COMMAND CONFIGURATION CONFIGURATIONS FAIL_REGULAR_EXPRESSION NAME ON PASS_REGULAR_EXPRESSION TARGET_FILE WILL_FAIL WORKING_DIRECTORY + \ contained + +syn keyword cmakeKWbuild_command + \ CONFIGURATION NEW TARGET + \ contained + +syn keyword cmakeKWbuild_name + \ CMAKE_CXX_COMPILER + \ contained + +syn keyword cmakeKWcmake_host_system_information + \ AVAILABLE_PHYSICAL_MEMORY AVAILABLE_VIRTUAL_MEMORY FQDN HOSTNAME NUMBER_OF_LOGICAL_CORES NUMBER_OF_PHYSICAL_CORES QUERY RESULT TOTAL_PHYSICAL_MEMORY TOTAL_VIRTUAL_MEMORY + \ contained + +syn keyword cmakeKWcmake_minimum_required + \ FATAL_ERROR VERSION + \ contained + +syn keyword cmakeKWcmake_parse_arguments + \ ARGN CONFIGURATIONS DESTINATION FALSE FAST FILES MY_INSTALL MY_INSTALL_CONFIGURATIONS MY_INSTALL_DESTINATION MY_INSTALL_FAST MY_INSTALL_OPTIONAL MY_INSTALL_RENAME MY_INSTALL_TARGETS MY_INSTALL_UNPARSED_ARGUMENTS OPTIONAL RENAME TARGETS TRUE _UNPARSED_ARGUMENTS + \ contained + +syn keyword cmakeKWcmake_policy + \ CMAKE_POLICY_DEFAULT_CMP CMP GET NEW NNNN NO_POLICY_SCOPE OLD POP PUSH SET VERSION + \ contained + +syn keyword cmakeKWconfigure_file + \ COPYONLY CRLF DOS ESCAPE_QUOTES FOO_ENABLE FOO_STRING LF NEWLINE_STYLE ON ONLY VAR + \ contained + +syn keyword cmakeKWcreate_test_sourcelist + \ CMAKE_TESTDRIVER_AFTER_TESTMAIN CMAKE_TESTDRIVER_BEFORE_TESTMAIN EXTRA_INCLUDE FUNCTION + \ contained + +syn keyword cmakeKWctest_build + \ ALL_BUILD APPEND BUILD CONFIGURATION CTEST_BUILD_CONFIGURATION CTEST_BUILD_FLAGS CTEST_BUILD_TARGET CTEST_PROJECT_NAME FLAGS NUMBER_ERRORS NUMBER_WARNINGS QUIET RETURN_VALUE TARGET + \ contained + +syn keyword cmakeKWctest_configure + \ APPEND BUILD OPTIONS QUIET RETURN_VALUE SOURCE + \ contained + +syn keyword cmakeKWctest_coverage + \ APPEND BUILD LABELS QUIET RETURN_VALUE + \ contained + +syn keyword cmakeKWctest_memcheck + \ APPEND BUILD END EXCLUDE EXCLUDE_LABEL INCLUDE INCLUDE_LABEL OFF ON PARALLEL_LEVEL QUIET RETURN_VALUE SCHEDULE_RANDOM START STOP_TIME STRIDE TEST_LOAD + \ contained + +syn keyword cmakeKWctest_run_script + \ NEW_PROCESS RETURN_VALUE + \ contained + +syn keyword cmakeKWctest_start + \ APPEND QUIET TAG TRACK + \ contained + +syn keyword cmakeKWctest_submit + \ API CDASH_UPLOAD CDASH_UPLOAD_TYPE CTEST_EXTRA_SUBMIT_FILES CTEST_NOTES_FILES FILES PARTS QUIET RETRY_COUNT RETRY_DELAY RETURN_VALUE + \ contained + +syn keyword cmakeKWctest_test + \ APPEND BUILD CPU END EXCLUDE EXCLUDE_LABEL INCLUDE INCLUDE_LABEL OFF ON PARALLEL_LEVEL QUIET RETURN_VALUE SCHEDULE_RANDOM START STOP_TIME STRIDE TEST_LOAD + \ contained + +syn keyword cmakeKWctest_update + \ QUIET RETURN_VALUE SOURCE + \ contained + +syn keyword cmakeKWctest_upload + \ FILES QUIET + \ contained + +syn keyword cmakeKWdefine_property + \ BRIEF_DOCS CACHED_VARIABLE DIRECTORY FULL_DOCS GLOBAL INHERITED PROPERTY SOURCE TARGET TEST VARIABLE + \ contained + +syn keyword cmakeKWenable_language + \ OPTIONAL + \ contained + +syn keyword cmakeKWexec_program + \ ARGS OUTPUT_VARIABLE RETURN_VALUE + \ contained + +syn keyword cmakeKWexecute_process + \ COMMAND ERROR_ ERROR_FILE ERROR_QUIET ERROR_STRIP_TRAILING_WHITESPACE ERROR_VARIABLE INPUT_ INPUT_FILE OUTPUT_ OUTPUT_FILE OUTPUT_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE RESULT_VARIABLE TIMEOUT VERBATIM WORKING_DIRECTORY + \ contained + +syn keyword cmakeKWexport + \ APPEND CONFIG EXPORT EXPORT_LINK_INTERFACE_LIBRARIES FILE IMPORTED IMPORTED_ LINK_INTERFACE_LIBRARIES NAMESPACE NEW PACKAGE TARGETS + \ contained + +syn keyword cmakeKWexport_library_dependencies + \ APPEND EXPORT INCLUDE LINK_INTERFACE_LIBRARIES SET + \ contained + +syn keyword cmakeKWfile + \ ALGO APPEND ASCII CMAKE_TLS_CAINFO CMAKE_TLS_VERIFY CONDITION CONFIG CONTENT COPY CR DESTINATION DIRECTORY DIRECTORY_PERMISSIONS DOWNLOAD ENCODING EXCLUDE EXPECTED_HASH FILE FILES_MATCHING FILE_PERMISSIONS FOLLOW_SYMLINKS FUNCTION GENERATE GLOB GLOB_RECURSE GUARD HEX INACTIVITY_TIMEOUT INPUT INSTALL LENGTH_MAXIMUM LENGTH_MINIMUM LF LIMIT LIMIT_COUNT LIMIT_INPUT LIMIT_OUTPUT LIST_DIRECTORIES LOCK LOG MAKE_DIRECTORY NEW NEWLINE_CONSUME NO_HEX_CONVERSION NO_SOURCE_PERMISSIONS OFF OFFSET OLD ON OUTPUT PATH PATTERN PERMISSIONS PROCESS READ REGEX RELATIVE RELATIVE_PATH RELEASE REMOVE REMOVE_RECURSE RENAME RESULT_VARIABLE SHOW_PROGRESS SORT SSL STATUS STRINGS TIMEOUT TIMESTAMP TLS TLS_CAINFO TLS_VERIFY TO_CMAKE_PATH TO_NATIVE_PATH UPLOAD USE_SOURCE_PERMISSIONS UTC UTF WRITE + \ contained + +syn keyword cmakeKWfind_file + \ CMAKE_FIND_ROOT_PATH_BOTH DOC DVAR HINTS INCLUDE NAMES NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_FIND_ROOT_PATH NO_CMAKE_PATH NO_CMAKE_SYSTEM_PATH NO_DEFAULT_PATH NO_SYSTEM_ENVIRONMENT_PATH ONLY_CMAKE_FIND_ROOT_PATH OS PATH PATHS PATH_SUFFIXES VAR + \ contained + +syn keyword cmakeKWfind_library + \ CMAKE_FIND_ROOT_PATH_BOTH DOC DVAR HINTS LIB NAMES NAMES_PER_DIR NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_FIND_ROOT_PATH NO_CMAKE_PATH NO_CMAKE_SYSTEM_PATH NO_DEFAULT_PATH NO_SYSTEM_ENVIRONMENT_PATH ONLY_CMAKE_FIND_ROOT_PATH OS PATH PATHS PATH_SUFFIXES VAR + \ contained + +syn keyword cmakeKWfind_package + \ CMAKE_DISABLE_FIND_PACKAGE_ CMAKE_FIND_ROOT_PATH_BOTH COMPONENTS CONFIG CONFIGS DVAR EXACT HINTS MODULE NAMES NO_CMAKE_BUILDS_PATH NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_FIND_ROOT_PATH NO_CMAKE_PACKAGE_REGISTRY NO_CMAKE_PATH NO_CMAKE_SYSTEM_PACKAGE_REGISTRY NO_CMAKE_SYSTEM_PATH NO_DEFAULT_PATH NO_MODULE NO_POLICY_SCOPE NO_SYSTEM_ENVIRONMENT_PATH ONLY_CMAKE_FIND_ROOT_PATH OPTIONAL_COMPONENTS OS PACKAGE_FIND_NAME PACKAGE_FIND_VERSION PACKAGE_FIND_VERSION_COUNT PACKAGE_FIND_VERSION_MAJOR PACKAGE_FIND_VERSION_MINOR PACKAGE_FIND_VERSION_PATCH PACKAGE_FIND_VERSION_TWEAK PACKAGE_VERSION PACKAGE_VERSION_COMPATIBLE PACKAGE_VERSION_EXACT PACKAGE_VERSION_UNSUITABLE PATH PATHS PATH_SUFFIXES QUIET REQUIRED TRUE _CONFIG _CONSIDERED_CONFIGS _CONSIDERED_VERSIONS _DIR _FIND_COMPONENTS _FIND_QUIETLY _FIND_REQUIRED _FIND_REQUIRED_ _FIND_VERSION _FIND_VERSION_COUNT _FIND_VERSION_EXACT _FIND_VERSION_MAJOR _FIND_VERSION_MINOR _FIND_VERSION_PATCH _FIND_VERSION_TWEAK _FOUND _VERSION _VERSION_COUNT _VERSION_MAJOR _VERSION_MINOR _VERSION_PATCH _VERSION_TWEAK + \ contained + +syn keyword cmakeKWfind_path + \ CMAKE_FIND_ROOT_PATH_BOTH DOC DVAR HINTS INCLUDE NAMES NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_FIND_ROOT_PATH NO_CMAKE_PATH NO_CMAKE_SYSTEM_PATH NO_DEFAULT_PATH NO_SYSTEM_ENVIRONMENT_PATH ONLY_CMAKE_FIND_ROOT_PATH OS PATH PATHS PATH_SUFFIXES VAR + \ contained + +syn keyword cmakeKWfind_program + \ CMAKE_FIND_ROOT_PATH_BOTH DOC DVAR HINTS NAMES NAMES_PER_DIR NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_FIND_ROOT_PATH NO_CMAKE_PATH NO_CMAKE_SYSTEM_PATH NO_DEFAULT_PATH NO_SYSTEM_ENVIRONMENT_PATH ONLY_CMAKE_FIND_ROOT_PATH OS PATH PATHS PATH_SUFFIXES VAR + \ contained + +syn keyword cmakeKWfltk_wrap_ui + \ FLTK + \ contained + +syn keyword cmakeKWforeach + \ ARGS IN ITEMS LISTS RANGE + \ contained + +syn keyword cmakeKWfunction + \ ARGC ARGN ARGS ARGV PARENT_SCOPE + \ contained + +syn keyword cmakeKWget_cmake_property + \ VAR + \ contained + +syn keyword cmakeKWget_directory_property + \ DEFINITION DIRECTORY + \ contained + +syn keyword cmakeKWget_filename_component + \ ABSOLUTE ARG_VAR BASE_DIR CACHE COMP DIRECTORY EXT NAME NAME_WE PATH PROGRAM PROGRAM_ARGS REALPATH VAR + \ contained + +syn keyword cmakeKWget_property + \ BRIEF_DOCS CACHE DEFINED DIRECTORY FULL_DOCS GLOBAL INSTALL PROPERTY SET SOURCE TARGET TEST VARIABLE + \ contained + +syn keyword cmakeKWget_source_file_property + \ LOCATION VAR + \ contained + +syn keyword cmakeKWget_target_property + \ VAR + \ contained + +syn keyword cmakeKWget_test_property + \ VAR + \ contained + +syn keyword cmakeKWif + \ AND ARGS CMP COMMAND DEFINED EQUAL EXISTS FALSE GREATER IGNORE IN_LIST IS_ABSOLUTE IS_DIRECTORY IS_NEWER_THAN IS_SYMLINK LESS MATCHES NNNN NO NOT OFF ON OR POLICY STREQUAL STRGREATER STRLESS TARGET TEST THEN TRUE VERSION_EQUAL VERSION_GREATER VERSION_LESS YES + \ contained + +syn keyword cmakeKWinclude + \ NO_POLICY_SCOPE OPTIONAL RESULT_VARIABLE VAR + \ contained + +syn keyword cmakeKWinclude_directories + \ AFTER BEFORE INCLUDE_DIRECTORIES ON SYSTEM + \ contained + +syn keyword cmakeKWinclude_external_msproject + \ GUID PLATFORM TYPE WIX + \ contained + +syn keyword cmakeKWinstall + \ ARCHIVE BUNDLE CODE COMPONENT CONFIG CONFIGURATIONS CVS DESTDIR DESTINATION DIRECTORY DIRECTORY_PERMISSIONS DLL EXCLUDE EXCLUDE_FROM_ALL EXPORT EXPORT_LINK_INTERFACE_LIBRARIES FILE FILES FILES_MATCHING FILE_PERMISSIONS FRAMEWORK GROUP_EXECUTE GROUP_READ GROUP_WRITE IMPORTED_ INCLUDES INSTALL_PREFIX INTERFACE_INCLUDE_DIRECTORIES LIBRARY LINK_INTERFACE_LIBRARIES MACOSX_BUNDLE MESSAGE MESSAGE_NEVER NAMELINK_ONLY NAMELINK_SKIP NAMESPACE NEW OPTIONAL OS OWNER_EXECUTE OWNER_READ OWNER_WRITE PATTERN PERMISSIONS POST_INSTALL_SCRIPT PRE_INSTALL_SCRIPT PRIVATE_HEADER PROGRAMS PUBLIC_HEADER REGEX RENAME RESOURCE RUNTIME SCRIPT SETGID SETUID SOVERSION TARGETS TRUE USE_SOURCE_PERMISSIONS VERSION WORLD_EXECUTE WORLD_READ WORLD_WRITE + \ contained + +syn keyword cmakeKWinstall_files + \ FILES GLOB + \ contained + +syn keyword cmakeKWinstall_programs + \ FILES GLOB PROGRAMS TARGETS + \ contained + +syn keyword cmakeKWinstall_targets + \ DLL RUNTIME_DIRECTORY TARGETS + \ contained + +syn keyword cmakeKWlist + \ APPEND CACHE FIND GET INSERT INTERNAL LENGTH LIST NOTES PARENT_SCOPE REMOVE_AT REMOVE_DUPLICATES REMOVE_ITEM REVERSE SORT + \ contained + +syn keyword cmakeKWload_cache + \ EXCLUDE INCLUDE_INTERNALS READ_WITH_PREFIX + \ contained + +syn keyword cmakeKWload_command + \ CMAKE_LOADED_COMMAND_ COMMAND_NAME + \ contained + +syn keyword cmakeKWmacro + \ ARGC ARGN ARGS ARGV DEFINED GREATER IN LISTS NOT _BAR _FOO + \ contained + +syn keyword cmakeKWmake_directory + \ MAKE_DIRECTORY + \ contained + +syn keyword cmakeKWmark_as_advanced + \ CLEAR FORCE VAR + \ contained + +syn keyword cmakeKWmath + \ EXPR + \ contained + +syn keyword cmakeKWmessage + \ AUTHOR_WARNING DEPRECATION FATAL_ERROR GUI SEND_ERROR STATUS WARNING + \ contained + +syn keyword cmakeKWoption + \ OFF ON + \ contained + +syn keyword cmakeKWproject + \ CMAKE_PROJECT_ LANGUAGES NAME NEW NONE PROJECT VERSION _BINARY_DIR _INCLUDE _SOURCE_DIR _VERSION _VERSION_MAJOR _VERSION_MINOR _VERSION_PATCH _VERSION_TWEAK + \ contained + +syn keyword cmakeKWremove + \ REMOVE_ITEM VALUE VAR + \ contained + +syn keyword cmakeKWseparate_arguments + \ MSDN UNIX_COMMAND VARIABLE WINDOWS WINDOWS_COMMAND _COMMAND + \ contained + +syn keyword cmakeKWset + \ BOOL CACHE FILEPATH FORCE INTERNAL OFF ON PARENT_SCOPE PATH STRING STRINGS + \ contained + +syn keyword cmakeKWset_directory_properties + \ PROPERTIES + \ contained + +syn keyword cmakeKWset_property + \ APPEND APPEND_STRING CACHE DIRECTORY GLOBAL INSTALL PROPERTY SOURCE TARGET TEST WIX + \ contained + +syn keyword cmakeKWset_source_files_properties + \ PROPERTIES + \ contained + +syn keyword cmakeKWset_target_properties + \ PROPERTIES + \ contained + +syn keyword cmakeKWset_tests_properties + \ PROPERTIES + \ contained + +syn keyword cmakeKWsource_group + \ FILES REGULAR_EXPRESSION + \ contained + +syn keyword cmakeKWstring + \ ALPHABET APPEND ASCII CMAKE_MATCH_ COMPARE CONCAT CONFIGURE EQUAL ESCAPE_QUOTES FIND GENEX_STRIP GREATER GUID LENGTH LESS MAKE_C_IDENTIFIER MATCH MATCHALL MATCHES NAME NAMESPACE NOTEQUAL ONLY RANDOM RANDOM_SEED REGEX REPLACE REVERSE STRIP SUBSTRING SZ TIMESTAMP TOLOWER TOUPPER TYPE UPPER UTC UUID + \ contained + +syn keyword cmakeKWsubdirs + \ EXCLUDE_FROM_ALL PREORDER + \ contained + +syn keyword cmakeKWtarget_compile_definitions + \ COMPILE_DEFINITIONS INTERFACE INTERFACE_COMPILE_DEFINITIONS PRIVATE PUBLIC + \ contained + +syn keyword cmakeKWtarget_compile_features + \ COMPILE_FEATURES IMPORTED INTERFACE INTERFACE_COMPILE_FEATURES PRIVATE PUBLIC + \ contained + +syn keyword cmakeKWtarget_compile_options + \ BEFORE COMPILE_OPTIONS IMPORTED INTERFACE INTERFACE_COMPILE_OPTIONS PRIVATE PUBLIC + \ contained + +syn keyword cmakeKWtarget_include_directories + \ BEFORE BUILD_INTERFACE IMPORTED INCLUDE_DIRECTORIES INSTALL_INTERFACE INTERFACE INTERFACE_INCLUDE_DIRECTORIES INTERFACE_LINK_LIBRARIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES PRIVATE PUBLIC SYSTEM + \ contained + +syn keyword cmakeKWtarget_link_libraries + \ ALIAS DAG DEBUG_CONFIGURATIONS IMPORTED IMPORTED_NO_SONAME INTERFACE INTERFACE_LINK_LIBRARIES LINK_INTERFACE_LIBRARIES LINK_INTERFACE_LIBRARIES_DEBUG LINK_INTERFACE_MULTIPLICITY LINK_PRIVATE LINK_PUBLIC NEW OLD OSX PRIVATE PUBLIC SONAME STATIC + \ contained + +syn keyword cmakeKWtarget_sources + \ IMPORTED INTERFACE INTERFACE_SOURCES PRIVATE PUBLIC SOURCES + \ contained + +syn keyword cmakeKWtry_compile + \ ALL_BUILD CMAKE_FLAGS COMPILE_DEFINITIONS COPY_FILE COPY_FILE_ERROR DEFINED DLINK_LIBRARIES DVAR FALSE INCLUDE_DIRECTORIES LINK_DIRECTORIES LINK_LIBRARIES NEW NOT OUTPUT_VARIABLE RESULT_VAR SOURCES TRUE TYPE VALUE + \ contained + +syn keyword cmakeKWtry_run + \ ARGS CMAKE_FLAGS COMPILE_DEFINITIONS COMPILE_OUTPUT_VARIABLE COMPILE_RESULT_VAR DLINK_LIBRARIES DVAR FAILED_TO_RUN FALSE INCLUDE_DIRECTORIES LINK_DIRECTORIES LINK_LIBRARIES OUTPUT_VARIABLE RUN_OUTPUT_VARIABLE RUN_RESULT_VAR TRUE TYPE VALUE __TRYRUN_OUTPUT + \ contained + +syn keyword cmakeKWunset + \ CACHE LD_LIBRARY_PATH PARENT_SCOPE + \ contained + +syn keyword cmakeKWuse_mangled_mesa + \ GL OUTPUT_DIRECTORY PATH_TO_MESA + \ contained + +syn keyword cmakeKWvariable_requires + \ RESULT_VARIABLE TEST_VARIABLE + \ contained + +syn keyword cmakeKWvariable_watch + \ COMMAND + \ contained + +syn keyword cmakeKWwhile + \ ARGS + \ contained + +syn keyword cmakeKWwrite_file + \ APPEND CONFIGURE_FILE NOTE WRITE + \ contained + + +syn keyword cmakeGeneratorExpressions + \ LINK_LIBRARIES INCLUDE_DIRECTORIES COMPILE_DEFINITIONS CONFIG DEBUG_MODE DEBUG_MODE BOOL AND OR NOT STREQUAL STREQUAL EQUAL EQUAL CONFIG MAP_IMPORTED_CONFIG_ CONFIG IMPORTED PLATFORM_ID C_COMPILER_ID CXX_COMPILER_ID VERSION_GREATER VERSION_LESS VERSION_EQUAL C_COMPILER_VERSION CXX_COMPILER_VERSION TARGET_POLICY NEW COMPILE_FEATURES C_STANDARD CXX_STANDARD COMPILE_LANGUAGE PRIVATE COMPILE_LANGUAGE PUBLIC PRIVATE COMPILE_LANGUAGE COMPILING_CXX PRIVATE COMPILE_LANGUAGE CXX_COMPILER_ID GNU VERSION_LESS CXX_COMPILER_VERSION OLD_COMPILER OLD_COMPILER CMAKE_CXX_COMPILER_VERSION CONFIGURATION CONFIG CONFIG PLATFORM_ID C_COMPILER_ID CMAKE_ LANG _COMPILER_ID CXX_COMPILER_ID CMAKE_ LANG _COMPILER_ID C_COMPILER_VERSION CMAKE_ LANG _COMPILER_VERSION CXX_COMPILER_VERSION CMAKE_ LANG _COMPILER_VERSION TARGET_FILE TARGET_FILE_NAME TARGET_FILE_DIR TARGET_LINKER_FILE TARGET_LINKER_FILE_NAME TARGET_LINKER_FILE_DIR TARGET_SONAME_FILE TARGET_SONAME_FILE_NAME TARGET_SONAME_FILE_DIR TARGET_PDB_FILE PDB_NAME PDB_OUTPUT_DIRECTORY PDB_NAME_ CONFIG PDB_OUTPUT_DIRECTORY_ CONFIG TARGET_PDB_FILE_NAME TARGET_PDB_FILE_DIR TARGET_PROPERTY TARGET_PROPERTY INSTALL_PREFIX EXPORT COMPILE_LANGUAGE JOIN TARGET_PROPERTY INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES BOOL JOIN TARGET_PROPERTY INCLUDE_DIRECTORIES JOIN ANGLE COMMA SEMICOLON TARGET_NAME LINK_ONLY INTERFACE_LINK_LIBRARIES INSTALL_INTERFACE EXPORT BUILD_INTERFACE LOWER_CASE UPPER_CASE MAKE_C_IDENTIFIER TARGET_OBJECTS OBJECT_LIBRARY SHELL_PATH MSYS + \ contained + +syn case ignore +syn keyword cmakeCommand + \ add_compile_options add_custom_command add_custom_target add_definitions add_dependencies add_executable add_library add_subdirectory add_test aux_source_directory break build_command cmake_host_system_information cmake_minimum_required cmake_parse_arguments cmake_policy configure_file continue create_test_sourcelist ctest_build ctest_configure ctest_coverage ctest_empty_binary_directory ctest_memcheck ctest_read_custom_files ctest_run_script ctest_sleep ctest_start ctest_submit ctest_test ctest_update ctest_upload define_property enable_language enable_testing endfunction endmacro execute_process export file find_file find_library find_package find_path find_program fltk_wrap_ui function get_cmake_property get_directory_property get_filename_component get_property get_source_file_property get_target_property get_test_property include include_directories include_external_msproject include_regular_expression install link_directories list load_cache load_command macro mark_as_advanced math message option project qt_wrap_cpp qt_wrap_ui remove_definitions return separate_arguments set set_directory_properties set_property set_source_files_properties set_target_properties set_tests_properties site_name source_group string target_compile_definitions target_compile_features target_compile_options target_include_directories target_link_libraries target_sources try_compile try_run unset variable_watch + \ nextgroup=cmakeArguments +syn keyword cmakeCommandConditional + \ else elseif endif if + \ nextgroup=cmakeArguments +syn keyword cmakeCommandRepeat + \ endforeach endwhile foreach while + \ nextgroup=cmakeArguments +syn keyword cmakeCommandDeprecated + \ build_name exec_program export_library_dependencies install_files install_programs install_targets link_libraries make_directory output_required_files remove subdir_depends subdirs use_mangled_mesa utility_source variable_requires write_file + \ nextgroup=cmakeArguments +syn case match + +syn keyword cmakeTodo + \ TODO FIXME XXX + \ contained + +hi def link cmakeCommand Function +hi def link cmakeCommandConditional Conditional +hi def link cmakeCommandDeprecated WarningMsg +hi def link cmakeCommandRepeat Repeat +hi def link cmakeComment Comment +hi def link cmakeEnvironment Special +hi def link cmakeEscaped Special +hi def link cmakeGeneratorExpression WarningMsg +hi def link cmakeGeneratorExpressions ModeMsg +hi def link cmakeLuaComment Comment +hi def link cmakeModule Include +hi def link cmakeProperty Constant +hi def link cmakeRegistry Underlined +hi def link cmakeString String +hi def link cmakeTodo TODO +hi def link cmakeVariable Identifier +hi def link cmakeVariableValue Type + +hi def link cmakeKWExternalProject ModeMsg +hi def link cmakeKWadd_compile_options ModeMsg +hi def link cmakeKWadd_custom_command ModeMsg +hi def link cmakeKWadd_custom_target ModeMsg +hi def link cmakeKWadd_definitions ModeMsg +hi def link cmakeKWadd_dependencies ModeMsg +hi def link cmakeKWadd_executable ModeMsg +hi def link cmakeKWadd_library ModeMsg +hi def link cmakeKWadd_subdirectory ModeMsg +hi def link cmakeKWadd_test ModeMsg +hi def link cmakeKWbuild_command ModeMsg +hi def link cmakeKWbuild_name ModeMsg +hi def link cmakeKWcmake_host_system_information ModeMsg +hi def link cmakeKWcmake_minimum_required ModeMsg +hi def link cmakeKWcmake_parse_arguments ModeMsg +hi def link cmakeKWcmake_policy ModeMsg +hi def link cmakeKWconfigure_file ModeMsg +hi def link cmakeKWcreate_test_sourcelist ModeMsg +hi def link cmakeKWctest_build ModeMsg +hi def link cmakeKWctest_configure ModeMsg +hi def link cmakeKWctest_coverage ModeMsg +hi def link cmakeKWctest_memcheck ModeMsg +hi def link cmakeKWctest_run_script ModeMsg +hi def link cmakeKWctest_start ModeMsg +hi def link cmakeKWctest_submit ModeMsg +hi def link cmakeKWctest_test ModeMsg +hi def link cmakeKWctest_update ModeMsg +hi def link cmakeKWctest_upload ModeMsg +hi def link cmakeKWdefine_property ModeMsg +hi def link cmakeKWenable_language ModeMsg +hi def link cmakeKWexec_program ModeMsg +hi def link cmakeKWexecute_process ModeMsg +hi def link cmakeKWexport ModeMsg +hi def link cmakeKWexport_library_dependencies ModeMsg +hi def link cmakeKWfile ModeMsg +hi def link cmakeKWfind_file ModeMsg +hi def link cmakeKWfind_library ModeMsg +hi def link cmakeKWfind_package ModeMsg +hi def link cmakeKWfind_path ModeMsg +hi def link cmakeKWfind_program ModeMsg +hi def link cmakeKWfltk_wrap_ui ModeMsg +hi def link cmakeKWforeach ModeMsg +hi def link cmakeKWfunction ModeMsg +hi def link cmakeKWget_cmake_property ModeMsg +hi def link cmakeKWget_directory_property ModeMsg +hi def link cmakeKWget_filename_component ModeMsg +hi def link cmakeKWget_property ModeMsg +hi def link cmakeKWget_source_file_property ModeMsg +hi def link cmakeKWget_target_property ModeMsg +hi def link cmakeKWget_test_property ModeMsg +hi def link cmakeKWif ModeMsg +hi def link cmakeKWinclude ModeMsg +hi def link cmakeKWinclude_directories ModeMsg +hi def link cmakeKWinclude_external_msproject ModeMsg +hi def link cmakeKWinstall ModeMsg +hi def link cmakeKWinstall_files ModeMsg +hi def link cmakeKWinstall_programs ModeMsg +hi def link cmakeKWinstall_targets ModeMsg +hi def link cmakeKWlist ModeMsg +hi def link cmakeKWload_cache ModeMsg +hi def link cmakeKWload_command ModeMsg +hi def link cmakeKWmacro ModeMsg +hi def link cmakeKWmake_directory ModeMsg +hi def link cmakeKWmark_as_advanced ModeMsg +hi def link cmakeKWmath ModeMsg +hi def link cmakeKWmessage ModeMsg +hi def link cmakeKWoption ModeMsg +hi def link cmakeKWproject ModeMsg +hi def link cmakeKWremove ModeMsg +hi def link cmakeKWseparate_arguments ModeMsg +hi def link cmakeKWset ModeMsg +hi def link cmakeKWset_directory_properties ModeMsg +hi def link cmakeKWset_property ModeMsg +hi def link cmakeKWset_source_files_properties ModeMsg +hi def link cmakeKWset_target_properties ModeMsg +hi def link cmakeKWset_tests_properties ModeMsg +hi def link cmakeKWsource_group ModeMsg +hi def link cmakeKWstring ModeMsg +hi def link cmakeKWsubdirs ModeMsg +hi def link cmakeKWtarget_compile_definitions ModeMsg +hi def link cmakeKWtarget_compile_features ModeMsg +hi def link cmakeKWtarget_compile_options ModeMsg +hi def link cmakeKWtarget_include_directories ModeMsg +hi def link cmakeKWtarget_link_libraries ModeMsg +hi def link cmakeKWtarget_sources ModeMsg +hi def link cmakeKWtry_compile ModeMsg +hi def link cmakeKWtry_run ModeMsg +hi def link cmakeKWunset ModeMsg +hi def link cmakeKWuse_mangled_mesa ModeMsg +hi def link cmakeKWvariable_requires ModeMsg +hi def link cmakeKWvariable_watch ModeMsg +hi def link cmakeKWwhile ModeMsg +hi def link cmakeKWwrite_file ModeMsg + +let b:current_syntax = "cmake" https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f21a823598c672efd73de09b826acaeba231946c commit f21a823598c672efd73de09b826acaeba231946c Author: Brad King AuthorDate: Wed Aug 17 09:07:21 2016 -0400 Commit: Brad King CommitDate: Wed Aug 17 09:11:13 2016 -0400 Aux: Drop vim files prior to import of third-party version diff --git a/Auxiliary/CMakeLists.txt b/Auxiliary/CMakeLists.txt index c003b28..4567d10 100644 --- a/Auxiliary/CMakeLists.txt +++ b/Auxiliary/CMakeLists.txt @@ -1,4 +1,3 @@ -install(FILES cmake-help.vim cmake-indent.vim cmake-syntax.vim DESTINATION ${CMAKE_DATA_DIR}/editors/vim) install(FILES cmake-mode.el DESTINATION ${CMAKE_DATA_DIR}/editors/emacs) install(FILES cmake.m4 DESTINATION share/aclocal) add_subdirectory (bash-completion) diff --git a/Auxiliary/cmake-help.vim b/Auxiliary/cmake-help.vim deleted file mode 100644 index 17cfa83..0000000 --- a/Auxiliary/cmake-help.vim +++ /dev/null @@ -1,21 +0,0 @@ -nmap ,hc :call OpenCmakeHelp() - -function! OpenCmakeHelp() - let s = getline( '.' ) - let i = col( '.' ) - 1 - while i > 0 && strpart( s, i, 1 ) =~ '[A-Za-z0-9_]' - let i = i - 1 - endwhile - while i < col('$') && strpart( s, i, 1 ) !~ '[A-Za-z0-9_]' - let i = i + 1 - endwhile - let start = match( s, '[A-Za-z0-9_]\+', i ) - let end = matchend( s, '[A-Za-z0-9_]\+', i ) - let ident = strpart( s, start, end - start ) - execute "vertical new" - execute "%!cmake --help-command ".ident - set nomodified - set readonly -endfunction - -autocmd BufRead,BufNewFile *.cmake,CMakeLists.txt,*.cmake.in nmap :call OpenCmakeHelp() diff --git a/Auxiliary/cmake-indent.vim b/Auxiliary/cmake-indent.vim deleted file mode 100644 index fa088e4..0000000 --- a/Auxiliary/cmake-indent.vim +++ /dev/null @@ -1,93 +0,0 @@ -" ============================================================================= -" -" Program: CMake - Cross-Platform Makefile Generator -" Module: $RCSfile$ -" Language: VIM -" Date: $Date$ -" Version: $Revision$ -" -" ============================================================================= - -" Vim indent file -" Language: CMake (ft=cmake) -" Author: Andy Cedilnik -" Maintainer: Karthik Krishnan -" Last Change: $Date$ -" Version: $Revision$ -" -" Licence: The CMake license applies to this file. See -" https://cmake.org/licensing -" This implies that distribution with Vim is allowed - -if exists("b:did_indent") - finish -endif -let b:did_indent = 1 - -setlocal indentexpr=CMakeGetIndent(v:lnum) -setlocal indentkeys+==ENDIF(,ENDFOREACH(,ENDMACRO(,ELSE(,ELSEIF(,ENDWHILE( - -" Only define the function once. -if exists("*CMakeGetIndent") - finish -endif - -fun! CMakeGetIndent(lnum) - let this_line = getline(a:lnum) - - " Find a non-blank line above the current line. - let lnum = a:lnum - let lnum = prevnonblank(lnum - 1) - let previous_line = getline(lnum) - - " Hit the start of the file, use zero indent. - if lnum == 0 - return 0 - endif - - let ind = indent(lnum) - - let or = '\|' - " Regular expressions used by line indentation function. - let cmake_regex_comment = '#.*' - let cmake_regex_identifier = '[A-Za-z][A-Za-z0-9_]*' - let cmake_regex_quoted = '"\([^"\\]\|\\.\)*"' - let cmake_regex_arguments = '\(' . cmake_regex_quoted . - \ or . '\$(' . cmake_regex_identifier . ')' . - \ or . '[^()\\#"]' . or . '\\.' . '\)*' - - let cmake_indent_comment_line = '^\s*' . cmake_regex_comment - let cmake_indent_blank_regex = '^\s*$' - let cmake_indent_open_regex = '^\s*' . cmake_regex_identifier . - \ '\s*(' . cmake_regex_arguments . - \ '\(' . cmake_regex_comment . '\)\?$' - - let cmake_indent_close_regex = '^' . cmake_regex_arguments . - \ ')\s*' . - \ '\(' . cmake_regex_comment . '\)\?$' - - let cmake_indent_begin_regex = '^\s*\(IF\|MACRO\|FOREACH\|ELSE\|ELSEIF\|WHILE\|FUNCTION\)\s*(' - let cmake_indent_end_regex = '^\s*\(ENDIF\|ENDFOREACH\|ENDMACRO\|ELSE\|ELSEIF\|ENDWHILE\|ENDFUNCTION\)\s*(' - - " Add - if previous_line =~? cmake_indent_comment_line " Handle comments - let ind = ind - else - if previous_line =~? cmake_indent_begin_regex - let ind = ind + &sw - endif - if previous_line =~? cmake_indent_open_regex - let ind = ind + &sw - endif - endif - - " Subtract - if this_line =~? cmake_indent_end_regex - let ind = ind - &sw - endif - if previous_line =~? cmake_indent_close_regex - let ind = ind - &sw - endif - - return ind -endfun diff --git a/Auxiliary/cmake-syntax.vim b/Auxiliary/cmake-syntax.vim deleted file mode 100644 index 9ffc1e8..0000000 --- a/Auxiliary/cmake-syntax.vim +++ /dev/null @@ -1,559 +0,0 @@ -" vim: set nowrap: -" Vim syntax file -" Language: CMake -" Author: Andy Cedilnik , Nicholas Hutchinson , Patrick Boettcher -" Maintainer: Karthik Krishnan -" Last Change: $Date$ -" Version: $Revision$ -" -" Licence: The CMake license applies to this file. See -" https://cmake.org/licensing -" This implies that distribution with Vim is allowed - -if exists("b:current_syntax") - finish -endif - -syn match cmakeEscaped /\(\\\\\|\\"\|\\n\|\\t\)/ contained -syn region cmakeComment start="#" end="$" contains=cmakeTodo, at Spell -syn region cmakeLuaComment start="\[\z(=*\)\[" end="\]\z1\]" contains=cmakeTodo, at Spell -syn region cmakeGeneratorExpression start=/$/ - \ contained oneline contains=CONTAINED,cmakeTodo,cmakeVariable,cmakeProperty,cmakeGeneratorExpressions -syn region cmakeRegistry start=/\[/ end=/]/ - \ contained oneline contains=CONTAINED,cmakeTodo,cmakeEscaped -syn region cmakeVariableValue start=/\${/ end=/}/ - \ contained oneline contains=CONTAINED,cmakeTodo,cmakeVariable -syn region cmakeEnvironment start=/\$ENV{/ end=/}/ - \ contained oneline contains=CONTAINED,cmakeTodo -syn region cmakeString start=/"/ end=/"/ - \ contains=CONTAINED,cmakeTodo -syn region cmakeArguments start=/(/ end=/)/ - \ contains=ALLBUT,cmakeArguments,cmakeTodo - -syn case match -syn keyword cmakeProperty - \ ABSTRACT ADDITIONAL_MAKE_CLEAN_FILES ADVANCED ALIASED_TARGET ALLOW_DUPLICATE_CUSTOM_TARGETS ANDROID_ANT_ADDITIONAL_OPTIONS ANDROID_API ANDROID_API_MIN ANDROID_ARCH ANDROID_ASSETS_DIRECTORIES ANDROID_GUI ANDROID_JAR_DEPENDENCIES ANDROID_JAR_DIRECTORIES ANDROID_JAVA_SOURCE_DIR ANDROID_NATIVE_LIB_DEPENDENCIES ANDROID_NATIVE_LIB_DIRECTORIES ANDROID_PROCESS_MAX ANDROID_PROGUARD ANDROID_PROGUARD_CONFIG_PATH ANDROID_SECURE_PROPS_PATH ANDROID_SKIP_ANT_STEP ANDROID_STL_TYPE ARCHIVE_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY_DEBUG ARCHIVE_OUTPUT_DIRECTORY_RELEASE ARCHIVE_OUTPUT_NAME ARCHIVE_OUTPUT_NAME_DEBUG ARCHIVE_OUTPUT_NAME_RELEASE ATTACHED_FILES ATTACHED_FILES_ON_FAIL AUTOGEN_TARGETS_FOLDER AUTOGEN_TARGET_DEPENDS AUTOMOC AUTOMOC_MOC_OPTIONS AUTOMOC_TARGETS_FOLDER AUTORCC AUTORCC_OPTIONS AUTOUIC AUTOUIC_OPTIONS BINARY_DIR BUILD_WITH_INSTALL_RPATH BUNDLE BUNDLE_EXTENSION CACHE_VARIABLES CLEAN_NO_CUSTOM CMAKE_CONFIGURE_DEPENDS CMAKE_CXX_KNOWN_FEATURES CMAKE_C_KNOWN_FEATURES COMPATIBLE_INTERFACE_BOOL COMPATIBLE_INTERFACE_NUMBER_MAX COMPATIBLE_INTERFACE_NUMBER_MIN COMPATIBLE_INTERFACE_STRING COMPILE_DEFINITIONS COMPILE_DEFINITIONS_DEBUG COMPILE_DEFINITIONS_RELEASE COMPILE_FEATURES COMPILE_FLAGS COMPILE_OPTIONS COMPILE_PDB_NAME COMPILE_PDB_NAME_DEBUG COMPILE_PDB_NAME_RELEASE COMPILE_PDB_OUTPUT_DIRECTORY COMPILE_PDB_OUTPUT_DIRECTORY_DEBUG COMPILE_PDB_OUTPUT_DIRECTORY_RELEASE COST CPACK_DESKTOP_SHORTCUTS CPACK_NEVER_OVERWRITE CPACK_PERMANENT CPACK_STARTUP_SHORTCUTS CPACK_START_MENU_SHORTCUTS CPACK_WIX_ACL CROSSCOMPILING_EMULATOR CXX_EXTENSIONS CXX_STANDARD CXX_STANDARD_REQUIRED C_EXTENSIONS C_STANDARD C_STANDARD_REQUIRED DEBUG_CONFIGURATIONS DEBUG_POSTFIX DEFINE_SYMBOL DEFINITIONS DEPENDS DISABLED_FEATURES ECLIPSE_EXTRA_NATURES ENABLED_FEATURES ENABLED_LANGUAGES ENABLE_EXPORTS ENVIRONMENT EXCLUDE_FROM_ALL EXCLUDE_FROM_DEFAULT_BUILD EXCLUDE_FROM_DEFAULT_BUILD_DEBUG EXCLUDE_FROM_DEFAULT_BUILD_RELEASE EXPORT_NAME EXTERNAL_OBJECT EchoString FAIL_REGULAR_EXPRESSION FIND_LIBRARY_USE_LIB64_PATHS FIND_LIBRARY_USE_OPENBSD_VERSIONING FOLDER FRAMEWORK FRAMEWORK_VERSION Fortran_FORMAT Fortran_MODULE_DIRECTORY GENERATED GENERATOR_FILE_NAME GLOBAL_DEPENDS_DEBUG_MODE GLOBAL_DEPENDS_NO_CYCLES GNUtoMS HAS_CXX HEADER_FILE_ONLY HELPSTRING IMPLICIT_DEPENDS_INCLUDE_TRANSFORM IMPORTED IMPORTED_CONFIGURATIONS IMPORTED_IMPLIB IMPORTED_IMPLIB_DEBUG IMPORTED_IMPLIB_RELEASE IMPORTED_LINK_DEPENDENT_LIBRARIES IMPORTED_LINK_DEPENDENT_LIBRARIES_DEBUG IMPORTED_LINK_DEPENDENT_LIBRARIES_RELEASE IMPORTED_LINK_INTERFACE_LANGUAGES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE IMPORTED_LINK_INTERFACE_LIBRARIES IMPORTED_LINK_INTERFACE_LIBRARIES_DEBUG IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE IMPORTED_LINK_INTERFACE_MULTIPLICITY IMPORTED_LINK_INTERFACE_MULTIPLICITY_DEBUG IMPORTED_LINK_INTERFACE_MULTIPLICITY_RELEASE IMPORTED_LOCATION IMPORTED_LOCATION_DEBUG IMPORTED_LOCATION_RELEASE IMPORTED_NO_SONAME IMPORTED_NO_SONAME_DEBUG IMPORTED_NO_SONAME_RELEASE IMPORTED_SONAME IMPORTED_SONAME_DEBUG IMPORTED_SONAME_RELEASE IMPORT_PREFIX IMPORT_SUFFIX INCLUDE_DIRECTORIES INCLUDE_REGULAR_EXPRESSION INSTALL_NAME_DIR INSTALL_RPATH INSTALL_RPATH_USE_LINK_PATH INTERFACE_AUTOUIC_OPTIONS INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_FEATURES INTERFACE_COMPILE_OPTIONS INTERFACE_INCLUDE_DIRECTORIES INTERFACE_LINK_LIBRARIES INTERFACE_POSITION_INDEPENDENT_CODE INTERFACE_SOURCES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES INTERPROCEDURAL_OPTIMIZATION INTERPROCEDURAL_OPTIMIZATION_DEBUG INTERPROCEDURAL_OPTIMIZATION_RELEASE IN_TRY_COMPILE JOB_POOLS JOB_POOL_COMPILE JOB_POOL_LINK KEEP_EXTENSION LABELS LANGUAGE LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_DEBUG LIBRARY_OUTPUT_DIRECTORY_RELEASE LIBRARY_OUTPUT_NAME LIBRARY_OUTPUT_NAME_DEBUG LIBRARY_OUTPUT_NAME_RELEASE LINKER_LANGUAGE LINK_DEPENDS LINK_DEPENDS_NO_SHARED LINK_DIRECTORIES LINK_FLAGS LINK_FLAGS_DEBUG LINK_FLAGS_RELEASE LINK_INTERFACE_LIBRARIES LINK_INTERFACE_LIBRARIES_DEBUG LINK_INTERFACE_LIBRARIES_RELEASE LINK_INTERFACE_MULTIPLICITY LINK_INTERFACE_MULTIPLICITY_DEBUG LINK_INTERFACE_MULTIPLICITY_RELEASE LINK_LIBRARIES LINK_SEARCH_END_STATIC LINK_SEARCH_START_STATIC LISTFILE_STACK LOCATION LOCATION_DEBUG LOCATION_RELEASE MACOSX_BUNDLE MACOSX_BUNDLE_INFO_PLIST MACOSX_FRAMEWORK_INFO_PLIST MACOSX_PACKAGE_LOCATION MACOSX_RPATH MACROS MAP_IMPORTED_CONFIG_DEBUG MAP_IMPORTED_CONFIG_RELEASE MEASUREMENT MODIFIED NAME NO_SONAME NO_SYSTEM_FROM_IMPORTED OBJECT_DEPENDS OBJECT_OUTPUTS OSX_ARCHITECTURES OSX_ARCHITECTURES_DEBUG OSX_ARCHITECTURES_RELEASE OUTPUT_NAME OUTPUT_NAME_DEBUG OUTPUT_NAME_RELEASE PACKAGES_FOUND PACKAGES_NOT_FOUND PARENT_DIRECTORY PASS_REGULAR_EXPRESSION PDB_NAME PDB_NAME_DEBUG PDB_NAME_RELEASE PDB_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY_DEBUG PDB_OUTPUT_DIRECTORY_RELEASE POSITION_INDEPENDENT_CODE POST_INSTALL_SCRIPT PREDEFINED_TARGETS_FOLDER PREFIX PRE_INSTALL_SCRIPT PRIVATE_HEADER PROCESSORS PROJECT_LABEL PUBLIC_HEADER REPORT_UNDEFINED_PROPERTIES REQUIRED_FILES RESOURCE RESOURCE_LOCK RULE_LAUNCH_COMPILE RULE_LAUNCH_CUSTOM RULE_LAUNCH_LINK RULE_MESSAGES RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_DEBUG RUNTIME_OUTPUT_DIRECTORY_RELEASE RUNTIME_OUTPUT_NAME RUNTIME_OUTPUT_NAME_DEBUG RUNTIME_OUTPUT_NAME_RELEASE RUN_SERIAL SKIP_BUILD_RPATH SKIP_RETURN_CODE SOURCES SOURCE_DIR SOVERSION STATIC_LIBRARY_FLAGS STATIC_LIBRARY_FLAGS_DEBUG STATIC_LIBRARY_FLAGS_RELEASE STRINGS SUFFIX SYMBOLIC TARGET_ARCHIVES_MAY_BE_SHARED_LIBS TARGET_MESSAGES TARGET_SUPPORTS_SHARED_LIBS TEST_INCLUDE_FILE TIMEOUT TYPE USE_FOLDERS VALUE VARIABLES VERSION VISIBILITY_INLINES_HIDDEN VS_DEPLOYMENT_CONTENT VS_DEPLOYMENT_LOCATION VS_DESKTOP_EXTENSIONS_VERSION VS_DOTNET_REFERENCES VS_DOTNET_TARGET_FRAMEWORK_VERSION VS_GLOBAL_KEYWORD VS_GLOBAL_PROJECT_TYPES VS_GLOBAL_ROOTNAMESPACE VS_IOT_EXTENSIONS_VERSION VS_IOT_STARTUP_TASK VS_KEYWORD VS_MOBILE_EXTENSIONS_VERSION VS_SCC_AUXPATH VS_SCC_LOCALPATH VS_SCC_PROJECTNAME VS_SCC_PROVIDER VS_SHADER_ENTRYPOINT VS_SHADER_FLAGS VS_SHADER_MODEL VS_SHADER_TYPE VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION VS_WINRT_COMPONENT VS_WINRT_EXTENSIONS VS_WINRT_REFERENCES VS_XAML_TYPE WILL_FAIL WIN32_EXECUTABLE WINDOWS_EXPORT_ALL_SYMBOLS WORKING_DIRECTORY WRAP_EXCLUDE XCODE_EXPLICIT_FILE_TYPE XCODE_LAST_KNOWN_FILE_TYPE XCTEST - \ contained - -syn keyword cmakeVariable - \ _BINARY_DIR _SOURCE_DIR _VERSION _VERSION_MAJOR _VERSION_MINOR _VERSION_PATCH _VERSION_TWEAK APPLE BORLAND BUILD_SHARED_LIBS CMAKE__POSTFIX CMAKE__ARCHIVE_APPEND CMAKE__ARCHIVE_CREATE CMAKE__ARCHIVE_FINISH CMAKE__COMPILER CMAKE__COMPILER_ABI CMAKE__COMPILER_EXTERNAL_TOOLCHAIN CMAKE__COMPILER_ID CMAKE__COMPILER_LAUNCHER CMAKE__COMPILER_LOADED CMAKE__COMPILER_TARGET CMAKE__COMPILER_VERSION CMAKE__COMPILE_OBJECT CMAKE__CREATE_SHARED_LIBRARY CMAKE__CREATE_SHARED_MODULE CMAKE__CREATE_STATIC_LIBRARY CMAKE__FLAGS CMAKE__FLAGS_DEBUG CMAKE__FLAGS_MINSIZEREL CMAKE__FLAGS_RELEASE CMAKE__FLAGS_RELWITHDEBINFO CMAKE__GHS_KERNEL_FLAGS_DEBUG CMAKE__GHS_KERNEL_FLAGS_MINSIZEREL CMAKE__GHS_KERNEL_FLAGS_RELEASE CMAKE__GHS_KERNEL_FLAGS_RELWITHDEBINFO CMAKE__IGNORE_EXTENSIONS CMAKE__IMPLICIT_INCLUDE_DIRECTORIES CMAKE__IMPLICIT_LINK_DIRECTORIES CMAKE__IMPLICIT_LINK_FRAMEWORK_DIRECTORIES CMAKE__IMPLICIT_LINK_LIBRARIES CMAKE__INCLUDE_WHAT_YOU_USE CMAKE__LIBRARY_ARCHITECTURE CMAKE__LINKER_PREFERENCE CMAKE__LINKER_PREFERENCE_PROPAGATES CMAKE__LINK_EXECUTABLE CMAKE__OUTPUT_EXTENSION CMAKE__PLATFORM_ID CMAKE__SIMULATE_ID CMAKE__SIMULATE_VERSION CMAKE__SIZEOF_DATA_PTR CMAKE__SOURCE_FILE_EXTENSIONS CMAKE__VISIBILITY_PRESET CMAKE_ABSOLUTE_DESTINATION_FILES CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS CMAKE_ANDROID_API CMAKE_ANDROID_API_MIN CMAKE_ANDROID_ARCH CMAKE_ANDROID_ASSETS_DIRECTORIES CMAKE_ANDROID_GUI CMAKE_ANDROID_JAR_DEPENDENCIES CMAKE_ANDROID_JAR_DIRECTORIES CMAKE_ANDROID_JAVA_SOURCE_DIR CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES CMAKE_ANDROID_PROCESS_MAX CMAKE_ANDROID_PROGUARD CMAKE_ANDROID_PROGUARD_CONFIG_PATH CMAKE_ANDROID_SECURE_PROPS_PATH CMAKE_ANDROID_SKIP_ANT_STEP CMAKE_ANDROID_STL_TYPE CMAKE_APPBUNDLE_PATH CMAKE_AR CMAKE_ARCHIVE_OUTPUT_DIRECTORY CMAKE_ARCHIVE_OUTPUT_DIRECTORY_ CMAKE_ARGC CMAKE_ARGV0 CMAKE_AUTOMOC CMAKE_AUTOMOC_MOC_OPTIONS CMAKE_AUTOMOC_RELAXED_MODE CMAKE_AUTORCC CMAKE_AUTORCC_OPTIONS CMAKE_AUTOUIC CMAKE_AUTOUIC_OPTIONS CMAKE_BACKWARDS_COMPATIBILITY CMAKE_BINARY_DIR CMAKE_BUILD_TOOL CMAKE_BUILD_TYPE CMAKE_BUILD_WITH_INSTALL_RPATH CMAKE_CACHEFILE_DIR CMAKE_CACHE_MAJOR_VERSION CMAKE_CACHE_MINOR_VERSION CMAKE_CACHE_PATCH_VERSION CMAKE_CFG_INTDIR CMAKE_CL_64 CMAKE_COLOR_MAKEFILE CMAKE_COMMAND CMAKE_COMPILER_2005 CMAKE_COMPILER_IS_GNU CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_ CMAKE_CONFIGURATION_TYPES CMAKE_CROSSCOMPILING CMAKE_CROSSCOMPILING_EMULATOR CMAKE_CMAKE_COMMAND CMAKE_CPACK_COMMAND CMAKE_CTEST_COMMAND CMAKE_CURRENT_BINARY_DIR CMAKE_CURRENT_LIST_DIR CMAKE_CURRENT_LIST_FILE CMAKE_CURRENT_LIST_LINE CMAKE_CURRENT_SOURCE_DIR CMAKE_CXX_COMPILE_FEATURES CMAKE_CXX_EXTENSIONS CMAKE_CXX_STANDARD CMAKE_CXX_STANDARD_REQUIRED CMAKE_C_COMPILE_FEATURES CMAKE_C_EXTENSIONS CMAKE_C_STANDARD CMAKE_C_STANDARD_REQUIRED CMAKE_DEBUG_POSTFIX CMAKE_DEBUG_TARGET_PROPERTIES CMAKE_DISABLE_FIND_PACKAGE_ CMAKE_DL_LIBS CMAKE_EDIT_COMMAND CMAKE_ENABLE_EXPORTS CMAKE_ERROR_DEPRECATED CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION CMAKE_EXECUTABLE_SUFFIX CMAKE_EXE_LINKER_FLAGS CMAKE_EXE_LINKER_FLAGS_ CMAKE_EXPORT_COMPILE_COMMANDS CMAKE_EXPORT_NO_PACKAGE_REGISTRY CMAKE_EXTRA_GENERATOR CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES CMAKE_FIND_APPBUNDLE CMAKE_FIND_FRAMEWORK CMAKE_FIND_LIBRARY_PREFIXES CMAKE_FIND_LIBRARY_SUFFIXES CMAKE_FIND_NO_INSTALL_PREFIX CMAKE_FIND_PACKAGE_NAME CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY CMAKE_FIND_PACKAGE_WARN_NO_MODULE CMAKE_FIND_ROOT_PATH CMAKE_FIND_ROOT_PATH_MODE_INCLUDE CMAKE_FIND_ROOT_PATH_MODE_LIBRARY CMAKE_FIND_ROOT_PATH_MODE_PACKAGE CMAKE_FIND_ROOT_PATH_MODE_PROGRAM CMAKE_FRAMEWORK_PATH CMAKE_Fortran_FORMAT CMAKE_Fortran_MODDIR_DEFAULT CMAKE_Fortran_MODDIR_FLAG CMAKE_Fortran_MODOUT_FLAG CMAKE_Fortran_MODULE_DIRECTORY CMAKE_GENERATOR CMAKE_GENERATOR_PLATFORM CMAKE_GENERATOR_TOOLSET CMAKE_GNUtoMS CMAKE_HOME_DIRECTORY CMAKE_HOST_APPLE CMAKE_HOST_SYSTEM CMAKE_HOST_SYSTEM_NAME CMAKE_HOST_SYSTEM_PROCESSOR CMAKE_HOST_SYSTEM_VERSION CMAKE_HOST_UNIX CMAKE_HOST_WIN32 CMAKE_IGNORE_PATH CMAKE_IMPORT_LIBRARY_PREFIX CMAKE_IMPORT_LIBRARY_SUFFIX CMAKE_INCLUDE_CURRENT_DIR CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE CMAKE_INCLUDE_DIRECTORIES_BEFORE CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE CMAKE_INCLUDE_PATH CMAKE_INSTALL_DEFAULT_COMPONENT_NAME CMAKE_INSTALL_MESSAGE CMAKE_INSTALL_NAME_DIR CMAKE_INSTALL_PREFIX CMAKE_INSTALL_RPATH CMAKE_INSTALL_RPATH_USE_LINK_PATH CMAKE_INTERNAL_PLATFORM_ABI CMAKE_IOS_INSTALL_COMBINED CMAKE_JOB_POOL_COMPILE CMAKE_JOB_POOL_LINK CMAKE_LIBRARY_ARCHITECTURE CMAKE_LIBRARY_ARCHITECTURE_REGEX CMAKE_LIBRARY_OUTPUT_DIRECTORY CMAKE_LIBRARY_OUTPUT_DIRECTORY_ CMAKE_LIBRARY_PATH CMAKE_LIBRARY_PATH_FLAG CMAKE_LINK_DEF_FILE_FLAG CMAKE_LINK_DEPENDS_NO_SHARED CMAKE_LINK_INTERFACE_LIBRARIES CMAKE_LINK_LIBRARY_FILE_FLAG CMAKE_LINK_LIBRARY_FLAG CMAKE_LINK_LIBRARY_SUFFIX CMAKE_LINK_SEARCH_END_STATIC CMAKE_LINK_SEARCH_START_STATIC CMAKE_MACOSX_BUNDLE CMAKE_MACOSX_RPATH CMAKE_MAJOR_VERSION CMAKE_MAKE_PROGRAM CMAKE_MAP_IMPORTED_CONFIG_ CMAKE_MATCH_COUNT CMAKE_MFC_FLAG CMAKE_MINIMUM_REQUIRED_VERSION CMAKE_MINOR_VERSION CMAKE_MODULE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS_ CMAKE_MODULE_PATH CMAKE_NOT_USING_CONFIG_FLAGS CMAKE_NO_BUILTIN_CHRPATH CMAKE_NO_SYSTEM_FROM_IMPORTED CMAKE_OBJECT_PATH_MAX CMAKE_OSX_ARCHITECTURES CMAKE_OSX_DEPLOYMENT_TARGET CMAKE_OSX_SYSROOT CMAKE_PARENT_LIST_FILE CMAKE_PATCH_VERSION CMAKE_PDB_OUTPUT_DIRECTORY CMAKE_PDB_OUTPUT_DIRECTORY_ CMAKE_POLICY_DEFAULT_CMP CMAKE_POLICY_WARNING_CMP CMAKE_POSITION_INDEPENDENT_CODE CMAKE_PREFIX_PATH CMAKE_PROGRAM_PATH CMAKE_PROJECT__INCLUDE CMAKE_PROJECT_NAME CMAKE_RANLIB CMAKE_ROOT CMAKE_RUNTIME_OUTPUT_DIRECTORY CMAKE_RUNTIME_OUTPUT_DIRECTORY_ CMAKE_SCRIPT_MODE_FILE CMAKE_SHARED_LIBRARY_PREFIX CMAKE_SHARED_LIBRARY_SUFFIX CMAKE_SHARED_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS_ CMAKE_SHARED_MODULE_PREFIX CMAKE_SHARED_MODULE_SUFFIX CMAKE_SIZEOF_VOID_P CMAKE_SKIP_BUILD_RPATH CMAKE_SKIP_INSTALL_ALL_DEPENDENCY CMAKE_SKIP_INSTALL_RPATH CMAKE_SKIP_INSTALL_RULES CMAKE_SKIP_RPATH CMAKE_SOURCE_DIR CMAKE_STAGING_PREFIX CMAKE_STANDARD_LIBRARIES CMAKE_STATIC_LIBRARY_PREFIX CMAKE_STATIC_LIBRARY_SUFFIX CMAKE_STATIC_LINKER_FLAGS CMAKE_STATIC_LINKER_FLAGS_ CMAKE_SYSROOT CMAKE_SYSTEM CMAKE_SYSTEM_APPBUNDLE_PATH CMAKE_SYSTEM_FRAMEWORK_PATH CMAKE_SYSTEM_IGNORE_PATH CMAKE_SYSTEM_INCLUDE_PATH CMAKE_SYSTEM_LIBRARY_PATH CMAKE_SYSTEM_NAME CMAKE_SYSTEM_PREFIX_PATH CMAKE_SYSTEM_PROCESSOR CMAKE_SYSTEM_PROGRAM_PATH CMAKE_SYSTEM_VERSION CMAKE_TOOLCHAIN_FILE CMAKE_TRY_COMPILE_CONFIGURATION CMAKE_TWEAK_VERSION CMAKE_USER_MAKE_RULES_OVERRIDE CMAKE_USER_MAKE_RULES_OVERRIDE_ CMAKE_USE_RELATIVE_PATHS CMAKE_VERBOSE_MAKEFILE CMAKE_VERSION CMAKE_VISIBILITY_INLINES_HIDDEN CMAKE_VS_DEVENV_COMMAND CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD CMAKE_VS_INTEL_Fortran_PROJECT_VERSION CMAKE_VS_MSBUILD_COMMAND CMAKE_VS_MSDEV_COMMAND CMAKE_VS_NsightTegra_VERSION CMAKE_VS_PLATFORM_NAME CMAKE_VS_PLATFORM_TOOLSET CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION CMAKE_WARN_DEPRECATED CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION CMAKE_WIN32_EXECUTABLE CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS CMAKE_XCODE_ATTRIBUTE_ CMAKE_XCODE_PLATFORM_TOOLSET CPACK_ABSOLUTE_DESTINATION_FILES CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION CPACK_INCLUDE_TOPLEVEL_DIRECTORY CPACK_INSTALL_SCRIPT CPACK_PACKAGING_INSTALL_PREFIX CPACK_SET_DESTDIR CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION CTEST_BINARY_DIRECTORY CTEST_BUILD_COMMAND CTEST_BUILD_NAME CTEST_BZR_COMMAND CTEST_BZR_UPDATE_OPTIONS CTEST_CHANGE_ID CTEST_CHECKOUT_COMMAND CTEST_CONFIGURATION_TYPE CTEST_CONFIGURE_COMMAND CTEST_COVERAGE_COMMAND CTEST_COVERAGE_EXTRA_FLAGS CTEST_CURL_OPTIONS CTEST_CUSTOM_COVERAGE_EXCLUDE CTEST_CUSTOM_ERROR_EXCEPTION CTEST_CUSTOM_ERROR_MATCH CTEST_CUSTOM_ERROR_POST_CONTEXT CTEST_CUSTOM_ERROR_PRE_CONTEXT CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE CTEST_CUSTOM_MEMCHECK_IGNORE CTEST_CUSTOM_POST_MEMCHECK CTEST_CUSTOM_POST_TEST CTEST_CUSTOM_PRE_MEMCHECK CTEST_CUSTOM_PRE_TEST CTEST_CUSTOM_TEST_IGNORE CTEST_CUSTOM_WARNING_EXCEPTION CTEST_CUSTOM_WARNING_MATCH CTEST_CVS_CHECKOUT CTEST_CVS_COMMAND CTEST_CVS_UPDATE_OPTIONS CTEST_DROP_LOCATION CTEST_DROP_METHOD CTEST_DROP_SITE CTEST_DROP_SITE_CDASH CTEST_DROP_SITE_PASSWORD CTEST_DROP_SITE_USER CTEST_EXTRA_COVERAGE_GLOB CTEST_GIT_COMMAND CTEST_GIT_UPDATE_CUSTOM CTEST_GIT_UPDATE_OPTIONS CTEST_HG_COMMAND CTEST_HG_UPDATE_OPTIONS CTEST_MEMORYCHECK_COMMAND CTEST_MEMORYCHECK_COMMAND_OPTIONS CTEST_MEMORYCHECK_SANITIZER_OPTIONS CTEST_MEMORYCHECK_SUPPRESSIONS_FILE CTEST_MEMORYCHECK_TYPE CTEST_NIGHTLY_START_TIME CTEST_P4_CLIENT CTEST_P4_COMMAND CTEST_P4_OPTIONS CTEST_P4_UPDATE_OPTIONS CTEST_SCP_COMMAND CTEST_SITE CTEST_SOURCE_DIRECTORY CTEST_SVN_COMMAND CTEST_SVN_OPTIONS CTEST_SVN_UPDATE_OPTIONS CTEST_TEST_LOAD CTEST_TEST_TIMEOUT CTEST_TRIGGER_SITE CTEST_UPDATE_COMMAND CTEST_UPDATE_OPTIONS CTEST_UPDATE_VERSION_ONLY CTEST_USE_LAUNCHERS CYGWIN ENV EXECUTABLE_OUTPUT_PATH GHS-MULTI LIBRARY_OUTPUT_PATH MINGW MSVC MSVC10 MSVC11 MSVC12 MSVC14 MSVC60 MSVC70 MSVC71 MSVC80 MSVC90 MSVC_IDE MSVC_VERSION PROJECT_BINARY_DIR PROJECT_NAME PROJECT_SOURCE_DIR PROJECT_VERSION PROJECT_VERSION_MAJOR PROJECT_VERSION_MINOR PROJECT_VERSION_PATCH PROJECT_VERSION_TWEAK UNIX WIN32 WINCE WINDOWS_PHONE WINDOWS_STORE XCODE_VERSION - \ contained - -syn keyword cmakeModule - \ ExternalProject - \ contained - -syn keyword cmakeKWExternalProject - \ ALGO ALWAYS BINARY_DIR BUILD_ALWAYS BUILD_BYPRODUCTS BUILD_COMMAND BUILD_IN_SOURCE BYPRODUCTS CMAKE_ARGS CMAKE_CACHE_ARGS CMAKE_CACHE_DEFAULT_ARGS COMMAND COMMENT CONFIGURE_COMMAND CVS CVSROOT CVS_ CVS_MODULE CVS_REPOSITORY CVS_TAG DEPENDEES DEPENDERS DEPENDS DIRECTORY DOWNLOAD_COMMAND DOWNLOAD_DIR DOWNLOAD_NAME DOWNLOAD_NO_PROGRESS EP_BASE EP_INDEPENDENT_STEP_TARGETS EP_PREFIX EP_STEP_TARGETS EP_UPDATE_DISCONNECTED EXCLUDE_FROM_ALL EXCLUDE_FROM_MAIN FORCE GIT_REMOTE_NAME GIT_REPOSITORY GIT_SUBMODULES GIT_TAG HG_REPOSITORY HG_TAG INDEPENDENT INDEPENDENT_STEP_TARGETS INSTALL_COMMAND INSTALL_DIR JOB_POOLS LIST_SEPARATOR LOG LOG_BUILD LOG_CONFIGURE LOG_DOWNLOAD LOG_INSTALL LOG_TEST LOG_UPDATE NO_DEPENDS PATCH_COMMAND PREFIX PROPERTY SOURCE_DIR STAMP_DIR STEP_TARGETS SVN_ SVN_PASSWORD SVN_REPOSITORY SVN_REVISION SVN_TRUST_CERT SVN_USERNAME TEST_AFTER_INSTALL TEST_BEFORE_INSTALL TEST_COMMAND TEST_EXCLUDE_FROM_MAIN TIMEOUT TLS_CAINFO TLS_VERIFY TMP_DIR UPDATE_COMMAND UPDATE_DISCONNECTED URL URL_HASH USES_TERMINAL USES_TERMINAL_BUILD USES_TERMINAL_CONFIGURE USES_TERMINAL_DOWNLOAD USES_TERMINAL_INSTALL USES_TERMINAL_TEST USES_TERMINAL_UPDATE WORKING_DIRECTORY _COMMAND _DIR - \ contained - -syn keyword cmakeKWadd_compile_options - \ COMPILE_OPTIONS - \ contained - -syn keyword cmakeKWadd_custom_command - \ APPEND ARGS BYPRODUCTS COMMAND COMMENT DEPENDS GENERATE GENERATED IMPLICIT_DEPENDS MAIN_DEPENDENCY NOT OUTPUT POST_BUILD PRE_BUILD PRE_LINK SYMBOLIC TARGET TARGET_FILE USES_TERMINAL VERBATIM WORKING_DIRECTORY - \ contained - -syn keyword cmakeKWadd_custom_target - \ ALL BYPRODUCTS COMMAND COMMENT DEPENDS GENERATE GENERATED SOURCES USES_TERMINAL VERBATIM WORKING_DIRECTORY - \ contained - -syn keyword cmakeKWadd_definitions - \ COMPILE_DEFINITIONS DBAR DFOO - \ contained - -syn keyword cmakeKWadd_dependencies - \ DEPENDS OBJECT_DEPENDS - \ contained - -syn keyword cmakeKWadd_executable - \ ALIAS CONFIG EXCLUDE_FROM_ALL GLOBAL IMPORTED IMPORTED_ IMPORTED_LOCATION IMPORTED_LOCATION_ MACOSX_BUNDLE OUTPUT_NAME RUNTIME_OUTPUT_DIRECTORY TARGET - \ contained - -syn keyword cmakeKWadd_library - \ ALIAS ARCHIVE_OUTPUT_DIRECTORY CLI CONFIG DLL EXCLUDE_FROM_ALL FRAMEWORK GLOBAL IMPORTED IMPORTED_ IMPORTED_LOCATION IMPORTED_LOCATION_ INTERFACE INTERFACE_ LIBRARY_OUTPUT_DIRECTORY MODULE OBJECT ON OS OUTPUT_NAME POSITION_INDEPENDENT_CODE POST_BUILD PRE_BUILD PRE_LINK RUNTIME_OUTPUT_DIRECTORY SHARED STATIC TARGET TARGET_OBJECTS UNKNOWN - \ contained - -syn keyword cmakeKWadd_subdirectory - \ ALL EXCLUDE_FROM_ALL - \ contained - -syn keyword cmakeKWadd_test - \ BUILD_TESTING COMMAND CONFIGURATION CONFIGURATIONS FAIL_REGULAR_EXPRESSION NAME ON PASS_REGULAR_EXPRESSION TARGET_FILE WILL_FAIL WORKING_DIRECTORY - \ contained - -syn keyword cmakeKWbuild_command - \ CONFIGURATION NEW TARGET - \ contained - -syn keyword cmakeKWbuild_name - \ CMAKE_CXX_COMPILER - \ contained - -syn keyword cmakeKWcmake_host_system_information - \ AVAILABLE_PHYSICAL_MEMORY AVAILABLE_VIRTUAL_MEMORY FQDN HOSTNAME NUMBER_OF_LOGICAL_CORES NUMBER_OF_PHYSICAL_CORES QUERY RESULT TOTAL_PHYSICAL_MEMORY TOTAL_VIRTUAL_MEMORY - \ contained - -syn keyword cmakeKWcmake_minimum_required - \ FATAL_ERROR VERSION - \ contained - -syn keyword cmakeKWcmake_parse_arguments - \ ARGN CONFIGURATIONS DESTINATION FALSE FAST FILES MY_INSTALL MY_INSTALL_CONFIGURATIONS MY_INSTALL_DESTINATION MY_INSTALL_FAST MY_INSTALL_OPTIONAL MY_INSTALL_RENAME MY_INSTALL_TARGETS MY_INSTALL_UNPARSED_ARGUMENTS OPTIONAL RENAME TARGETS TRUE _UNPARSED_ARGUMENTS - \ contained - -syn keyword cmakeKWcmake_policy - \ CMAKE_POLICY_DEFAULT_CMP CMP GET NEW NNNN NO_POLICY_SCOPE OLD POP PUSH SET VERSION - \ contained - -syn keyword cmakeKWconfigure_file - \ COPYONLY CRLF DOS ESCAPE_QUOTES FOO_ENABLE FOO_STRING LF NEWLINE_STYLE ON ONLY VAR - \ contained - -syn keyword cmakeKWcreate_test_sourcelist - \ CMAKE_TESTDRIVER_AFTER_TESTMAIN CMAKE_TESTDRIVER_BEFORE_TESTMAIN EXTRA_INCLUDE FUNCTION - \ contained - -syn keyword cmakeKWctest_build - \ ALL_BUILD APPEND BUILD CONFIGURATION CTEST_BUILD_CONFIGURATION CTEST_BUILD_FLAGS CTEST_BUILD_TARGET CTEST_PROJECT_NAME FLAGS NUMBER_ERRORS NUMBER_WARNINGS QUIET RETURN_VALUE TARGET - \ contained - -syn keyword cmakeKWctest_configure - \ APPEND BUILD OPTIONS QUIET RETURN_VALUE SOURCE - \ contained - -syn keyword cmakeKWctest_coverage - \ APPEND BUILD LABELS QUIET RETURN_VALUE - \ contained - -syn keyword cmakeKWctest_memcheck - \ APPEND BUILD END EXCLUDE EXCLUDE_LABEL INCLUDE INCLUDE_LABEL OFF ON PARALLEL_LEVEL QUIET RETURN_VALUE SCHEDULE_RANDOM START STOP_TIME STRIDE TEST_LOAD - \ contained - -syn keyword cmakeKWctest_run_script - \ NEW_PROCESS RETURN_VALUE - \ contained - -syn keyword cmakeKWctest_start - \ APPEND QUIET TAG TRACK - \ contained - -syn keyword cmakeKWctest_submit - \ API CDASH_UPLOAD CDASH_UPLOAD_TYPE CTEST_EXTRA_SUBMIT_FILES CTEST_NOTES_FILES FILES PARTS QUIET RETRY_COUNT RETRY_DELAY RETURN_VALUE - \ contained - -syn keyword cmakeKWctest_test - \ APPEND BUILD CPU END EXCLUDE EXCLUDE_LABEL INCLUDE INCLUDE_LABEL OFF ON PARALLEL_LEVEL QUIET RETURN_VALUE SCHEDULE_RANDOM START STOP_TIME STRIDE TEST_LOAD - \ contained - -syn keyword cmakeKWctest_update - \ QUIET RETURN_VALUE SOURCE - \ contained - -syn keyword cmakeKWctest_upload - \ FILES QUIET - \ contained - -syn keyword cmakeKWdefine_property - \ BRIEF_DOCS CACHED_VARIABLE DIRECTORY FULL_DOCS GLOBAL INHERITED PROPERTY SOURCE TARGET TEST VARIABLE - \ contained - -syn keyword cmakeKWenable_language - \ OPTIONAL - \ contained - -syn keyword cmakeKWexec_program - \ ARGS OUTPUT_VARIABLE RETURN_VALUE - \ contained - -syn keyword cmakeKWexecute_process - \ COMMAND ERROR_ ERROR_FILE ERROR_QUIET ERROR_STRIP_TRAILING_WHITESPACE ERROR_VARIABLE INPUT_ INPUT_FILE OUTPUT_ OUTPUT_FILE OUTPUT_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE RESULT_VARIABLE TIMEOUT VERBATIM WORKING_DIRECTORY - \ contained - -syn keyword cmakeKWexport - \ APPEND CONFIG EXPORT EXPORT_LINK_INTERFACE_LIBRARIES FILE IMPORTED IMPORTED_ LINK_INTERFACE_LIBRARIES NAMESPACE NEW PACKAGE TARGETS - \ contained - -syn keyword cmakeKWexport_library_dependencies - \ APPEND EXPORT INCLUDE LINK_INTERFACE_LIBRARIES SET - \ contained - -syn keyword cmakeKWfile - \ ALGO APPEND ASCII CMAKE_TLS_CAINFO CMAKE_TLS_VERIFY CONDITION CONFIG CONTENT COPY CR DESTINATION DIRECTORY DIRECTORY_PERMISSIONS DOWNLOAD ENCODING EXCLUDE EXPECTED_HASH FILE FILES_MATCHING FILE_PERMISSIONS FOLLOW_SYMLINKS FUNCTION GENERATE GLOB GLOB_RECURSE GUARD HEX INACTIVITY_TIMEOUT INPUT INSTALL LENGTH_MAXIMUM LENGTH_MINIMUM LF LIMIT LIMIT_COUNT LIMIT_INPUT LIMIT_OUTPUT LIST_DIRECTORIES LOCK LOG MAKE_DIRECTORY NEW NEWLINE_CONSUME NO_HEX_CONVERSION NO_SOURCE_PERMISSIONS OFF OFFSET OLD ON OUTPUT PATH PATTERN PERMISSIONS PROCESS READ REGEX RELATIVE RELATIVE_PATH RELEASE REMOVE REMOVE_RECURSE RENAME RESULT_VARIABLE SHOW_PROGRESS SORT SSL STATUS STRINGS TIMEOUT TIMESTAMP TLS TLS_CAINFO TLS_VERIFY TO_CMAKE_PATH TO_NATIVE_PATH UPLOAD USE_SOURCE_PERMISSIONS UTC UTF WRITE - \ contained - -syn keyword cmakeKWfind_file - \ CMAKE_FIND_ROOT_PATH_BOTH DOC DVAR HINTS INCLUDE NAMES NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_FIND_ROOT_PATH NO_CMAKE_PATH NO_CMAKE_SYSTEM_PATH NO_DEFAULT_PATH NO_SYSTEM_ENVIRONMENT_PATH ONLY_CMAKE_FIND_ROOT_PATH OS PATH PATHS PATH_SUFFIXES VAR - \ contained - -syn keyword cmakeKWfind_library - \ CMAKE_FIND_ROOT_PATH_BOTH DOC DVAR HINTS LIB NAMES NAMES_PER_DIR NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_FIND_ROOT_PATH NO_CMAKE_PATH NO_CMAKE_SYSTEM_PATH NO_DEFAULT_PATH NO_SYSTEM_ENVIRONMENT_PATH ONLY_CMAKE_FIND_ROOT_PATH OS PATH PATHS PATH_SUFFIXES VAR - \ contained - -syn keyword cmakeKWfind_package - \ CMAKE_DISABLE_FIND_PACKAGE_ CMAKE_FIND_ROOT_PATH_BOTH COMPONENTS CONFIG CONFIGS DVAR EXACT HINTS MODULE NAMES NO_CMAKE_BUILDS_PATH NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_FIND_ROOT_PATH NO_CMAKE_PACKAGE_REGISTRY NO_CMAKE_PATH NO_CMAKE_SYSTEM_PACKAGE_REGISTRY NO_CMAKE_SYSTEM_PATH NO_DEFAULT_PATH NO_MODULE NO_POLICY_SCOPE NO_SYSTEM_ENVIRONMENT_PATH ONLY_CMAKE_FIND_ROOT_PATH OPTIONAL_COMPONENTS OS PACKAGE_FIND_NAME PACKAGE_FIND_VERSION PACKAGE_FIND_VERSION_COUNT PACKAGE_FIND_VERSION_MAJOR PACKAGE_FIND_VERSION_MINOR PACKAGE_FIND_VERSION_PATCH PACKAGE_FIND_VERSION_TWEAK PACKAGE_VERSION PACKAGE_VERSION_COMPATIBLE PACKAGE_VERSION_EXACT PACKAGE_VERSION_UNSUITABLE PATH PATHS PATH_SUFFIXES QUIET REQUIRED TRUE _CONFIG _CONSIDERED_CONFIGS _CONSIDERED_VERSIONS _DIR _FIND_COMPONENTS _FIND_QUIETLY _FIND_REQUIRED _FIND_REQUIRED_ _FIND_VERSION _FIND_VERSION_COUNT _FIND_VERSION_EXACT _FIND_VERSION_MAJOR _FIND_VERSION_MINOR _FIND_VERSION_PATCH _FIND_VERSION_TWEAK _FOUND _VERSION _VERSION_COUNT _VERSION_MAJOR _VERSION_MINOR _VERSION_PATCH _VERSION_TWEAK - \ contained - -syn keyword cmakeKWfind_path - \ CMAKE_FIND_ROOT_PATH_BOTH DOC DVAR HINTS INCLUDE NAMES NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_FIND_ROOT_PATH NO_CMAKE_PATH NO_CMAKE_SYSTEM_PATH NO_DEFAULT_PATH NO_SYSTEM_ENVIRONMENT_PATH ONLY_CMAKE_FIND_ROOT_PATH OS PATH PATHS PATH_SUFFIXES VAR - \ contained - -syn keyword cmakeKWfind_program - \ CMAKE_FIND_ROOT_PATH_BOTH DOC DVAR HINTS NAMES NAMES_PER_DIR NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_FIND_ROOT_PATH NO_CMAKE_PATH NO_CMAKE_SYSTEM_PATH NO_DEFAULT_PATH NO_SYSTEM_ENVIRONMENT_PATH ONLY_CMAKE_FIND_ROOT_PATH OS PATH PATHS PATH_SUFFIXES VAR - \ contained - -syn keyword cmakeKWfltk_wrap_ui - \ FLTK - \ contained - -syn keyword cmakeKWforeach - \ ARGS IN ITEMS LISTS RANGE - \ contained - -syn keyword cmakeKWfunction - \ ARGC ARGN ARGS ARGV PARENT_SCOPE - \ contained - -syn keyword cmakeKWget_cmake_property - \ VAR - \ contained - -syn keyword cmakeKWget_directory_property - \ DEFINITION DIRECTORY - \ contained - -syn keyword cmakeKWget_filename_component - \ ABSOLUTE ARG_VAR BASE_DIR CACHE COMP DIRECTORY EXT NAME NAME_WE PATH PROGRAM PROGRAM_ARGS REALPATH VAR - \ contained - -syn keyword cmakeKWget_property - \ BRIEF_DOCS CACHE DEFINED DIRECTORY FULL_DOCS GLOBAL INSTALL PROPERTY SET SOURCE TARGET TEST VARIABLE - \ contained - -syn keyword cmakeKWget_source_file_property - \ LOCATION VAR - \ contained - -syn keyword cmakeKWget_target_property - \ VAR - \ contained - -syn keyword cmakeKWget_test_property - \ VAR - \ contained - -syn keyword cmakeKWif - \ AND ARGS CMP COMMAND DEFINED EQUAL EXISTS FALSE GREATER IGNORE IN_LIST IS_ABSOLUTE IS_DIRECTORY IS_NEWER_THAN IS_SYMLINK LESS MATCHES NNNN NO NOT OFF ON OR POLICY STREQUAL STRGREATER STRLESS TARGET TEST THEN TRUE VERSION_EQUAL VERSION_GREATER VERSION_LESS YES - \ contained - -syn keyword cmakeKWinclude - \ NO_POLICY_SCOPE OPTIONAL RESULT_VARIABLE VAR - \ contained - -syn keyword cmakeKWinclude_directories - \ AFTER BEFORE INCLUDE_DIRECTORIES ON SYSTEM - \ contained - -syn keyword cmakeKWinclude_external_msproject - \ GUID PLATFORM TYPE WIX - \ contained - -syn keyword cmakeKWinstall - \ ARCHIVE BUNDLE CODE COMPONENT CONFIG CONFIGURATIONS CVS DESTDIR DESTINATION DIRECTORY DIRECTORY_PERMISSIONS DLL EXCLUDE EXCLUDE_FROM_ALL EXPORT EXPORT_LINK_INTERFACE_LIBRARIES FILE FILES FILES_MATCHING FILE_PERMISSIONS FRAMEWORK GROUP_EXECUTE GROUP_READ GROUP_WRITE IMPORTED_ INCLUDES INSTALL_PREFIX INTERFACE_INCLUDE_DIRECTORIES LIBRARY LINK_INTERFACE_LIBRARIES MACOSX_BUNDLE MESSAGE MESSAGE_NEVER NAMELINK_ONLY NAMELINK_SKIP NAMESPACE NEW OPTIONAL OS OWNER_EXECUTE OWNER_READ OWNER_WRITE PATTERN PERMISSIONS POST_INSTALL_SCRIPT PRE_INSTALL_SCRIPT PRIVATE_HEADER PROGRAMS PUBLIC_HEADER REGEX RENAME RESOURCE RUNTIME SCRIPT SETGID SETUID SOVERSION TARGETS TRUE USE_SOURCE_PERMISSIONS VERSION WORLD_EXECUTE WORLD_READ WORLD_WRITE - \ contained - -syn keyword cmakeKWinstall_files - \ FILES GLOB - \ contained - -syn keyword cmakeKWinstall_programs - \ FILES GLOB PROGRAMS TARGETS - \ contained - -syn keyword cmakeKWinstall_targets - \ DLL RUNTIME_DIRECTORY TARGETS - \ contained - -syn keyword cmakeKWlist - \ APPEND CACHE FIND GET INSERT INTERNAL LENGTH LIST NOTES PARENT_SCOPE REMOVE_AT REMOVE_DUPLICATES REMOVE_ITEM REVERSE SORT - \ contained - -syn keyword cmakeKWload_cache - \ EXCLUDE INCLUDE_INTERNALS READ_WITH_PREFIX - \ contained - -syn keyword cmakeKWload_command - \ CMAKE_LOADED_COMMAND_ COMMAND_NAME - \ contained - -syn keyword cmakeKWmacro - \ ARGC ARGN ARGS ARGV DEFINED GREATER IN LISTS NOT _BAR _FOO - \ contained - -syn keyword cmakeKWmake_directory - \ MAKE_DIRECTORY - \ contained - -syn keyword cmakeKWmark_as_advanced - \ CLEAR FORCE VAR - \ contained - -syn keyword cmakeKWmath - \ EXPR - \ contained - -syn keyword cmakeKWmessage - \ AUTHOR_WARNING DEPRECATION FATAL_ERROR GUI SEND_ERROR STATUS WARNING - \ contained - -syn keyword cmakeKWoption - \ OFF ON - \ contained - -syn keyword cmakeKWproject - \ CMAKE_PROJECT_ LANGUAGES NAME NEW NONE PROJECT VERSION _BINARY_DIR _INCLUDE _SOURCE_DIR _VERSION _VERSION_MAJOR _VERSION_MINOR _VERSION_PATCH _VERSION_TWEAK - \ contained - -syn keyword cmakeKWremove - \ REMOVE_ITEM VALUE VAR - \ contained - -syn keyword cmakeKWremove_definitions - \ DBAR DFOO - \ contained - -syn keyword cmakeKWseparate_arguments - \ MSDN UNIX_COMMAND VARIABLE WINDOWS WINDOWS_COMMAND _COMMAND - \ contained - -syn keyword cmakeKWset - \ BOOL CACHE FILEPATH FORCE INTERNAL OFF ON PARENT_SCOPE PATH STRING STRINGS - \ contained - -syn keyword cmakeKWset_directory_properties - \ PROPERTIES - \ contained - -syn keyword cmakeKWset_property - \ APPEND APPEND_STRING CACHE DIRECTORY GLOBAL INSTALL PROPERTY SOURCE TARGET TEST WIX - \ contained - -syn keyword cmakeKWset_source_files_properties - \ PROPERTIES - \ contained - -syn keyword cmakeKWset_target_properties - \ PROPERTIES - \ contained - -syn keyword cmakeKWset_tests_properties - \ PROPERTIES - \ contained - -syn keyword cmakeKWsource_group - \ FILES REGULAR_EXPRESSION - \ contained - -syn keyword cmakeKWstring - \ ALPHABET APPEND ASCII CMAKE_MATCH_ COMPARE CONCAT CONFIGURE EQUAL ESCAPE_QUOTES FIND GENEX_STRIP GREATER GUID LENGTH LESS MAKE_C_IDENTIFIER MATCH MATCHALL MATCHES NAME NAMESPACE NOTEQUAL ONLY RANDOM RANDOM_SEED REGEX REPLACE REVERSE STRIP SUBSTRING SZ TIMESTAMP TOLOWER TOUPPER TYPE UPPER UTC UUID - \ contained - -syn keyword cmakeKWsubdirs - \ EXCLUDE_FROM_ALL PREORDER - \ contained - -syn keyword cmakeKWtarget_compile_definitions - \ COMPILE_DEFINITIONS INTERFACE INTERFACE_COMPILE_DEFINITIONS PRIVATE PUBLIC - \ contained - -syn keyword cmakeKWtarget_compile_features - \ COMPILE_FEATURES IMPORTED INTERFACE INTERFACE_COMPILE_FEATURES PRIVATE PUBLIC - \ contained - -syn keyword cmakeKWtarget_compile_options - \ BEFORE COMPILE_OPTIONS IMPORTED INTERFACE INTERFACE_COMPILE_OPTIONS PRIVATE PUBLIC - \ contained - -syn keyword cmakeKWtarget_include_directories - \ BEFORE BUILD_INTERFACE IMPORTED INCLUDE_DIRECTORIES INSTALL_INTERFACE INTERFACE INTERFACE_INCLUDE_DIRECTORIES INTERFACE_LINK_LIBRARIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES PRIVATE PUBLIC SYSTEM - \ contained - -syn keyword cmakeKWtarget_link_libraries - \ ALIAS DAG DEBUG_CONFIGURATIONS IMPORTED IMPORTED_NO_SONAME INTERFACE INTERFACE_LINK_LIBRARIES LINK_INTERFACE_LIBRARIES LINK_INTERFACE_LIBRARIES_DEBUG LINK_INTERFACE_MULTIPLICITY LINK_PRIVATE LINK_PUBLIC NEW OLD OSX PRIVATE PUBLIC SONAME STATIC - \ contained - -syn keyword cmakeKWtarget_sources - \ IMPORTED INTERFACE INTERFACE_SOURCES PRIVATE PUBLIC SOURCES - \ contained - -syn keyword cmakeKWtry_compile - \ ALL_BUILD CMAKE_FLAGS COMPILE_DEFINITIONS COPY_FILE COPY_FILE_ERROR DEFINED DLINK_LIBRARIES DVAR FALSE INCLUDE_DIRECTORIES LINK_DIRECTORIES LINK_LIBRARIES NEW NOT OUTPUT_VARIABLE RESULT_VAR SOURCES TRUE TYPE VALUE - \ contained - -syn keyword cmakeKWtry_run - \ ARGS CMAKE_FLAGS COMPILE_DEFINITIONS COMPILE_OUTPUT_VARIABLE COMPILE_RESULT_VAR DLINK_LIBRARIES DVAR FAILED_TO_RUN FALSE INCLUDE_DIRECTORIES LINK_DIRECTORIES LINK_LIBRARIES OUTPUT_VARIABLE RUN_OUTPUT_VARIABLE RUN_RESULT_VAR TRUE TYPE VALUE __TRYRUN_OUTPUT - \ contained - -syn keyword cmakeKWunset - \ CACHE LD_LIBRARY_PATH PARENT_SCOPE - \ contained - -syn keyword cmakeKWuse_mangled_mesa - \ GL OUTPUT_DIRECTORY PATH_TO_MESA - \ contained - -syn keyword cmakeKWvariable_requires - \ RESULT_VARIABLE TEST_VARIABLE - \ contained - -syn keyword cmakeKWvariable_watch - \ COMMAND - \ contained - -syn keyword cmakeKWwhile - \ ARGS - \ contained - -syn keyword cmakeKWwrite_file - \ APPEND CONFIGURE_FILE NOTE WRITE - \ contained - - -syn keyword cmakeGeneratorExpressions - \ LINK_LIBRARIES INCLUDE_DIRECTORIES COMPILE_DEFINITIONS CONFIG DEBUG_MODE DEBUG_MODE BOOL AND OR NOT STREQUAL STREQUAL EQUAL EQUAL CONFIG MAP_IMPORTED_CONFIG_ CONFIG IMPORTED PLATFORM_ID C_COMPILER_ID CXX_COMPILER_ID VERSION_GREATER VERSION_LESS VERSION_EQUAL C_COMPILER_VERSION CXX_COMPILER_VERSION TARGET_POLICY NEW COMPILE_FEATURES C_STANDARD CXX_STANDARD COMPILE_LANGUAGE PRIVATE COMPILE_LANGUAGE PUBLIC PRIVATE COMPILE_LANGUAGE COMPILING_CXX PRIVATE COMPILE_LANGUAGE CXX_COMPILER_ID GNU VERSION_LESS CXX_COMPILER_VERSION OLD_COMPILER OLD_COMPILER CMAKE_CXX_COMPILER_VERSION CONFIGURATION CONFIG CONFIG PLATFORM_ID C_COMPILER_ID CMAKE_ LANG _COMPILER_ID CXX_COMPILER_ID CMAKE_ LANG _COMPILER_ID C_COMPILER_VERSION CMAKE_ LANG _COMPILER_VERSION CXX_COMPILER_VERSION CMAKE_ LANG _COMPILER_VERSION TARGET_FILE TARGET_FILE_NAME TARGET_FILE_DIR TARGET_LINKER_FILE TARGET_LINKER_FILE_NAME TARGET_LINKER_FILE_DIR TARGET_SONAME_FILE TARGET_SONAME_FILE_NAME TARGET_SONAME_FILE_DIR TARGET_PDB_FILE PDB_NAME PDB_OUTPUT_DIRECTORY PDB_NAME_ CONFIG PDB_OUTPUT_DIRECTORY_ CONFIG TARGET_PDB_FILE_NAME TARGET_PDB_FILE_DIR TARGET_PROPERTY TARGET_PROPERTY INSTALL_PREFIX EXPORT COMPILE_LANGUAGE JOIN TARGET_PROPERTY INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES BOOL JOIN TARGET_PROPERTY INCLUDE_DIRECTORIES JOIN ANGLE COMMA SEMICOLON TARGET_NAME LINK_ONLY INTERFACE_LINK_LIBRARIES INSTALL_INTERFACE EXPORT BUILD_INTERFACE LOWER_CASE UPPER_CASE MAKE_C_IDENTIFIER TARGET_OBJECTS OBJECT_LIBRARY SHELL_PATH MSYS - \ contained - -syn case ignore -syn keyword cmakeCommand - \ add_compile_options add_custom_command add_custom_target add_definitions add_dependencies add_executable add_library add_subdirectory add_test aux_source_directory break build_command cmake_host_system_information cmake_minimum_required cmake_parse_arguments cmake_policy configure_file continue create_test_sourcelist ctest_build ctest_configure ctest_coverage ctest_empty_binary_directory ctest_memcheck ctest_read_custom_files ctest_run_script ctest_sleep ctest_start ctest_submit ctest_test ctest_update ctest_upload define_property enable_language enable_testing endfunction endmacro execute_process export file find_file find_library find_package find_path find_program fltk_wrap_ui function get_cmake_property get_directory_property get_filename_component get_property get_source_file_property get_target_property get_test_property include include_directories include_external_msproject include_regular_expression install link_directories list load_cache load_command macro mark_as_advanced math message option project qt_wrap_cpp qt_wrap_ui remove_definitions return separate_arguments set set_directory_properties set_property set_source_files_properties set_target_properties set_tests_properties site_name source_group string target_compile_definitions target_compile_features target_compile_options target_include_directories target_link_libraries target_sources try_compile try_run unset variable_watch - \ nextgroup=cmakeArguments -syn keyword cmakeCommandConditional - \ else elseif endif if - \ nextgroup=cmakeArguments -syn keyword cmakeCommandRepeat - \ endforeach endwhile foreach while - \ nextgroup=cmakeArguments -syn keyword cmakeCommandDeprecated - \ build_name exec_program export_library_dependencies install_files install_programs install_targets link_libraries make_directory output_required_files remove subdir_depends subdirs use_mangled_mesa utility_source variable_requires write_file - \ nextgroup=cmakeArguments -syn case match - -syn keyword cmakeTodo - \ TODO FIXME XXX - \ contained - -hi def link cmakeCommand Function -hi def link cmakeCommandConditional Conditional -hi def link cmakeCommandDeprecated WarningMsg -hi def link cmakeCommandRepeat Repeat -hi def link cmakeComment Comment -hi def link cmakeEnvironment Special -hi def link cmakeEscaped Special -hi def link cmakeGeneratorExpression WarningMsg -hi def link cmakeGeneratorExpressions Keyword -hi def link cmakeLuaComment Comment -hi def link cmakeModule Include -hi def link cmakeProperty Constant -hi def link cmakeRegistry Underlined -hi def link cmakeString String -hi def link cmakeTodo TODO -hi def link cmakeVariable Identifier -hi def link cmakeVariableValue Type - -hi def link cmakeKWExternalProject ModeMsg -hi def link cmakeKWadd_compile_options ModeMsg -hi def link cmakeKWadd_custom_command ModeMsg -hi def link cmakeKWadd_custom_target ModeMsg -hi def link cmakeKWadd_definitions ModeMsg -hi def link cmakeKWadd_dependencies ModeMsg -hi def link cmakeKWadd_executable ModeMsg -hi def link cmakeKWadd_library ModeMsg -hi def link cmakeKWadd_subdirectory ModeMsg -hi def link cmakeKWadd_test ModeMsg -hi def link cmakeKWbuild_command ModeMsg -hi def link cmakeKWbuild_name ModeMsg -hi def link cmakeKWcmake_host_system_information ModeMsg -hi def link cmakeKWcmake_minimum_required ModeMsg -hi def link cmakeKWcmake_parse_arguments ModeMsg -hi def link cmakeKWcmake_policy ModeMsg -hi def link cmakeKWconfigure_file ModeMsg -hi def link cmakeKWcreate_test_sourcelist ModeMsg -hi def link cmakeKWctest_build ModeMsg -hi def link cmakeKWctest_configure ModeMsg -hi def link cmakeKWctest_coverage ModeMsg -hi def link cmakeKWctest_memcheck ModeMsg -hi def link cmakeKWctest_run_script ModeMsg -hi def link cmakeKWctest_start ModeMsg -hi def link cmakeKWctest_submit ModeMsg -hi def link cmakeKWctest_test ModeMsg -hi def link cmakeKWctest_update ModeMsg -hi def link cmakeKWctest_upload ModeMsg -hi def link cmakeKWdefine_property ModeMsg -hi def link cmakeKWenable_language ModeMsg -hi def link cmakeKWexec_program ModeMsg -hi def link cmakeKWexecute_process ModeMsg -hi def link cmakeKWexport ModeMsg -hi def link cmakeKWexport_library_dependencies ModeMsg -hi def link cmakeKWfile ModeMsg -hi def link cmakeKWfind_file ModeMsg -hi def link cmakeKWfind_library ModeMsg -hi def link cmakeKWfind_package ModeMsg -hi def link cmakeKWfind_path ModeMsg -hi def link cmakeKWfind_program ModeMsg -hi def link cmakeKWfltk_wrap_ui ModeMsg -hi def link cmakeKWforeach ModeMsg -hi def link cmakeKWfunction ModeMsg -hi def link cmakeKWget_cmake_property ModeMsg -hi def link cmakeKWget_directory_property ModeMsg -hi def link cmakeKWget_filename_component ModeMsg -hi def link cmakeKWget_property ModeMsg -hi def link cmakeKWget_source_file_property ModeMsg -hi def link cmakeKWget_target_property ModeMsg -hi def link cmakeKWget_test_property ModeMsg -hi def link cmakeKWif ModeMsg -hi def link cmakeKWinclude ModeMsg -hi def link cmakeKWinclude_directories ModeMsg -hi def link cmakeKWinclude_external_msproject ModeMsg -hi def link cmakeKWinstall ModeMsg -hi def link cmakeKWinstall_files ModeMsg -hi def link cmakeKWinstall_programs ModeMsg -hi def link cmakeKWinstall_targets ModeMsg -hi def link cmakeKWlist ModeMsg -hi def link cmakeKWload_cache ModeMsg -hi def link cmakeKWload_command ModeMsg -hi def link cmakeKWmacro ModeMsg -hi def link cmakeKWmake_directory ModeMsg -hi def link cmakeKWmark_as_advanced ModeMsg -hi def link cmakeKWmath ModeMsg -hi def link cmakeKWmessage ModeMsg -hi def link cmakeKWoption ModeMsg -hi def link cmakeKWproject ModeMsg -hi def link cmakeKWremove ModeMsg -hi def link cmakeKWremove_definitions ModeMsg -hi def link cmakeKWseparate_arguments ModeMsg -hi def link cmakeKWset ModeMsg -hi def link cmakeKWset_directory_properties ModeMsg -hi def link cmakeKWset_property ModeMsg -hi def link cmakeKWset_source_files_properties ModeMsg -hi def link cmakeKWset_target_properties ModeMsg -hi def link cmakeKWset_tests_properties ModeMsg -hi def link cmakeKWsource_group ModeMsg -hi def link cmakeKWstring ModeMsg -hi def link cmakeKWsubdirs ModeMsg -hi def link cmakeKWtarget_compile_definitions ModeMsg -hi def link cmakeKWtarget_compile_features ModeMsg -hi def link cmakeKWtarget_compile_options ModeMsg -hi def link cmakeKWtarget_include_directories ModeMsg -hi def link cmakeKWtarget_link_libraries ModeMsg -hi def link cmakeKWtarget_sources ModeMsg -hi def link cmakeKWtry_compile ModeMsg -hi def link cmakeKWtry_run ModeMsg -hi def link cmakeKWunset ModeMsg -hi def link cmakeKWuse_mangled_mesa ModeMsg -hi def link cmakeKWvariable_requires ModeMsg -hi def link cmakeKWvariable_watch ModeMsg -hi def link cmakeKWwhile ModeMsg -hi def link cmakeKWwrite_file ModeMsg - -let b:current_syntax = "cmake" https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0966f1c5489591ba049b43f9e56a9f4e34778789 commit 0966f1c5489591ba049b43f9e56a9f4e34778789 Author: Brad King AuthorDate: Wed Aug 3 10:23:19 2016 -0400 Commit: Brad King CommitDate: Wed Aug 17 09:11:06 2016 -0400 Add script to update vim-cmake-syntax from upstream diff --git a/Utilities/Scripts/update-vim-syntax.bash b/Utilities/Scripts/update-vim-syntax.bash new file mode 100755 index 0000000..bb14683 --- /dev/null +++ b/Utilities/Scripts/update-vim-syntax.bash @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +set -e +set -x +shopt -s dotglob + +readonly name="vim-cmake-syntax" +readonly ownership="vim-cmake-syntax upstream " +readonly subtree="Auxiliary/vim" +readonly repo="https://github.com/pboettch/vim-cmake-syntax.git" +readonly tag="master" +readonly shortlog=true +readonly paths=" + indent + syntax + cmake.vim.in + extract-upper-case.pl +" + +extract_source () { + git_archive +} + +. "${BASH_SOURCE%/*}/update-third-party.bash" ----------------------------------------------------------------------- Summary of changes: Auxiliary/CMakeLists.txt | 2 +- Auxiliary/cmake-help.vim | 21 --- Auxiliary/vim/cmake.vim.in | 91 +++++++++++++ Auxiliary/vim/extract-upper-case.pl | 141 ++++++++++++++++++++ .../{cmake-indent.vim => vim/indent/cmake.vim} | 10 -- .../{cmake-syntax.vim => vim/syntax/cmake.vim} | 11 +- Help/release/dev/vim-cmake-syntax.rst | 11 ++ Utilities/Scripts/update-vim-syntax.bash | 24 ++++ 8 files changed, 271 insertions(+), 40 deletions(-) delete mode 100644 Auxiliary/cmake-help.vim create mode 100644 Auxiliary/vim/cmake.vim.in create mode 100755 Auxiliary/vim/extract-upper-case.pl rename Auxiliary/{cmake-indent.vim => vim/indent/cmake.vim} (88%) rename Auxiliary/{cmake-syntax.vim => vim/syntax/cmake.vim} (83%) create mode 100644 Help/release/dev/vim-cmake-syntax.rst create mode 100755 Utilities/Scripts/update-vim-syntax.bash hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 23 13:37:53 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 23 Aug 2016 13:37:53 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1370-ge8da83d Message-ID: <20160823173753.DB540F5899@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via e8da83dac6744b6c72fc19ca6372ea0feb2ccbdd (commit) via 4d3dd12b9e27f4675d07b907a313c942c7b4cffe (commit) via ff5c89de0c23c0568afcbabd63974388ca045aa3 (commit) from 4f3bc561c7c08a06ecab628d5492212a399ac6a3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e8da83dac6744b6c72fc19ca6372ea0feb2ccbdd commit e8da83dac6744b6c72fc19ca6372ea0feb2ccbdd Merge: 4f3bc56 4d3dd12 Author: Brad King AuthorDate: Tue Aug 23 13:37:52 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 23 13:37:52 2016 -0400 Merge topic 'extend-find-package-search-path' into next 4d3dd12b find_package: Extend search path for combined Windows/UNIX convention ff5c89de Help: Widen find_package search path table https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4d3dd12b9e27f4675d07b907a313c942c7b4cffe commit 4d3dd12b9e27f4675d07b907a313c942c7b4cffe Author: Silvio Traversaro AuthorDate: Sat Aug 20 12:06:55 2016 +0200 Commit: Brad King CommitDate: Tue Aug 23 13:29:11 2016 -0400 find_package: Extend search path for combined Windows/UNIX convention Find packages that install their cmake package configuration files in `lib/cmake/` when they are installed in the default Windows CMAKE_INSTALL_PREFIX, `C:/Program Files/`. Closes: #16212 diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst index 8098a87..c44fe86 100644 --- a/Help/command/find_package.rst +++ b/Help/command/find_package.rst @@ -201,6 +201,9 @@ Each entry is meant for installation trees following Windows (W), UNIX /(lib/|lib|share)/cmake/*/ (U) /(lib/|lib|share)/*/ (U) /(lib/|lib|share)/*/(cmake|CMake)/ (U) + /*/(lib/|lib|share)/cmake/*/ (W/U) + /*/(lib/|lib|share)/*/ (W/U) + /*/(lib/|lib|share)/*/(cmake|CMake)/ (W/U) On systems supporting OS X Frameworks and Application Bundles the following directories are searched for frameworks or bundles diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 260079b..62a0400 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -1961,6 +1961,44 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) } } + // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib|share)/cmake/(Foo|foo|FOO).*/ + { + cmFindPackageFileList lister(this); + lister / cmFileListGeneratorFixed(prefix) / + cmFileListGeneratorProject(this->Names) / + cmFileListGeneratorEnumerate(common) / + cmFileListGeneratorFixed("cmake") / + cmFileListGeneratorProject(this->Names); + if (lister.Search()) { + return true; + } + } + + // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib|share)/(Foo|foo|FOO).*/ + { + cmFindPackageFileList lister(this); + lister / cmFileListGeneratorFixed(prefix) / + cmFileListGeneratorProject(this->Names) / + cmFileListGeneratorEnumerate(common) / + cmFileListGeneratorProject(this->Names); + if (lister.Search()) { + return true; + } + } + + // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib|share)/(Foo|foo|FOO).*/(cmake|CMake)/ + { + cmFindPackageFileList lister(this); + lister / cmFileListGeneratorFixed(prefix) / + cmFileListGeneratorProject(this->Names) / + cmFileListGeneratorEnumerate(common) / + cmFileListGeneratorProject(this->Names) / + cmFileListGeneratorCaseInsensitive("cmake"); + if (lister.Search()) { + return true; + } + } + return false; } diff --git a/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfig.cmake b/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfig.cmake new file mode 100644 index 0000000..deffa57 --- /dev/null +++ b/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfig.cmake @@ -0,0 +1 @@ +# Test config file. diff --git a/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfigVersion.cmake b/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfigVersion.cmake new file mode 100644 index 0000000..d8cac77 --- /dev/null +++ b/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfigVersion.cmake @@ -0,0 +1,7 @@ +set(PACKAGE_VERSION 1.3) +if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 1) + set(PACKAGE_VERSION_COMPATIBLE 1) + if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 3) + set(PACKAGE_VERSION_EXACT 1) + endif() +endif() diff --git a/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfig.cmake b/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfig.cmake new file mode 100644 index 0000000..deffa57 --- /dev/null +++ b/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfig.cmake @@ -0,0 +1 @@ +# Test config file. diff --git a/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfigVersion.cmake b/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfigVersion.cmake new file mode 100644 index 0000000..5026fad --- /dev/null +++ b/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfigVersion.cmake @@ -0,0 +1,7 @@ +set(PACKAGE_VERSION 2.0) +if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 2) + set(PACKAGE_VERSION_COMPATIBLE 1) + if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 0) + set(PACKAGE_VERSION_EXACT 1) + endif() +endif() diff --git a/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfig.cmake b/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfig.cmake new file mode 100644 index 0000000..deffa57 --- /dev/null +++ b/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfig.cmake @@ -0,0 +1 @@ +# Test config file. diff --git a/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfigVersion.cmake b/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfigVersion.cmake new file mode 100644 index 0000000..a180143 --- /dev/null +++ b/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfigVersion.cmake @@ -0,0 +1,7 @@ +set(PACKAGE_VERSION 2.1) +if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 2) + set(PACKAGE_VERSION_COMPATIBLE 1) + if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 1) + set(PACKAGE_VERSION_EXACT 1) + endif() +endif() diff --git a/Tests/FindPackageTest/CMakeLists.txt b/Tests/FindPackageTest/CMakeLists.txt index d3e68bc..04bbbc6 100644 --- a/Tests/FindPackageTest/CMakeLists.txt +++ b/Tests/FindPackageTest/CMakeLists.txt @@ -102,6 +102,7 @@ endif() set(PACKAGES foo Foo Bar Blub TFramework Tframework TApp Tapp Special VersionedA VersionedB VersionedC VersionedD VersionedE + VersionedF VersionedG VersionedH WrongA WrongB WrongC WrongD wibbleA wibbleB RecursiveA RecursiveB RecursiveC @@ -142,6 +143,10 @@ find_package(VersionedB 3.1 EXACT NAMES zot) find_package(VersionedC 4.0 EXACT NAMES zot) find_package(VersionedD 1.1 EXACT NAMES Baz) find_package(VersionedE 1.2 EXACT NAMES Baz) +find_package(VersionedF 1.3 EXACT NAMES Baz) +find_package(VersionedG 2.0 EXACT NAMES Baz) +find_package(VersionedH 2.1 EXACT NAMES Baz) + # Test Config files which set Xyz_FOUND themselves: find_package(SetFoundTRUE NO_MODULE) @@ -158,12 +163,12 @@ find_package(WrongB 1.2 EXACT NAMES Baz) # Test wrong initial path when result is missing. set(WrongC_DIR "${VersionedD_DIR}") -find_package(WrongC 1.3 EXACT QUIET NAMES Baz) +find_package(WrongC 1.4 EXACT QUIET NAMES Baz) # Test wrong initial cache entry of UNINITIALIZED type when result is missing. set(WrongD_DIR "${VersionedD_DIR}" CACHE UNINITIALIZED "Wrong Value" FORCE) get_property(type CACHE WrongD_DIR PROPERTY TYPE) -find_package(WrongD 1.3 EXACT QUIET NAMES Baz) +find_package(WrongD 1.4 EXACT QUIET NAMES Baz) # HINTS should override the system but PATHS should not list(INSERT CMAKE_SYSTEM_PREFIX_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/A") @@ -216,6 +221,9 @@ set(VersionedB_EXPECTED "lib/zot-3.1/zot-config.cmake") set(VersionedC_EXPECTED "lib/cmake/zot-4.0/zot-config.cmake") set(VersionedD_EXPECTED "Baz 1.1/BazConfig.cmake") set(VersionedE_EXPECTED "Baz 1.2/CMake/BazConfig.cmake") +set(VersionedF_EXPECTED "Baz 1.3/lib/cmake/Baz/BazConfig.cmake") +set(VersionedG_EXPECTED "Baz 2.0/share/Baz 2/BazConfig.cmake") +set(VersionedH_EXPECTED "Baz 2.1/lib/Baz 2/cmake/BazConfig.cmake") set(WrongA_EXPECTED "${VersionedE_EXPECTED}") set(WrongB_EXPECTED "${VersionedE_EXPECTED}") set(WrongC_MISSING "WrongC_DIR-NOTFOUND") https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ff5c89de0c23c0568afcbabd63974388ca045aa3 commit ff5c89de0c23c0568afcbabd63974388ca045aa3 Author: Silvio Traversaro AuthorDate: Sat Aug 20 12:06:55 2016 +0200 Commit: Brad King CommitDate: Tue Aug 23 13:28:42 2016 -0400 Help: Widen find_package search path table Make room for additional longer entries. diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst index 58dff9d..8098a87 100644 --- a/Help/command/find_package.rst +++ b/Help/command/find_package.rst @@ -194,13 +194,13 @@ configuration file. The tables below show the directories searched. Each entry is meant for installation trees following Windows (W), UNIX (U), or Apple (A) conventions:: - / (W) - /(cmake|CMake)/ (W) - /*/ (W) - /*/(cmake|CMake)/ (W) - /(lib/|lib|share)/cmake/*/ (U) - /(lib/|lib|share)/*/ (U) - /(lib/|lib|share)/*/(cmake|CMake)/ (U) + / (W) + /(cmake|CMake)/ (W) + /*/ (W) + /*/(cmake|CMake)/ (W) + /(lib/|lib|share)/cmake/*/ (U) + /(lib/|lib|share)/*/ (U) + /(lib/|lib|share)/*/(cmake|CMake)/ (U) On systems supporting OS X Frameworks and Application Bundles the following directories are searched for frameworks or bundles ----------------------------------------------------------------------- Summary of changes: Help/command/find_package.rst | 17 +++++---- Source/cmFindPackageCommand.cxx | 38 ++++++++++++++++++++ .../lib/cmake/Baz}/BazConfig.cmake | 0 .../lib/cmake/Baz/BazConfigVersion.cmake} | 4 +-- .../share/Baz 2}/BazConfig.cmake | 0 .../share/Baz 2/BazConfigVersion.cmake} | 4 +-- .../lib/Baz 2/cmake}/BazConfig.cmake | 0 .../lib/Baz 2/cmake/BazConfigVersion.cmake} | 4 +-- Tests/FindPackageTest/CMakeLists.txt | 12 +++++-- 9 files changed, 64 insertions(+), 15 deletions(-) copy Tests/FindPackageTest/{Baz 1.1 => Baz 1.3/lib/cmake/Baz}/BazConfig.cmake (100%) copy Tests/FindPackageTest/{lib/suffix/test/SuffixTestConfigVersion.cmake => Baz 1.3/lib/cmake/Baz/BazConfigVersion.cmake} (64%) copy Tests/FindPackageTest/{Baz 1.1 => Baz 2.0/share/Baz 2}/BazConfig.cmake (100%) copy Tests/FindPackageTest/{lib/arch/cmake/zot-4.0/zot-config-version.cmake => Baz 2.0/share/Baz 2/BazConfigVersion.cmake} (65%) copy Tests/FindPackageTest/{Baz 1.1 => Baz 2.1/lib/Baz 2/cmake}/BazConfig.cmake (100%) copy Tests/FindPackageTest/{lib/arch/zot-3.1/zot-config-version.cmake => Baz 2.1/lib/Baz 2/cmake/BazConfigVersion.cmake} (65%) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 23 13:52:15 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 23 Aug 2016 13:52:15 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1372-g8007742 Message-ID: <20160823175215.62937F4951@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 8007742a3a19ff7d9fded4ee7a8aeec8201dce1f (commit) via ae39fdb6abaf63e7011652de801fbd4b478b2002 (commit) from e8da83dac6744b6c72fc19ca6372ea0feb2ccbdd (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8007742a3a19ff7d9fded4ee7a8aeec8201dce1f commit 8007742a3a19ff7d9fded4ee7a8aeec8201dce1f Merge: e8da83d ae39fdb Author: Brad King AuthorDate: Tue Aug 23 13:52:14 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 23 13:52:14 2016 -0400 Merge topic 'extend-find-package-search-path' into next ae39fdb6 fixup! find_package: Extend search path for combined Windows/UNIX convention https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ae39fdb6abaf63e7011652de801fbd4b478b2002 commit ae39fdb6abaf63e7011652de801fbd4b478b2002 Author: Brad King AuthorDate: Tue Aug 23 13:51:51 2016 -0400 Commit: Brad King CommitDate: Tue Aug 23 13:51:51 2016 -0400 fixup! find_package: Extend search path for combined Windows/UNIX convention diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 62a0400..8338c2a 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -1961,7 +1961,7 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) } } - // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib|share)/cmake/(Foo|foo|FOO).*/ + // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib|share)/cmake/(Foo|foo|FOO).*/ { cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / @@ -1974,7 +1974,7 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) } } - // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib|share)/(Foo|foo|FOO).*/ + // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib|share)/(Foo|foo|FOO).*/ { cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / @@ -1986,7 +1986,7 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) } } - // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib|share)/(Foo|foo|FOO).*/(cmake|CMake)/ + // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib|share)/(Foo|foo|FOO).*/(cmake|CMake)/ { cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / ----------------------------------------------------------------------- Summary of changes: Source/cmFindPackageCommand.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) hooks/post-receive -- CMake From gjasny at googlemail.com Tue Aug 23 15:12:22 2016 From: gjasny at googlemail.com (Gregor Jasny) Date: Tue, 23 Aug 2016 15:12:22 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1374-g91e3176 Message-ID: <20160823191222.5014CF3970@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 91e3176521915a83fa1bbe3efbd03042a906bcc2 (commit) via a0fbdb8b2c928306848dd19de0ceaf5a90c741a7 (commit) from 8007742a3a19ff7d9fded4ee7a8aeec8201dce1f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=91e3176521915a83fa1bbe3efbd03042a906bcc2 commit 91e3176521915a83fa1bbe3efbd03042a906bcc2 Merge: 8007742 a0fbdb8 Author: Gregor Jasny AuthorDate: Tue Aug 23 15:12:21 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 23 15:12:21 2016 -0400 Merge topic '16101-xcode-fix-directory-exclude-from-all' into next a0fbdb8b Xcode: Add targets marked as EXCLUDE_FROM_ALL to project (#16101) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a0fbdb8b2c928306848dd19de0ceaf5a90c741a7 commit a0fbdb8b2c928306848dd19de0ceaf5a90c741a7 Author: Gregor Jasny AuthorDate: Fri Aug 19 21:50:48 2016 +0200 Commit: Gregor Jasny CommitDate: Sat Aug 20 22:27:09 2016 +0200 Xcode: Add targets marked as EXCLUDE_FROM_ALL to project (#16101) diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 780ca90..7b7c744 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -2639,9 +2639,6 @@ bool cmGlobalXCodeGenerator::CreateGroups( { for (std::vector::iterator i = generators.begin(); i != generators.end(); ++i) { - if (this->IsExcluded(root, *i)) { - continue; - } cmMakefile* mf = (*i)->GetMakefile(); std::vector sourceGroups = mf->GetSourceGroups(); std::vector tgts = (*i)->GetGeneratorTargets(); @@ -3041,10 +3038,8 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( std::vector targets; for (std::vector::iterator i = generators.begin(); i != generators.end(); ++i) { - if (!this->IsExcluded(root, *i)) { - if (!this->CreateXCodeTargets(*i, targets)) { - return false; - } + if (!this->CreateXCodeTargets(*i, targets)) { + return false; } } // loop over all targets and add link and depend info diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake b/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake new file mode 100644 index 0000000..f686005 --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake @@ -0,0 +1,6 @@ +enable_language(CXX) + +add_subdirectory(ExcludeFromAll EXCLUDE_FROM_ALL) + +add_executable(main main.cpp) +target_link_libraries(main PRIVATE foo) diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt new file mode 100644 index 0000000..b1df6b0 --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(bar STATIC bar.cpp) + +add_library(foo STATIC foo.cpp) +target_include_directories(foo PUBLIC .) diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp new file mode 100644 index 0000000..7a828bd --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp @@ -0,0 +1 @@ +#error This should be excluded from all target diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp new file mode 100644 index 0000000..2789e61 --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp @@ -0,0 +1,3 @@ +#include "foo.h" + +int foo() { return 42; } diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.h b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.h new file mode 100644 index 0000000..5d5f8f0 --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.h @@ -0,0 +1 @@ +int foo(); diff --git a/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake index 9d514e1..6d9418b 100644 --- a/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake +++ b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake @@ -3,3 +3,15 @@ include(RunCMake) run_cmake(DoesNotExist) run_cmake(Missing) run_cmake(Function) + +set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ExcludeFromAll) +set(RunCMake_TEST_NO_CLEAN 1) + +file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") +file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + +run_cmake(ExcludeFromAll) +run_cmake_command(ExcludeFromAll-build ${CMAKE_COMMAND} --build .) + +unset(RunCMake_TEST_BINARY_DIR) +unset(RunCMake_TEST_NO_CLEAN) diff --git a/Tests/RunCMake/add_subdirectory/main.cpp b/Tests/RunCMake/add_subdirectory/main.cpp new file mode 100644 index 0000000..1fbb144 --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/main.cpp @@ -0,0 +1,6 @@ +#include "foo.h" + +int main(int argc, char* argv[]) +{ + return foo(); +} ----------------------------------------------------------------------- Summary of changes: Source/cmGlobalXCodeGenerator.cxx | 9 ++------- Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake | 6 ++++++ .../add_subdirectory/ExcludeFromAll/CMakeLists.txt | 4 ++++ Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp | 1 + Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp | 3 +++ .../{Framework => add_subdirectory/ExcludeFromAll}/foo.h | 0 Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake | 12 ++++++++++++ .../Case5/main.c => RunCMake/add_subdirectory/main.cpp} | 5 ++--- 8 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake create mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt create mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp create mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp copy Tests/RunCMake/{Framework => add_subdirectory/ExcludeFromAll}/foo.h (100%) copy Tests/{Dependency/Case5/main.c => RunCMake/add_subdirectory/main.cpp} (50%) hooks/post-receive -- CMake From daniel at pfeifer-mail.de Tue Aug 23 18:30:00 2016 From: daniel at pfeifer-mail.de (Daniel Pfeifer) Date: Tue, 23 Aug 2016 18:30:00 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1376-g43edf72 Message-ID: <20160823223000.7BBDDF5200@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 43edf727670912226bfbb7d9b4579e28013b42be (commit) via 5cbb54880742c23658991edec91a514f3582ed2b (commit) from 91e3176521915a83fa1bbe3efbd03042a906bcc2 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=43edf727670912226bfbb7d9b4579e28013b42be commit 43edf727670912226bfbb7d9b4579e28013b42be Merge: 91e3176 5cbb548 Author: Daniel Pfeifer AuthorDate: Tue Aug 23 18:29:58 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 23 18:29:58 2016 -0400 Merge topic 'include-what-you-use' into next 5cbb5488 fix a batch of include-what-you-use violations https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5cbb54880742c23658991edec91a514f3582ed2b commit 5cbb54880742c23658991edec91a514f3582ed2b Author: Daniel Pfeifer AuthorDate: Wed Aug 24 00:29:15 2016 +0200 Commit: Daniel Pfeifer CommitDate: Wed Aug 24 00:29:15 2016 +0200 fix a batch of include-what-you-use violations diff --git a/Source/CTest/cmCTestCVS.h b/Source/CTest/cmCTestCVS.h index 4d5e6a9..67d162d 100644 --- a/Source/CTest/cmCTestCVS.h +++ b/Source/CTest/cmCTestCVS.h @@ -14,6 +14,9 @@ #include "cmCTestVC.h" +#include +#include + /** \class cmCTestCVS * \brief Interaction with cvs command-line tool * diff --git a/Source/CTest/cmCTestGlobalVC.h b/Source/CTest/cmCTestGlobalVC.h index 7ea3440..d42d2f2 100644 --- a/Source/CTest/cmCTestGlobalVC.h +++ b/Source/CTest/cmCTestGlobalVC.h @@ -15,6 +15,8 @@ #include "cmCTestVC.h" #include +#include +#include /** \class cmCTestGlobalVC * \brief Base class for handling globally-versioned trees diff --git a/Source/cmBreakCommand.cxx b/Source/cmBreakCommand.cxx index fd57705..b33494e 100644 --- a/Source/cmBreakCommand.cxx +++ b/Source/cmBreakCommand.cxx @@ -11,6 +11,8 @@ ============================================================================*/ #include "cmBreakCommand.h" +#include "cmExecutionStatus.h" + // cmBreakCommand bool cmBreakCommand::InitialPass(std::vector const& args, cmExecutionStatus& status) diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 28a3ab5..b9d71ec 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -11,38 +11,44 @@ ============================================================================*/ #include "cmMakefile.h" +#include "cmAlgorithms.h" #include "cmCommand.h" #include "cmCommandArgumentParserHelper.h" -#include "cmCommands.h" +#include "cmCustomCommand.h" +#include "cmCustomCommandLines.h" +#include "cmExecutionStatus.h" +#include "cmExpandedCommandArgument.h" +#include "cmFileLockPool.h" #include "cmFunctionBlocker.h" #include "cmGeneratorExpression.h" #include "cmGeneratorExpressionEvaluationFile.h" #include "cmGlobalGenerator.h" +#include "cmInstallGenerator.h" #include "cmListFileCache.h" -#include "cmOutputConverter.h" #include "cmSourceFile.h" #include "cmSourceFileLocation.h" #include "cmState.h" #include "cmSystemTools.h" #include "cmTest.h" +#include "cmTestGenerator.h" #include "cmVersion.h" +#include "cmake.h" + #ifdef CMAKE_BUILD_WITH_CMAKE #include "cmVariableWatch.h" #endif -#include "cmAlgorithms.h" -#include "cmInstallGenerator.h" -#include "cmTestGenerator.h" -#include "cmake.h" -#include // required for atoi #include #include #include -#include +#include #include -#include // for isspace -#include +#include +#include +#include +#include +#include // default is not to be building executables cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator, diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index d07b4e1..d082964 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -12,16 +12,15 @@ #ifndef cmMakefile_h #define cmMakefile_h -#include "cmStandardIncludes.h" +#include #include "cmAlgorithms.h" -#include "cmExecutionStatus.h" -#include "cmExpandedCommandArgument.h" #include "cmListFileCache.h" #include "cmNewLineStyle.h" +#include "cmPolicies.h" #include "cmState.h" -#include "cmSystemTools.h" #include "cmTarget.h" +#include "cmTargetLinkLibraryType.h" #include "cmake.h" #if defined(CMAKE_BUILD_WITH_CMAKE) @@ -30,6 +29,13 @@ #include #include + +#include +#include +#include +#include +#include + #if defined(CMAKE_BUILD_WITH_CMAKE) #ifdef CMake_HAVE_CXX_UNORDERED_MAP #include @@ -38,20 +44,20 @@ #endif #endif -#include - -class cmFunctionBlocker; class cmCommand; +class cmCompiledGeneratorExpression; +class cmCustomCommandLines; +class cmExecutionStatus; +class cmExpandedCommandArgument; +class cmExportBuildFileGenerator; +class cmFunctionBlocker; +class cmGeneratorExpressionEvaluationFile; +class cmGlobalGenerator; class cmInstallGenerator; class cmSourceFile; class cmTest; class cmTestGenerator; class cmVariableWatch; -class cmake; -class cmMakefileCall; -class cmCMakePolicyCommand; -class cmGeneratorExpressionEvaluationFile; -class cmExportBuildFileGenerator; /** \class cmMakefile * \brief Process the input CMakeLists.txt file. diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 3b8bf5a..6fadc8f 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -12,12 +12,20 @@ #include "cmMakefileExecutableTargetGenerator.h" #include "cmGeneratedFileStream.h" +#include "cmGeneratorTarget.h" #include "cmGlobalUnixMakefileGenerator3.h" +#include "cmLocalGenerator.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" -#include "cmSourceFile.h" +#include "cmOSXBundleGenerator.h" +#include "cmOutputConverter.h" +#include "cmSystemTools.h" #include "cmake.h" +#include +#include +#include + cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator( cmGeneratorTarget* target) : cmMakefileTargetGenerator(target) diff --git a/Source/cmMakefileExecutableTargetGenerator.h b/Source/cmMakefileExecutableTargetGenerator.h index 39def27..1e6047e 100644 --- a/Source/cmMakefileExecutableTargetGenerator.h +++ b/Source/cmMakefileExecutableTargetGenerator.h @@ -12,8 +12,12 @@ #ifndef cmMakefileExecutableTargetGenerator_h #define cmMakefileExecutableTargetGenerator_h +#include + #include "cmMakefileTargetGenerator.h" +class cmGeneratorTarget; + class cmMakefileExecutableTargetGenerator : public cmMakefileTargetGenerator { public: diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 68f8ff1..580343d 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -11,14 +11,21 @@ ============================================================================*/ #include "cmMakefileLibraryTargetGenerator.h" -#include "cmAlgorithms.h" #include "cmGeneratedFileStream.h" +#include "cmGeneratorTarget.h" #include "cmGlobalUnixMakefileGenerator3.h" +#include "cmLocalGenerator.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" -#include "cmSourceFile.h" +#include "cmOSXBundleGenerator.h" +#include "cmOutputConverter.h" +#include "cmState.h" +#include "cmSystemTools.h" #include "cmake.h" +#include +#include + cmMakefileLibraryTargetGenerator::cmMakefileLibraryTargetGenerator( cmGeneratorTarget* target) : cmMakefileTargetGenerator(target) diff --git a/Source/cmMakefileLibraryTargetGenerator.h b/Source/cmMakefileLibraryTargetGenerator.h index 935d8b1..ec2f6bb 100644 --- a/Source/cmMakefileLibraryTargetGenerator.h +++ b/Source/cmMakefileLibraryTargetGenerator.h @@ -12,8 +12,14 @@ #ifndef cmMakefileLibraryTargetGenerator_h #define cmMakefileLibraryTargetGenerator_h +#include + #include "cmMakefileTargetGenerator.h" +#include + +class cmGeneratorTarget; + class cmMakefileLibraryTargetGenerator : public cmMakefileTargetGenerator { public: diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index e12fc09..84a15e0 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -13,23 +13,30 @@ #include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" +#include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" -#include "cmGlobalGenerator.h" #include "cmGlobalUnixMakefileGenerator3.h" +#include "cmLocalGenerator.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" -#include "cmSourceFile.h" -#include "cmState.h" -#include "cmake.h" - #include "cmMakefileExecutableTargetGenerator.h" #include "cmMakefileLibraryTargetGenerator.h" #include "cmMakefileUtilityTargetGenerator.h" +#include "cmOutputConverter.h" +#include "cmSourceFile.h" +#include "cmState.h" +#include "cmSystemTools.h" +#include "cm_auto_ptr.hxx" +#include "cmake.h" +#include #include +#include +#include +#include #ifndef _WIN32 #include diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index 29b8887..e4f7a36 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -12,18 +12,22 @@ #ifndef cmMakefileTargetGenerator_h #define cmMakefileTargetGenerator_h -#include "cmCommonTargetGenerator.h" +#include +#include "cmCommonTargetGenerator.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmOSXBundleGenerator.h" +#include +#include +#include +#include +#include + class cmCustomCommandGenerator; -class cmDepends; -class cmGeneratorTarget; class cmGeneratedFileStream; +class cmGeneratorTarget; class cmGlobalUnixMakefileGenerator3; -class cmLocalUnixMakefileGenerator3; -class cmMakefile; class cmSourceFile; /** \class cmMakefileTargetGenerator diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx index 27006ee..dfad0c4 100644 --- a/Source/cmMakefileUtilityTargetGenerator.cxx +++ b/Source/cmMakefileUtilityTargetGenerator.cxx @@ -12,10 +12,16 @@ #include "cmMakefileUtilityTargetGenerator.h" #include "cmGeneratedFileStream.h" +#include "cmGeneratorTarget.h" #include "cmGlobalUnixMakefileGenerator3.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" -#include "cmSourceFile.h" +#include "cmOSXBundleGenerator.h" +#include "cmOutputConverter.h" + +#include +#include +#include cmMakefileUtilityTargetGenerator::cmMakefileUtilityTargetGenerator( cmGeneratorTarget* target) diff --git a/Source/cmMakefileUtilityTargetGenerator.h b/Source/cmMakefileUtilityTargetGenerator.h index b41fb8b..daf4bac 100644 --- a/Source/cmMakefileUtilityTargetGenerator.h +++ b/Source/cmMakefileUtilityTargetGenerator.h @@ -12,8 +12,12 @@ #ifndef cmMakefileUtilityTargetGenerator_h #define cmMakefileUtilityTargetGenerator_h +#include + #include "cmMakefileTargetGenerator.h" +class cmGeneratorTarget; + class cmMakefileUtilityTargetGenerator : public cmMakefileTargetGenerator { public: diff --git a/Source/cmNewLineStyle.cxx b/Source/cmNewLineStyle.cxx index d64993a..e9d017e 100644 --- a/Source/cmNewLineStyle.cxx +++ b/Source/cmNewLineStyle.cxx @@ -11,6 +11,8 @@ ============================================================================*/ #include "cmNewLineStyle.h" +#include + cmNewLineStyle::cmNewLineStyle() : NewLineStyle(Invalid) { diff --git a/Source/cmNewLineStyle.h b/Source/cmNewLineStyle.h index 800f131..427348a 100644 --- a/Source/cmNewLineStyle.h +++ b/Source/cmNewLineStyle.h @@ -12,7 +12,10 @@ #ifndef cmNewLineStyle_h #define cmNewLineStyle_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep + +#include +#include class cmNewLineStyle { diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 7644df3..d0db133 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -13,18 +13,30 @@ #include "cmNinjaNormalTargetGenerator.h" #include "cmAlgorithms.h" +#include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGlobalNinjaGenerator.h" +#include "cmLocalGenerator.h" #include "cmLocalNinjaGenerator.h" #include "cmMakefile.h" +#include "cmNinjaTypes.h" #include "cmOSXBundleGenerator.h" +#include "cmOutputConverter.h" #include "cmSourceFile.h" +#include "cmState.h" +#include "cmSystemTools.h" +#include "cmake.h" #include #include +#include #include +#include +#include +#include +#include #ifndef _WIN32 #include diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h index f466e17..1f670bf 100644 --- a/Source/cmNinjaNormalTargetGenerator.h +++ b/Source/cmNinjaNormalTargetGenerator.h @@ -13,14 +13,13 @@ #ifndef cmNinjaNormalTargetGenerator_h #define cmNinjaNormalTargetGenerator_h -#include "cmNinjaTargetGenerator.h" +#include -#include "cmNinjaTypes.h" +#include "cmNinjaTargetGenerator.h" -#include +#include +#include -class cmSourceFile; -class cmOSXBundleGenerator; class cmGeneratorTarget; class cmNinjaNormalTargetGenerator : public cmNinjaTargetGenerator diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 9030e05..6ac59d5 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -18,14 +18,22 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGlobalNinjaGenerator.h" +#include "cmLocalGenerator.h" #include "cmLocalNinjaGenerator.h" #include "cmMakefile.h" #include "cmNinjaNormalTargetGenerator.h" #include "cmNinjaUtilityTargetGenerator.h" +#include "cmOutputConverter.h" #include "cmSourceFile.h" +#include "cmState.h" #include "cmSystemTools.h" +#include "cmake.h" #include +#include +#include +#include +#include cmNinjaTargetGenerator* cmNinjaTargetGenerator::New(cmGeneratorTarget* target) { diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index 9740f0e..2b26788 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -13,19 +13,23 @@ #ifndef cmNinjaTargetGenerator_h #define cmNinjaTargetGenerator_h -#include "cmCommonTargetGenerator.h" +#include +#include "cmCommonTargetGenerator.h" #include "cmGlobalNinjaGenerator.h" -#include "cmLocalNinjaGenerator.h" #include "cmNinjaTypes.h" #include "cmOSXBundleGenerator.h" -class cmTarget; +#include +#include +#include + +class cmCustomCommand; class cmGeneratedFileStream; class cmGeneratorTarget; +class cmLocalNinjaGenerator; class cmMakefile; class cmSourceFile; -class cmCustomCommand; class cmNinjaTargetGenerator : public cmCommonTargetGenerator { diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx index 96a17ff..49836f2 100644 --- a/Source/cmNinjaUtilityTargetGenerator.cxx +++ b/Source/cmNinjaUtilityTargetGenerator.cxx @@ -15,9 +15,21 @@ #include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" #include "cmGeneratedFileStream.h" +#include "cmGeneratorTarget.h" #include "cmGlobalNinjaGenerator.h" +#include "cmLocalNinjaGenerator.h" #include "cmMakefile.h" +#include "cmNinjaTypes.h" +#include "cmOutputConverter.h" #include "cmSourceFile.h" +#include "cmState.h" +#include "cmSystemTools.h" +#include "cmake.h" + +#include +#include +#include +#include cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator( cmGeneratorTarget* target) diff --git a/Source/cmNinjaUtilityTargetGenerator.h b/Source/cmNinjaUtilityTargetGenerator.h index 0c33a54..78015aa 100644 --- a/Source/cmNinjaUtilityTargetGenerator.h +++ b/Source/cmNinjaUtilityTargetGenerator.h @@ -13,11 +13,11 @@ #ifndef cmNinjaUtilityTargetGenerator_h #define cmNinjaUtilityTargetGenerator_h -#include "cmNinjaTargetGenerator.h" +#include -#include "cmNinjaTypes.h" +#include "cmNinjaTargetGenerator.h" -class cmSourceFile; +class cmGeneratorTarget; class cmNinjaUtilityTargetGenerator : public cmNinjaTargetGenerator { diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index c456d88..7688c59 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -2,14 +2,18 @@ #include "cmAlgorithms.h" #include "cmMakefile.h" +#include "cmState.h" +#include "cmSystemTools.h" #include "cmVersion.h" -#include "cmVersionMacros.h" #include "cmake.h" + #include +#include #include -#include -#include -#include +#include +#include +#include +#include static bool stringToId(const char* input, cmPolicies::PolicyID& pid) { diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 0c8ff60..149bb46 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -12,12 +12,12 @@ #ifndef cmPolicies_h #define cmPolicies_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include +#include class cmMakefile; -class cmPolicy; #define CM_FOR_EACH_POLICY_TABLE(POLICY, SELECT) \ SELECT(POLICY, CMP0000, \ diff --git a/Source/cmProcessTools.cxx b/Source/cmProcessTools.cxx index 34b8df2..4a0d459 100644 --- a/Source/cmProcessTools.cxx +++ b/Source/cmProcessTools.cxx @@ -12,6 +12,7 @@ #include "cmProcessTools.h" #include +#include void cmProcessTools::RunProcess(struct cmsysProcess_s* cp, OutputParser* out, OutputParser* err) diff --git a/Source/cmProcessTools.h b/Source/cmProcessTools.h index 61bfc64..3d2a224 100644 --- a/Source/cmProcessTools.h +++ b/Source/cmProcessTools.h @@ -12,7 +12,11 @@ #ifndef cmProcessTools_h #define cmProcessTools_h -#include "cmStandardIncludes.h" +#include + +#include +#include +#include /** \class cmProcessTools * \brief Helper classes for process output parsing diff --git a/Source/cmProperty.cxx b/Source/cmProperty.cxx index 133258f..75b44cb 100644 --- a/Source/cmProperty.cxx +++ b/Source/cmProperty.cxx @@ -11,7 +11,7 @@ ============================================================================*/ #include "cmProperty.h" -#include "cmSystemTools.h" +#include void cmProperty::Set(const char* value) { diff --git a/Source/cmProperty.h b/Source/cmProperty.h index 1736136..2091360 100644 --- a/Source/cmProperty.h +++ b/Source/cmProperty.h @@ -12,7 +12,9 @@ #ifndef cmProperty_h #define cmProperty_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep + +#include class cmProperty { diff --git a/Source/cmPropertyDefinition.cxx b/Source/cmPropertyDefinition.cxx index 546146b..003898a 100644 --- a/Source/cmPropertyDefinition.cxx +++ b/Source/cmPropertyDefinition.cxx @@ -11,8 +11,6 @@ ============================================================================*/ #include "cmPropertyDefinition.h" -#include "cmSystemTools.h" - void cmPropertyDefinition::DefineProperty(const std::string& name, cmProperty::ScopeType scope, const char* shortDescription, diff --git a/Source/cmPropertyDefinition.h b/Source/cmPropertyDefinition.h index 5733917..5804df9 100644 --- a/Source/cmPropertyDefinition.h +++ b/Source/cmPropertyDefinition.h @@ -12,8 +12,12 @@ #ifndef cmPropertyDefinition_h #define cmPropertyDefinition_h +#include // IWYU pragma: keep + #include "cmProperty.h" +#include + /** \class cmPropertyDefinition * \brief Property meta-information * diff --git a/Source/cmPropertyDefinitionMap.cxx b/Source/cmPropertyDefinitionMap.cxx index 0ba35e7..0015337 100644 --- a/Source/cmPropertyDefinitionMap.cxx +++ b/Source/cmPropertyDefinitionMap.cxx @@ -11,8 +11,7 @@ ============================================================================*/ #include "cmPropertyDefinitionMap.h" -#include "cmDocumentationSection.h" -#include "cmSystemTools.h" +#include void cmPropertyDefinitionMap::DefineProperty(const std::string& name, cmProperty::ScopeType scope, diff --git a/Source/cmPropertyDefinitionMap.h b/Source/cmPropertyDefinitionMap.h index fbc9a18..a4e4600 100644 --- a/Source/cmPropertyDefinitionMap.h +++ b/Source/cmPropertyDefinitionMap.h @@ -12,9 +12,13 @@ #ifndef cmPropertyDefinitionMap_h #define cmPropertyDefinitionMap_h +#include // IWYU pragma: keep + +#include "cmProperty.h" #include "cmPropertyDefinition.h" -class cmDocumentationSection; +#include +#include class cmPropertyDefinitionMap : public std::map diff --git a/Source/cmPropertyMap.cxx b/Source/cmPropertyMap.cxx index 1e1ff91..5a6ba2a 100644 --- a/Source/cmPropertyMap.cxx +++ b/Source/cmPropertyMap.cxx @@ -11,12 +11,10 @@ ============================================================================*/ #include "cmPropertyMap.h" -#include "cmState.h" -#include "cmSystemTools.h" -#include "cmake.h" - #include #include +#include +#include cmProperty* cmPropertyMap::GetOrCreateProperty(const std::string& name) { diff --git a/Source/cmPropertyMap.h b/Source/cmPropertyMap.h index 6dc7bfb..151255e 100644 --- a/Source/cmPropertyMap.h +++ b/Source/cmPropertyMap.h @@ -12,8 +12,14 @@ #ifndef cmPropertyMap_h #define cmPropertyMap_h +#include // IWYU pragma: keep + #include "cmProperty.h" +#include +#include +#include + class cmPropertyMap : public std::map { public: ----------------------------------------------------------------------- Summary of changes: Source/CTest/cmCTestCVS.h | 3 +++ Source/CTest/cmCTestGlobalVC.h | 2 ++ Source/cmBreakCommand.cxx | 2 ++ Source/cmMakefile.cxx | 26 ++++++++++++-------- Source/cmMakefile.h | 30 ++++++++++++++---------- Source/cmMakefileExecutableTargetGenerator.cxx | 10 +++++++- Source/cmMakefileExecutableTargetGenerator.h | 4 ++++ Source/cmMakefileLibraryTargetGenerator.cxx | 11 +++++++-- Source/cmMakefileLibraryTargetGenerator.h | 6 +++++ Source/cmMakefileTargetGenerator.cxx | 17 ++++++++++---- Source/cmMakefileTargetGenerator.h | 14 +++++++---- Source/cmMakefileUtilityTargetGenerator.cxx | 8 ++++++- Source/cmMakefileUtilityTargetGenerator.h | 4 ++++ Source/cmNewLineStyle.cxx | 2 ++ Source/cmNewLineStyle.h | 5 +++- Source/cmNinjaNormalTargetGenerator.cxx | 12 ++++++++++ Source/cmNinjaNormalTargetGenerator.h | 9 ++++--- Source/cmNinjaTargetGenerator.cxx | 8 +++++++ Source/cmNinjaTargetGenerator.h | 12 ++++++---- Source/cmNinjaUtilityTargetGenerator.cxx | 12 ++++++++++ Source/cmNinjaUtilityTargetGenerator.h | 6 ++--- Source/cmPolicies.cxx | 12 ++++++---- Source/cmPolicies.h | 4 ++-- Source/cmProcessTools.cxx | 1 + Source/cmProcessTools.h | 6 ++++- Source/cmProperty.cxx | 2 +- Source/cmProperty.h | 4 +++- Source/cmPropertyDefinition.cxx | 2 -- Source/cmPropertyDefinition.h | 4 ++++ Source/cmPropertyDefinitionMap.cxx | 3 +-- Source/cmPropertyDefinitionMap.h | 6 ++++- Source/cmPropertyMap.cxx | 6 ++--- Source/cmPropertyMap.h | 6 +++++ 33 files changed, 192 insertions(+), 67 deletions(-) hooks/post-receive -- CMake From kwrobot at kitware.com Wed Aug 24 00:01:10 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Wed, 24 Aug 2016 00:01:10 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-667-g00a583a Message-ID: <20160824040110.57549F5412@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 00a583ac6833bdb2909d1bab1bffb28fb6c2b245 (commit) from 797f7ad87d6f1b6dd7cbbb553d5525ac8ee390f1 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=00a583ac6833bdb2909d1bab1bffb28fb6c2b245 commit 00a583ac6833bdb2909d1bab1bffb28fb6c2b245 Author: Kitware Robot AuthorDate: Wed Aug 24 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Wed Aug 24 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index da0aba0..aabc839 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160823) +set(CMake_VERSION_PATCH 20160824) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 09:32:36 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 09:32:36 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1379-gab1846f Message-ID: <20160824133236.8A602F57DB@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via ab1846f43b8eff95eba073a9df2414f24601d7a5 (commit) via d8fbb7d2d33ddbfa69f13e86c9da293591bf8d5f (commit) via 00a583ac6833bdb2909d1bab1bffb28fb6c2b245 (commit) from 43edf727670912226bfbb7d9b4579e28013b42be (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ab1846f43b8eff95eba073a9df2414f24601d7a5 commit ab1846f43b8eff95eba073a9df2414f24601d7a5 Merge: 43edf72 d8fbb7d Author: Brad King AuthorDate: Wed Aug 24 09:32:35 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 09:32:35 2016 -0400 Merge topic 'vs-resource-pri-dir' into next d8fbb7d2 VS: Use target-specific intermediate directory for `resources.pri` 00a583ac CMake Nightly Date Stamp https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d8fbb7d2d33ddbfa69f13e86c9da293591bf8d5f commit d8fbb7d2d33ddbfa69f13e86c9da293591bf8d5f Author: Vitalyi Khoruzhyi AuthorDate: Fri May 20 14:18:02 2016 +0300 Commit: Brad King CommitDate: Wed Aug 24 09:02:49 2016 -0400 VS: Use target-specific intermediate directory for `resources.pri` Set the `ProjectPriFullPath` field to a value that is unique to each target and not shared with others in order to avoid collisions. Closes: #16106 diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index c33a291..ffad095 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2742,7 +2742,7 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile() (*this->BuildFileStream) << cmVS10EscapeXML(artifactDir) << "\\\n"; this->WriteString("" - "$(TargetDir)resources.pri\n", + "$(IntDir)resources.pri\n", 2); // If we are missing files and we don't have a certificate and ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- Source/cmVisualStudio10TargetGenerator.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 09:40:44 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 09:40:44 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1381-gbbc5b5c Message-ID: <20160824134044.B394AF36A3@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via bbc5b5cbd9beeb0091fd8b07de4d4b2ef0b48f91 (commit) via 828d6c137d703ea095008fc6da794904a15c4ebd (commit) from ab1846f43b8eff95eba073a9df2414f24601d7a5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bbc5b5cbd9beeb0091fd8b07de4d4b2ef0b48f91 commit bbc5b5cbd9beeb0091fd8b07de4d4b2ef0b48f91 Merge: ab1846f 828d6c1 Author: Brad King AuthorDate: Wed Aug 24 09:40:43 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 09:40:43 2016 -0400 Merge topic 'extend-find-package-search-path' into next 828d6c13 find_package: Extend search path for combined Windows/UNIX convention https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=828d6c137d703ea095008fc6da794904a15c4ebd commit 828d6c137d703ea095008fc6da794904a15c4ebd Author: Silvio Traversaro AuthorDate: Sat Aug 20 12:06:55 2016 +0200 Commit: Brad King CommitDate: Wed Aug 24 09:40:25 2016 -0400 find_package: Extend search path for combined Windows/UNIX convention Find packages that install their cmake package configuration files in `lib/cmake/` when they are installed in the default Windows CMAKE_INSTALL_PREFIX, `C:/Program Files/`. Closes: #16212 diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst index 8098a87..c44fe86 100644 --- a/Help/command/find_package.rst +++ b/Help/command/find_package.rst @@ -201,6 +201,9 @@ Each entry is meant for installation trees following Windows (W), UNIX /(lib/|lib|share)/cmake/*/ (U) /(lib/|lib|share)/*/ (U) /(lib/|lib|share)/*/(cmake|CMake)/ (U) + /*/(lib/|lib|share)/cmake/*/ (W/U) + /*/(lib/|lib|share)/*/ (W/U) + /*/(lib/|lib|share)/*/(cmake|CMake)/ (W/U) On systems supporting OS X Frameworks and Application Bundles the following directories are searched for frameworks or bundles diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 260079b..8338c2a 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -1961,6 +1961,44 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) } } + // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib|share)/cmake/(Foo|foo|FOO).*/ + { + cmFindPackageFileList lister(this); + lister / cmFileListGeneratorFixed(prefix) / + cmFileListGeneratorProject(this->Names) / + cmFileListGeneratorEnumerate(common) / + cmFileListGeneratorFixed("cmake") / + cmFileListGeneratorProject(this->Names); + if (lister.Search()) { + return true; + } + } + + // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib|share)/(Foo|foo|FOO).*/ + { + cmFindPackageFileList lister(this); + lister / cmFileListGeneratorFixed(prefix) / + cmFileListGeneratorProject(this->Names) / + cmFileListGeneratorEnumerate(common) / + cmFileListGeneratorProject(this->Names); + if (lister.Search()) { + return true; + } + } + + // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib|share)/(Foo|foo|FOO).*/(cmake|CMake)/ + { + cmFindPackageFileList lister(this); + lister / cmFileListGeneratorFixed(prefix) / + cmFileListGeneratorProject(this->Names) / + cmFileListGeneratorEnumerate(common) / + cmFileListGeneratorProject(this->Names) / + cmFileListGeneratorCaseInsensitive("cmake"); + if (lister.Search()) { + return true; + } + } + return false; } diff --git a/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfig.cmake b/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfig.cmake new file mode 100644 index 0000000..deffa57 --- /dev/null +++ b/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfig.cmake @@ -0,0 +1 @@ +# Test config file. diff --git a/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfigVersion.cmake b/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfigVersion.cmake new file mode 100644 index 0000000..d8cac77 --- /dev/null +++ b/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfigVersion.cmake @@ -0,0 +1,7 @@ +set(PACKAGE_VERSION 1.3) +if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 1) + set(PACKAGE_VERSION_COMPATIBLE 1) + if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 3) + set(PACKAGE_VERSION_EXACT 1) + endif() +endif() diff --git a/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfig.cmake b/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfig.cmake new file mode 100644 index 0000000..deffa57 --- /dev/null +++ b/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfig.cmake @@ -0,0 +1 @@ +# Test config file. diff --git a/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfigVersion.cmake b/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfigVersion.cmake new file mode 100644 index 0000000..5026fad --- /dev/null +++ b/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfigVersion.cmake @@ -0,0 +1,7 @@ +set(PACKAGE_VERSION 2.0) +if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 2) + set(PACKAGE_VERSION_COMPATIBLE 1) + if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 0) + set(PACKAGE_VERSION_EXACT 1) + endif() +endif() diff --git a/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfig.cmake b/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfig.cmake new file mode 100644 index 0000000..deffa57 --- /dev/null +++ b/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfig.cmake @@ -0,0 +1 @@ +# Test config file. diff --git a/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfigVersion.cmake b/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfigVersion.cmake new file mode 100644 index 0000000..a180143 --- /dev/null +++ b/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfigVersion.cmake @@ -0,0 +1,7 @@ +set(PACKAGE_VERSION 2.1) +if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 2) + set(PACKAGE_VERSION_COMPATIBLE 1) + if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 1) + set(PACKAGE_VERSION_EXACT 1) + endif() +endif() diff --git a/Tests/FindPackageTest/CMakeLists.txt b/Tests/FindPackageTest/CMakeLists.txt index d3e68bc..04bbbc6 100644 --- a/Tests/FindPackageTest/CMakeLists.txt +++ b/Tests/FindPackageTest/CMakeLists.txt @@ -102,6 +102,7 @@ endif() set(PACKAGES foo Foo Bar Blub TFramework Tframework TApp Tapp Special VersionedA VersionedB VersionedC VersionedD VersionedE + VersionedF VersionedG VersionedH WrongA WrongB WrongC WrongD wibbleA wibbleB RecursiveA RecursiveB RecursiveC @@ -142,6 +143,10 @@ find_package(VersionedB 3.1 EXACT NAMES zot) find_package(VersionedC 4.0 EXACT NAMES zot) find_package(VersionedD 1.1 EXACT NAMES Baz) find_package(VersionedE 1.2 EXACT NAMES Baz) +find_package(VersionedF 1.3 EXACT NAMES Baz) +find_package(VersionedG 2.0 EXACT NAMES Baz) +find_package(VersionedH 2.1 EXACT NAMES Baz) + # Test Config files which set Xyz_FOUND themselves: find_package(SetFoundTRUE NO_MODULE) @@ -158,12 +163,12 @@ find_package(WrongB 1.2 EXACT NAMES Baz) # Test wrong initial path when result is missing. set(WrongC_DIR "${VersionedD_DIR}") -find_package(WrongC 1.3 EXACT QUIET NAMES Baz) +find_package(WrongC 1.4 EXACT QUIET NAMES Baz) # Test wrong initial cache entry of UNINITIALIZED type when result is missing. set(WrongD_DIR "${VersionedD_DIR}" CACHE UNINITIALIZED "Wrong Value" FORCE) get_property(type CACHE WrongD_DIR PROPERTY TYPE) -find_package(WrongD 1.3 EXACT QUIET NAMES Baz) +find_package(WrongD 1.4 EXACT QUIET NAMES Baz) # HINTS should override the system but PATHS should not list(INSERT CMAKE_SYSTEM_PREFIX_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/A") @@ -216,6 +221,9 @@ set(VersionedB_EXPECTED "lib/zot-3.1/zot-config.cmake") set(VersionedC_EXPECTED "lib/cmake/zot-4.0/zot-config.cmake") set(VersionedD_EXPECTED "Baz 1.1/BazConfig.cmake") set(VersionedE_EXPECTED "Baz 1.2/CMake/BazConfig.cmake") +set(VersionedF_EXPECTED "Baz 1.3/lib/cmake/Baz/BazConfig.cmake") +set(VersionedG_EXPECTED "Baz 2.0/share/Baz 2/BazConfig.cmake") +set(VersionedH_EXPECTED "Baz 2.1/lib/Baz 2/cmake/BazConfig.cmake") set(WrongA_EXPECTED "${VersionedE_EXPECTED}") set(WrongB_EXPECTED "${VersionedE_EXPECTED}") set(WrongC_MISSING "WrongC_DIR-NOTFOUND") ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 09:45:33 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 09:45:33 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-674-ga71ca1f Message-ID: <20160824134533.33A9BF4889@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via a71ca1f0b3a405e6ff1ea4b09badcc345581ddba (commit) via b4556b47a82f09d2dc40118e1e6cb41b69ece529 (commit) via 25c01cf0b0b940bbfb2d27410efdb4091479bcda (commit) via e3ac68cfbf04e48a089b6d3cb4f4091e559dc5a0 (commit) via 4a22c06e7fe8bcfb3c7243c5b8d98cc34df13f06 (commit) via f21a823598c672efd73de09b826acaeba231946c (commit) via 0966f1c5489591ba049b43f9e56a9f4e34778789 (commit) from 00a583ac6833bdb2909d1bab1bffb28fb6c2b245 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a71ca1f0b3a405e6ff1ea4b09badcc345581ddba commit a71ca1f0b3a405e6ff1ea4b09badcc345581ddba Merge: 00a583a b4556b4 Author: Brad King AuthorDate: Wed Aug 24 09:45:29 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 09:45:29 2016 -0400 Merge topic 'import-vim-syntax' b4556b47 Help: Add release notes for 'vim-cmake-syntax' import 25c01cf0 Aux: Install vim-cmake-syntax files with CMake e3ac68cf Merge branch 'upstream-vim-cmake-syntax' into import-vim-syntax 4a22c06e vim-cmake-syntax 2016-08-16 (e782679c) f21a8235 Aux: Drop vim files prior to import of third-party version 0966f1c5 Add script to update vim-cmake-syntax from upstream ----------------------------------------------------------------------- Summary of changes: Auxiliary/CMakeLists.txt | 2 +- Auxiliary/cmake-help.vim | 21 --- Auxiliary/vim/cmake.vim.in | 91 +++++++++++++ Auxiliary/vim/extract-upper-case.pl | 141 ++++++++++++++++++++ .../{cmake-indent.vim => vim/indent/cmake.vim} | 10 -- .../{cmake-syntax.vim => vim/syntax/cmake.vim} | 11 +- Help/release/dev/vim-cmake-syntax.rst | 11 ++ Utilities/Scripts/update-vim-syntax.bash | 24 ++++ 8 files changed, 271 insertions(+), 40 deletions(-) delete mode 100644 Auxiliary/cmake-help.vim create mode 100644 Auxiliary/vim/cmake.vim.in create mode 100755 Auxiliary/vim/extract-upper-case.pl rename Auxiliary/{cmake-indent.vim => vim/indent/cmake.vim} (88%) rename Auxiliary/{cmake-syntax.vim => vim/syntax/cmake.vim} (83%) create mode 100644 Help/release/dev/vim-cmake-syntax.rst create mode 100755 Utilities/Scripts/update-vim-syntax.bash hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 09:45:35 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 09:45:35 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-677-g2986ca5 Message-ID: <20160824134535.E67E8F49B7@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 2986ca5ecc0120790c7fc8801647078f3475be18 (commit) via aec06dd4922187ce5346d20a9f0d53f01b6ce9fc (commit) via ef13efab56464890f171c2a2142b64b728f4f2e8 (commit) from a71ca1f0b3a405e6ff1ea4b09badcc345581ddba (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2986ca5ecc0120790c7fc8801647078f3475be18 commit 2986ca5ecc0120790c7fc8801647078f3475be18 Merge: a71ca1f aec06dd Author: Brad King AuthorDate: Wed Aug 24 09:45:33 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 09:45:33 2016 -0400 Merge topic 'version-cleanups' aec06dd4 Version: Always define CMake_VERSION_IS_DIRTY to 0 or 1 ef13efab Version: Remove check for existence of CVS repository ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersionCompute.cmake | 1 + Source/CMakeVersionSource.cmake | 9 --------- 2 files changed, 1 insertion(+), 9 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 09:45:38 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 09:45:38 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-679-g1d858dc Message-ID: <20160824134538.89BFAF4A0A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 1d858dc017560b99206b542c42b2a7adaa344cb8 (commit) via 9bd0643a771b19131d14613e963d61d4b32106ee (commit) from 2986ca5ecc0120790c7fc8801647078f3475be18 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1d858dc017560b99206b542c42b2a7adaa344cb8 commit 1d858dc017560b99206b542c42b2a7adaa344cb8 Merge: 2986ca5 9bd0643 Author: Brad King AuthorDate: Wed Aug 24 09:45:36 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 09:45:36 2016 -0400 Merge topic 'test-extra-generator-dedup' 9bd0643a Tests: Refactor testing of extra generators. ----------------------------------------------------------------------- Summary of changes: Tests/CMakeLists.txt | 77 ++++++++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 47 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 09:45:41 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 09:45:41 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-681-g5c8b69b Message-ID: <20160824134541.2DAF5F4A9B@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 5c8b69b0f5408bb59a92ff3f061bd76efa773eff (commit) via 2dc9a754b539bb215ad2360a27327a629ad26627 (commit) from 1d858dc017560b99206b542c42b2a7adaa344cb8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5c8b69b0f5408bb59a92ff3f061bd76efa773eff commit 5c8b69b0f5408bb59a92ff3f061bd76efa773eff Merge: 1d858dc 2dc9a75 Author: Brad King AuthorDate: Wed Aug 24 09:45:39 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 09:45:39 2016 -0400 Merge topic 'FindCUDA-fix-arch-regex' 2dc9a754 FindCUDA: Support `2.1(2.0)` architecture notation ----------------------------------------------------------------------- Summary of changes: Modules/FindCUDA/select_compute_arch.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 09:45:43 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 09:45:43 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-683-g21a7809 Message-ID: <20160824134543.CD213F487D@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 21a7809bfaa02ec3d11620676636e65b47065b62 (commit) via 15cc50fbb505b526e28c708e4e1b16e79a66799c (commit) from 5c8b69b0f5408bb59a92ff3f061bd76efa773eff (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=21a7809bfaa02ec3d11620676636e65b47065b62 commit 21a7809bfaa02ec3d11620676636e65b47065b62 Merge: 5c8b69b 15cc50f Author: Brad King AuthorDate: Wed Aug 24 09:45:41 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 09:45:41 2016 -0400 Merge topic 'doc-get_cmake_property' 15cc50fb Help: Clarify get_cmake_property command documentation ----------------------------------------------------------------------- Summary of changes: Help/command/get_cmake_property.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 09:45:46 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 09:45:46 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-685-g4a2a66e Message-ID: <20160824134546.A03B1F4987@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 4a2a66e31c4b7fbcc6bbe41219a6c7f0624dc165 (commit) via 5cbb54880742c23658991edec91a514f3582ed2b (commit) from 21a7809bfaa02ec3d11620676636e65b47065b62 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4a2a66e31c4b7fbcc6bbe41219a6c7f0624dc165 commit 4a2a66e31c4b7fbcc6bbe41219a6c7f0624dc165 Merge: 21a7809 5cbb548 Author: Brad King AuthorDate: Wed Aug 24 09:45:44 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 09:45:44 2016 -0400 Merge topic 'include-what-you-use' 5cbb5488 fix a batch of include-what-you-use violations ----------------------------------------------------------------------- Summary of changes: Source/CTest/cmCTestCVS.h | 3 +++ Source/CTest/cmCTestGlobalVC.h | 2 ++ Source/cmBreakCommand.cxx | 2 ++ Source/cmMakefile.cxx | 26 ++++++++++++-------- Source/cmMakefile.h | 30 ++++++++++++++---------- Source/cmMakefileExecutableTargetGenerator.cxx | 10 +++++++- Source/cmMakefileExecutableTargetGenerator.h | 4 ++++ Source/cmMakefileLibraryTargetGenerator.cxx | 11 +++++++-- Source/cmMakefileLibraryTargetGenerator.h | 6 +++++ Source/cmMakefileTargetGenerator.cxx | 17 ++++++++++---- Source/cmMakefileTargetGenerator.h | 14 +++++++---- Source/cmMakefileUtilityTargetGenerator.cxx | 8 ++++++- Source/cmMakefileUtilityTargetGenerator.h | 4 ++++ Source/cmNewLineStyle.cxx | 2 ++ Source/cmNewLineStyle.h | 5 +++- Source/cmNinjaNormalTargetGenerator.cxx | 12 ++++++++++ Source/cmNinjaNormalTargetGenerator.h | 9 ++++--- Source/cmNinjaTargetGenerator.cxx | 8 +++++++ Source/cmNinjaTargetGenerator.h | 12 ++++++---- Source/cmNinjaUtilityTargetGenerator.cxx | 12 ++++++++++ Source/cmNinjaUtilityTargetGenerator.h | 6 ++--- Source/cmPolicies.cxx | 12 ++++++---- Source/cmPolicies.h | 4 ++-- Source/cmProcessTools.cxx | 1 + Source/cmProcessTools.h | 6 ++++- Source/cmProperty.cxx | 2 +- Source/cmProperty.h | 4 +++- Source/cmPropertyDefinition.cxx | 2 -- Source/cmPropertyDefinition.h | 4 ++++ Source/cmPropertyDefinitionMap.cxx | 3 +-- Source/cmPropertyDefinitionMap.h | 6 ++++- Source/cmPropertyMap.cxx | 6 ++--- Source/cmPropertyMap.h | 6 +++++ 33 files changed, 192 insertions(+), 67 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 09:45:49 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 09:45:49 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-688-gccddb45 Message-ID: <20160824134549.82E4FF49F7@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via ccddb454b8e7ae3ae075db5fd3233ce86c8c70cb (commit) via 828d6c137d703ea095008fc6da794904a15c4ebd (commit) via ff5c89de0c23c0568afcbabd63974388ca045aa3 (commit) from 4a2a66e31c4b7fbcc6bbe41219a6c7f0624dc165 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ccddb454b8e7ae3ae075db5fd3233ce86c8c70cb commit ccddb454b8e7ae3ae075db5fd3233ce86c8c70cb Merge: 4a2a66e 828d6c1 Author: Brad King AuthorDate: Wed Aug 24 09:45:47 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 09:45:47 2016 -0400 Merge topic 'extend-find-package-search-path' 828d6c13 find_package: Extend search path for combined Windows/UNIX convention ff5c89de Help: Widen find_package search path table ----------------------------------------------------------------------- Summary of changes: Help/command/find_package.rst | 17 +++++---- Source/cmFindPackageCommand.cxx | 38 ++++++++++++++++++++ .../lib/cmake/Baz}/BazConfig.cmake | 0 .../lib/cmake/Baz/BazConfigVersion.cmake} | 4 +-- .../share/Baz 2}/BazConfig.cmake | 0 .../share/Baz 2/BazConfigVersion.cmake} | 4 +-- .../lib/Baz 2/cmake}/BazConfig.cmake | 0 .../lib/Baz 2/cmake/BazConfigVersion.cmake} | 4 +-- Tests/FindPackageTest/CMakeLists.txt | 12 +++++-- 9 files changed, 64 insertions(+), 15 deletions(-) copy Tests/FindPackageTest/{Baz 1.1 => Baz 1.3/lib/cmake/Baz}/BazConfig.cmake (100%) copy Tests/FindPackageTest/{lib/suffix/test/SuffixTestConfigVersion.cmake => Baz 1.3/lib/cmake/Baz/BazConfigVersion.cmake} (64%) copy Tests/FindPackageTest/{Baz 1.1 => Baz 2.0/share/Baz 2}/BazConfig.cmake (100%) copy Tests/FindPackageTest/{lib/arch/cmake/zot-4.0/zot-config-version.cmake => Baz 2.0/share/Baz 2/BazConfigVersion.cmake} (65%) copy Tests/FindPackageTest/{Baz 1.1 => Baz 2.1/lib/Baz 2/cmake}/BazConfig.cmake (100%) copy Tests/FindPackageTest/{lib/arch/zot-3.1/zot-config-version.cmake => Baz 2.1/lib/Baz 2/cmake/BazConfigVersion.cmake} (65%) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 09:45:52 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 09:45:52 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-712-g96de370 Message-ID: <20160824134552.7B0E6F4ABC@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 96de37092a29cb2e7a92e9cb10b0ef47bca32732 (commit) via 7b637ebdc97655462d08d8ff70bee5d4f32e4681 (commit) via c2f561e58c799cc82df7db70710ae2f79b8b6b64 (commit) via 6b84df8da98169af43d4173dfbd1dedf5979dcb2 (commit) via d7d4083025f3007b862dd500c8f5fc64e105055b (commit) via b22294bc41c3ce62e561c7123c3f489a750dcb66 (commit) via b6a3102a9f8da05b50d4f4e96dd9f42ace37aa9b (commit) via d1e3cec2aa17a2f07f22c64c3bd29c765d69d9d2 (commit) via 504db72d99fc2302de605fd9c2f845c1b8865500 (commit) via fa6325782112063b5d425714a37c8ebd01b90d7c (commit) via 6299693f8aa5f5a61cec82215b73a2040a8d8603 (commit) via 29b51379de352980dd453243bea7ed37ed300c62 (commit) via 7d9b49fbdf55b28d2979af89a8192607df487ca1 (commit) via 4389664a26be4d1f96a55c34e5fac9ac1248e5f0 (commit) via 328191f65f7fb58ece6f749fbfc3462539c7afc1 (commit) via 9e032304ea4133dd6c59b2c0f3b686d4a7aac2a5 (commit) via fde59c4d882e104459dbdf8a07a22899427b6657 (commit) via 52b6effd817ae44577f86df4f382b0c98df7402a (commit) via 8e0cb45e5591cc778b054780f9e6290c3f239815 (commit) via d5e7d5f3ebb42e1a8b38e4bd30f717cdac81ed77 (commit) via 64be1ae4a3ae98e63cf35d495f0ca06c77cdf923 (commit) via 47866770cee381851ccc8070f64459909a838288 (commit) via 735f168bf08a4fdf1d9e245035d2dbcadbed652f (commit) via c148803a575ed1c3639123190b1d6a5d31578f34 (commit) from ccddb454b8e7ae3ae075db5fd3233ce86c8c70cb (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=96de37092a29cb2e7a92e9cb10b0ef47bca32732 commit 96de37092a29cb2e7a92e9cb10b0ef47bca32732 Merge: ccddb45 7b637eb Author: Brad King AuthorDate: Wed Aug 24 09:45:50 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 09:45:50 2016 -0400 Merge topic 'android-platform-modules' 7b637ebd Android: Add `ANDROID` variable to indicate the target c2f561e5 Android: Add test cases covering use of the NDK and standalone toolchains 6b84df8d Help: Document cross compiling for Android d7d40830 Android: Select the STL type for NDK builds b22294bc Android: Populate compiler flags for current ABI b6a3102a Android: Add a CMAKE_BUILD_TYPE default d1e3cec2 Android: Add Clang -target option for current ABI 504db72d Android: Add placeholders for compiler/abi-specific settings fa632578 Android: Avoid interfering with common pre-existing toolchain files 6299693f Android: Search for NDK and standalone toolchain in more places 29b51379 Android: Detect and save a standalone toolchain without the NDK 7d9b49fb Android: Detect settings from the CMAKE_SYSROOT if it is set 4389664a Android: Detect and save a toolchain from the NDK 328191f6 Android: Set CMAKE_SYSROOT automatically 9e032304 Android: Detect and save the architecture, ABI, and processor fde59c4d Android: Detect and save the API level ... ----------------------------------------------------------------------- Summary of changes: Help/manual/cmake-toolchains.7.rst | 204 ++++++++++++- Help/manual/cmake-variables.7.rst | 9 + Help/prop_tgt/ANDROID_API.rst | 9 +- Help/prop_tgt/ANDROID_ARCH.rst | 3 +- Help/prop_tgt/ANDROID_GUI.rst | 4 +- Help/prop_tgt/ANDROID_STL_TYPE.rst | 32 ++- Help/release/dev/android-platform-modules.rst | 5 + Help/variable/ANDROID.rst | 5 + Help/variable/CMAKE_ANDROID_API.rst | 10 +- Help/variable/CMAKE_ANDROID_ARCH.rst | 18 +- Help/variable/CMAKE_ANDROID_ARCH_ABI.rst | 17 ++ Help/variable/CMAKE_ANDROID_ARM_MODE.rst | 7 + Help/variable/CMAKE_ANDROID_ARM_NEON.rst | 6 + Help/variable/CMAKE_ANDROID_NDK.rst | 7 + .../CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION.rst | 13 + .../CMAKE_ANDROID_STANDALONE_TOOLCHAIN.rst | 6 + Help/variable/CMAKE_ANDROID_STL_TYPE.rst | 35 ++- .../CMAKE_LANG_ANDROID_TOOLCHAIN_PREFIX.rst | 11 + .../CMAKE_LANG_ANDROID_TOOLCHAIN_SUFFIX.rst | 7 + Modules/CMakeCCompiler.cmake.in | 1 + Modules/CMakeCXXCompiler.cmake.in | 1 + Modules/CMakeDetermineSystem.cmake | 1 + Modules/CMakeFortranCompiler.cmake.in | 2 + Modules/CMakeSystem.cmake.in | 2 +- Modules/Platform/Android-Clang-C.cmake | 2 + Modules/Platform/Android-Clang-CXX.cmake | 2 + Modules/Platform/Android-Clang.cmake | 52 ++++ Modules/Platform/Android-Common.cmake | 158 ++++++++++ Modules/Platform/Android-Determine-C.cmake | 2 + Modules/Platform/Android-Determine-CXX.cmake | 2 + Modules/Platform/Android-Determine.cmake | 301 ++++++++++++++++++++ Modules/Platform/Android-GNU-C.cmake | 2 + Modules/Platform/Android-GNU-CXX.cmake | 2 + Modules/Platform/Android-GNU.cmake | 43 +++ Modules/Platform/Android-Initialize.cmake | 51 ++++ Modules/Platform/Android.cmake | 2 + .../Platform/Android/Determine-Compiler-NDK.cmake | 256 +++++++++++++++++ .../Android/Determine-Compiler-Standalone.cmake | 69 +++++ Modules/Platform/Android/Determine-Compiler.cmake | 80 ++++++ Modules/Platform/Android/abi-arm64-v8a-Clang.cmake | 8 + Modules/Platform/Android/abi-arm64-v8a-GNU.cmake | 6 + Modules/Platform/Android/abi-armeabi-Clang.cmake | 20 ++ Modules/Platform/Android/abi-armeabi-GNU.cmake | 18 ++ .../Platform/Android/abi-armeabi-v6-Clang.cmake | 19 ++ Modules/Platform/Android/abi-armeabi-v6-GNU.cmake | 17 ++ .../Platform/Android/abi-armeabi-v7a-Clang.cmake | 29 ++ Modules/Platform/Android/abi-armeabi-v7a-GNU.cmake | 27 ++ Modules/Platform/Android/abi-common-Clang.cmake | 6 + Modules/Platform/Android/abi-common-GNU.cmake | 1 + Modules/Platform/Android/abi-common.cmake | 4 + Modules/Platform/Android/abi-mips-Clang.cmake | 8 + Modules/Platform/Android/abi-mips-GNU.cmake | 6 + Modules/Platform/Android/abi-mips64-Clang.cmake | 8 + Modules/Platform/Android/abi-mips64-GNU.cmake | 6 + Modules/Platform/Android/abi-x86-Clang.cmake | 8 + Modules/Platform/Android/abi-x86-GNU.cmake | 2 + Modules/Platform/Android/abi-x86_64-Clang.cmake | 8 + Modules/Platform/Android/abi-x86_64-GNU.cmake | 2 + Modules/Platform/Android/ndk-stl-c++.cmake | 13 + Modules/Platform/Android/ndk-stl-c++_shared.cmake | 4 + Modules/Platform/Android/ndk-stl-c++_static.cmake | 6 + Modules/Platform/Android/ndk-stl-gabi++.cmake | 7 + .../Platform/Android/ndk-stl-gabi++_shared.cmake | 4 + .../Platform/Android/ndk-stl-gabi++_static.cmake | 4 + Modules/Platform/Android/ndk-stl-gnustl.cmake | 9 + .../Platform/Android/ndk-stl-gnustl_shared.cmake | 4 + .../Platform/Android/ndk-stl-gnustl_static.cmake | 4 + Modules/Platform/Android/ndk-stl-none.cmake | 2 + Modules/Platform/Android/ndk-stl-stlport.cmake | 7 + .../Platform/Android/ndk-stl-stlport_shared.cmake | 4 + .../Platform/Android/ndk-stl-stlport_static.cmake | 4 + Modules/Platform/Android/ndk-stl-system.cmake | 6 + .../BadSYSROOT-result.txt} | 0 Tests/RunCMake/Android/BadSYSROOT-stderr.txt | 20 ++ .../RunCMake/Android/BadSYSROOT.cmake | 0 Tests/RunCMake/Android/CMakeLists.txt | 3 + Tests/RunCMake/Android/RunCMakeTest.cmake | 218 ++++++++++++++ Tests/RunCMake/Android/android.c | 6 + Tests/RunCMake/Android/android.cxx | 45 +++ Tests/RunCMake/Android/android.h | 103 +++++++ Tests/RunCMake/Android/common.cmake | 60 ++++ Tests/RunCMake/Android/ndk-arm64-v8a-stdout.txt | 2 + Tests/RunCMake/Android/ndk-arm64-v8a.cmake | 1 + Tests/RunCMake/Android/ndk-armeabi-arm-stdout.txt | 3 + Tests/RunCMake/Android/ndk-armeabi-arm.cmake | 1 + .../RunCMake/Android/ndk-armeabi-thumb-stdout.txt | 3 + Tests/RunCMake/Android/ndk-armeabi-thumb.cmake | 1 + .../Android/ndk-armeabi-v7a-neon-stdout.txt | 3 + Tests/RunCMake/Android/ndk-armeabi-v7a-neon.cmake | 1 + Tests/RunCMake/Android/ndk-armeabi-v7a-stdout.txt | 3 + Tests/RunCMake/Android/ndk-armeabi-v7a.cmake | 1 + .../ndk-badabi-result.txt} | 0 Tests/RunCMake/Android/ndk-badabi-stderr.txt | 5 + .../RunCMake/Android/ndk-badabi.cmake | 0 .../ndk-badarm-result.txt} | 0 Tests/RunCMake/Android/ndk-badarm-stderr.txt | 6 + .../RunCMake/Android/ndk-badarm.cmake | 0 .../ndk-badneon-result.txt} | 0 Tests/RunCMake/Android/ndk-badneon-stderr.txt | 6 + .../RunCMake/Android/ndk-badneon.cmake | 0 .../ndk-badstl-result.txt} | 0 Tests/RunCMake/Android/ndk-badstl-stderr.txt | 9 + Tests/RunCMake/Android/ndk-badstl.cmake | 1 + .../ndk-badver-result.txt} | 0 Tests/RunCMake/Android/ndk-badver-stderr.txt | 12 + Tests/RunCMake/Android/ndk-badver.cmake | 1 + .../ndk-badvernum-result.txt} | 0 Tests/RunCMake/Android/ndk-badvernum-stderr.txt | 13 + Tests/RunCMake/Android/ndk-badvernum.cmake | 1 + Tests/RunCMake/Android/ndk-mips-stdout.txt | 2 + Tests/RunCMake/Android/ndk-mips.cmake | 1 + Tests/RunCMake/Android/ndk-mips64-stdout.txt | 2 + Tests/RunCMake/Android/ndk-mips64.cmake | 1 + .../Android/ndk-sysroot-armeabi-stdout.txt | 1 + .../RunCMake/Android/ndk-sysroot-armeabi.cmake | 0 Tests/RunCMake/Android/ndk-x86-stdout.txt | 2 + Tests/RunCMake/Android/ndk-x86.cmake | 1 + Tests/RunCMake/Android/ndk-x86_64-stdout.txt | 2 + Tests/RunCMake/Android/ndk-x86_64.cmake | 1 + Tests/RunCMake/Android/standalone-stdout.txt | 1 + .../RunCMake/Android/standalone-sysroot-stdout.txt | 1 + .../RunCMake/Android/standalone-sysroot.cmake | 0 Tests/RunCMake/Android/standalone.cmake | 1 + Tests/RunCMake/CMakeLists.txt | 21 ++ 124 files changed, 2257 insertions(+), 28 deletions(-) create mode 100644 Help/release/dev/android-platform-modules.rst create mode 100644 Help/variable/ANDROID.rst create mode 100644 Help/variable/CMAKE_ANDROID_ARCH_ABI.rst create mode 100644 Help/variable/CMAKE_ANDROID_ARM_MODE.rst create mode 100644 Help/variable/CMAKE_ANDROID_ARM_NEON.rst create mode 100644 Help/variable/CMAKE_ANDROID_NDK.rst create mode 100644 Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION.rst create mode 100644 Help/variable/CMAKE_ANDROID_STANDALONE_TOOLCHAIN.rst create mode 100644 Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_PREFIX.rst create mode 100644 Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_SUFFIX.rst create mode 100644 Modules/Platform/Android-Clang-C.cmake create mode 100644 Modules/Platform/Android-Clang-CXX.cmake create mode 100644 Modules/Platform/Android-Clang.cmake create mode 100644 Modules/Platform/Android-Common.cmake create mode 100644 Modules/Platform/Android-Determine-C.cmake create mode 100644 Modules/Platform/Android-Determine-CXX.cmake create mode 100644 Modules/Platform/Android-Determine.cmake create mode 100644 Modules/Platform/Android-GNU-C.cmake create mode 100644 Modules/Platform/Android-GNU-CXX.cmake create mode 100644 Modules/Platform/Android-GNU.cmake create mode 100644 Modules/Platform/Android-Initialize.cmake create mode 100644 Modules/Platform/Android/Determine-Compiler-NDK.cmake create mode 100644 Modules/Platform/Android/Determine-Compiler-Standalone.cmake create mode 100644 Modules/Platform/Android/Determine-Compiler.cmake create mode 100644 Modules/Platform/Android/abi-arm64-v8a-Clang.cmake create mode 100644 Modules/Platform/Android/abi-arm64-v8a-GNU.cmake create mode 100644 Modules/Platform/Android/abi-armeabi-Clang.cmake create mode 100644 Modules/Platform/Android/abi-armeabi-GNU.cmake create mode 100644 Modules/Platform/Android/abi-armeabi-v6-Clang.cmake create mode 100644 Modules/Platform/Android/abi-armeabi-v6-GNU.cmake create mode 100644 Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake create mode 100644 Modules/Platform/Android/abi-armeabi-v7a-GNU.cmake create mode 100644 Modules/Platform/Android/abi-common-Clang.cmake create mode 100644 Modules/Platform/Android/abi-common-GNU.cmake create mode 100644 Modules/Platform/Android/abi-common.cmake create mode 100644 Modules/Platform/Android/abi-mips-Clang.cmake create mode 100644 Modules/Platform/Android/abi-mips-GNU.cmake create mode 100644 Modules/Platform/Android/abi-mips64-Clang.cmake create mode 100644 Modules/Platform/Android/abi-mips64-GNU.cmake create mode 100644 Modules/Platform/Android/abi-x86-Clang.cmake create mode 100644 Modules/Platform/Android/abi-x86-GNU.cmake create mode 100644 Modules/Platform/Android/abi-x86_64-Clang.cmake create mode 100644 Modules/Platform/Android/abi-x86_64-GNU.cmake create mode 100644 Modules/Platform/Android/ndk-stl-c++.cmake create mode 100644 Modules/Platform/Android/ndk-stl-c++_shared.cmake create mode 100644 Modules/Platform/Android/ndk-stl-c++_static.cmake create mode 100644 Modules/Platform/Android/ndk-stl-gabi++.cmake create mode 100644 Modules/Platform/Android/ndk-stl-gabi++_shared.cmake create mode 100644 Modules/Platform/Android/ndk-stl-gabi++_static.cmake create mode 100644 Modules/Platform/Android/ndk-stl-gnustl.cmake create mode 100644 Modules/Platform/Android/ndk-stl-gnustl_shared.cmake create mode 100644 Modules/Platform/Android/ndk-stl-gnustl_static.cmake create mode 100644 Modules/Platform/Android/ndk-stl-none.cmake create mode 100644 Modules/Platform/Android/ndk-stl-stlport.cmake create mode 100644 Modules/Platform/Android/ndk-stl-stlport_shared.cmake create mode 100644 Modules/Platform/Android/ndk-stl-stlport_static.cmake create mode 100644 Modules/Platform/Android/ndk-stl-system.cmake copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => Android/BadSYSROOT-result.txt} (100%) create mode 100644 Tests/RunCMake/Android/BadSYSROOT-stderr.txt copy Modules/IntelVSImplicitPath/hello.f => Tests/RunCMake/Android/BadSYSROOT.cmake (100%) create mode 100644 Tests/RunCMake/Android/CMakeLists.txt create mode 100644 Tests/RunCMake/Android/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/Android/android.c create mode 100644 Tests/RunCMake/Android/android.cxx create mode 100644 Tests/RunCMake/Android/android.h create mode 100644 Tests/RunCMake/Android/common.cmake create mode 100644 Tests/RunCMake/Android/ndk-arm64-v8a-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-arm64-v8a.cmake create mode 100644 Tests/RunCMake/Android/ndk-armeabi-arm-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-armeabi-arm.cmake create mode 100644 Tests/RunCMake/Android/ndk-armeabi-thumb-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-armeabi-thumb.cmake create mode 100644 Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-armeabi-v7a-neon.cmake create mode 100644 Tests/RunCMake/Android/ndk-armeabi-v7a-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-armeabi-v7a.cmake copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => Android/ndk-badabi-result.txt} (100%) create mode 100644 Tests/RunCMake/Android/ndk-badabi-stderr.txt copy Modules/IntelVSImplicitPath/hello.f => Tests/RunCMake/Android/ndk-badabi.cmake (100%) copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => Android/ndk-badarm-result.txt} (100%) create mode 100644 Tests/RunCMake/Android/ndk-badarm-stderr.txt copy Modules/IntelVSImplicitPath/hello.f => Tests/RunCMake/Android/ndk-badarm.cmake (100%) copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => Android/ndk-badneon-result.txt} (100%) create mode 100644 Tests/RunCMake/Android/ndk-badneon-stderr.txt copy Modules/IntelVSImplicitPath/hello.f => Tests/RunCMake/Android/ndk-badneon.cmake (100%) copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => Android/ndk-badstl-result.txt} (100%) create mode 100644 Tests/RunCMake/Android/ndk-badstl-stderr.txt create mode 100644 Tests/RunCMake/Android/ndk-badstl.cmake copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => Android/ndk-badver-result.txt} (100%) create mode 100644 Tests/RunCMake/Android/ndk-badver-stderr.txt create mode 100644 Tests/RunCMake/Android/ndk-badver.cmake copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => Android/ndk-badvernum-result.txt} (100%) create mode 100644 Tests/RunCMake/Android/ndk-badvernum-stderr.txt create mode 100644 Tests/RunCMake/Android/ndk-badvernum.cmake create mode 100644 Tests/RunCMake/Android/ndk-mips-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-mips.cmake create mode 100644 Tests/RunCMake/Android/ndk-mips64-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-mips64.cmake create mode 100644 Tests/RunCMake/Android/ndk-sysroot-armeabi-stdout.txt copy Modules/IntelVSImplicitPath/hello.f => Tests/RunCMake/Android/ndk-sysroot-armeabi.cmake (100%) create mode 100644 Tests/RunCMake/Android/ndk-x86-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-x86.cmake create mode 100644 Tests/RunCMake/Android/ndk-x86_64-stdout.txt create mode 100644 Tests/RunCMake/Android/ndk-x86_64.cmake create mode 100644 Tests/RunCMake/Android/standalone-stdout.txt create mode 100644 Tests/RunCMake/Android/standalone-sysroot-stdout.txt copy Modules/IntelVSImplicitPath/hello.f => Tests/RunCMake/Android/standalone-sysroot.cmake (100%) create mode 100644 Tests/RunCMake/Android/standalone.cmake hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 09:46:13 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 09:46:13 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1390-ge4ad8dc Message-ID: <20160824134613.62522F4ABC@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via e4ad8dc8cb379cd5875f079c6dea21fa89c79611 (commit) via 96de37092a29cb2e7a92e9cb10b0ef47bca32732 (commit) via ccddb454b8e7ae3ae075db5fd3233ce86c8c70cb (commit) via 4a2a66e31c4b7fbcc6bbe41219a6c7f0624dc165 (commit) via 21a7809bfaa02ec3d11620676636e65b47065b62 (commit) via 5c8b69b0f5408bb59a92ff3f061bd76efa773eff (commit) via 1d858dc017560b99206b542c42b2a7adaa344cb8 (commit) via 2986ca5ecc0120790c7fc8801647078f3475be18 (commit) via a71ca1f0b3a405e6ff1ea4b09badcc345581ddba (commit) from bbc5b5cbd9beeb0091fd8b07de4d4b2ef0b48f91 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e4ad8dc8cb379cd5875f079c6dea21fa89c79611 commit e4ad8dc8cb379cd5875f079c6dea21fa89c79611 Merge: bbc5b5c 96de370 Author: Brad King AuthorDate: Wed Aug 24 09:46:03 2016 -0400 Commit: Brad King CommitDate: Wed Aug 24 09:46:03 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 10:55:39 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 10:55:39 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1393-g89a08c9 Message-ID: <20160824145539.27BCFF57DD@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 89a08c97932ddd3f5083996a8fcc530ea88077aa (commit) via 7bc6dccc0a993ddb3681100e28405189be09ff72 (commit) via fcc532470aa56e7a2e345f7f2396774787feb2ce (commit) from e4ad8dc8cb379cd5875f079c6dea21fa89c79611 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=89a08c97932ddd3f5083996a8fcc530ea88077aa commit 89a08c97932ddd3f5083996a8fcc530ea88077aa Merge: e4ad8dc 7bc6dcc Author: Brad King AuthorDate: Wed Aug 24 10:55:38 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 10:55:38 2016 -0400 Merge topic 'update-kwsys' into next 7bc6dccc Merge branch 'upstream-KWSys' into update-kwsys fcc53247 KWSys 2016-08-24 (8e643b9b) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7bc6dccc0a993ddb3681100e28405189be09ff72 commit 7bc6dccc0a993ddb3681100e28405189be09ff72 Merge: 96de370 fcc5324 Author: Brad King AuthorDate: Wed Aug 24 10:55:19 2016 -0400 Commit: Brad King CommitDate: Wed Aug 24 10:55:19 2016 -0400 Merge branch 'upstream-KWSys' into update-kwsys * upstream-KWSys: KWSys 2016-08-24 (8e643b9b) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=fcc532470aa56e7a2e345f7f2396774787feb2ce commit fcc532470aa56e7a2e345f7f2396774787feb2ce Author: KWSys Upstream AuthorDate: Wed Aug 24 10:53:55 2016 -0400 Commit: Brad King CommitDate: Wed Aug 24 10:55:18 2016 -0400 KWSys 2016-08-24 (8e643b9b) Code extracted from: http://public.kitware.com/KWSys.git at commit 8e643b9b5f24d4cac68d59b1e2be9d161fb75974 (master). Upstream Shortlog ----------------- Brad King (1): 8e643b9b SystemTools: Fix crash in GetShortPath diff --git a/SystemTools.cxx b/SystemTools.cxx index eb2bec6..1a73b16 100644 --- a/SystemTools.cxx +++ b/SystemTools.cxx @@ -4725,8 +4725,11 @@ bool SystemTools::GetShortPath(const std::string& path, std::string& shortPath) std::wstring wtempPath = Encoding::ToWide(tempPath); DWORD ret = GetShortPathNameW(wtempPath.c_str(), NULL, 0); std::vector buffer(ret); - ret = GetShortPathNameW(wtempPath.c_str(), - &buffer[0], static_cast(buffer.size())); + if (ret != 0) + { + ret = GetShortPathNameW(wtempPath.c_str(), + &buffer[0], static_cast(buffer.size())); + } if (ret == 0) { ----------------------------------------------------------------------- Summary of changes: Source/kwsys/SystemTools.cxx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 10:59:10 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 10:59:10 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1395-gdbd8384 Message-ID: <20160824145910.50057F5850@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via dbd83843c85a8d6db2a41f4b12c0ad22162cb18e (commit) via 828e763260c257920d91037395c7f88e59243367 (commit) from 89a08c97932ddd3f5083996a8fcc530ea88077aa (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=dbd83843c85a8d6db2a41f4b12c0ad22162cb18e commit dbd83843c85a8d6db2a41f4b12c0ad22162cb18e Merge: 89a08c9 828e763 Author: Brad King AuthorDate: Wed Aug 24 10:59:09 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 10:59:09 2016 -0400 Merge topic 'test-RunCMake.CMP0040-fix' into next 828e7632 Tests: Fix RunCMake.CMP0040 custom command syntax https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=828e763260c257920d91037395c7f88e59243367 commit 828e763260c257920d91037395c7f88e59243367 Author: Brad King AuthorDate: Wed Aug 24 10:56:53 2016 -0400 Commit: Brad King CommitDate: Wed Aug 24 10:56:57 2016 -0400 Tests: Fix RunCMake.CMP0040 custom command syntax diff --git a/Tests/RunCMake/CMP0040/CMP0040-NEW-existing-target.cmake b/Tests/RunCMake/CMP0040/CMP0040-NEW-existing-target.cmake index f9c8afd..880b178 100644 --- a/Tests/RunCMake/CMP0040/CMP0040-NEW-existing-target.cmake +++ b/Tests/RunCMake/CMP0040/CMP0040-NEW-existing-target.cmake @@ -3,5 +3,5 @@ cmake_policy(SET CMP0040 NEW) add_library(foobar empty.cpp) add_custom_command(TARGET foobar PRE_BUILD - COMMAND "${CMAKE_COMMAND} -E echo hello world" + COMMAND ${CMAKE_COMMAND} -E echo hello world ) diff --git a/Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target.cmake b/Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target.cmake index 276863d..a9f764c 100644 --- a/Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target.cmake +++ b/Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target.cmake @@ -1,5 +1,5 @@ cmake_policy(SET CMP0040 NEW) add_custom_command(TARGET foobar PRE_BUILD - COMMAND "${CMAKE_COMMAND} -E hello world" + COMMAND ${CMAKE_COMMAND} -E hello world ) diff --git a/Tests/RunCMake/CMP0040/CMP0040-OLD-existing-target.cmake b/Tests/RunCMake/CMP0040/CMP0040-OLD-existing-target.cmake index d7ec50d..7a9e91e 100644 --- a/Tests/RunCMake/CMP0040/CMP0040-OLD-existing-target.cmake +++ b/Tests/RunCMake/CMP0040/CMP0040-OLD-existing-target.cmake @@ -3,5 +3,5 @@ cmake_policy(SET CMP0040 OLD) add_library(foobar empty.cpp) add_custom_command(TARGET foobar PRE_BUILD - COMMAND "${CMAKE_COMMAND} -E echo hello world" + COMMAND ${CMAKE_COMMAND} -E echo hello world ) diff --git a/Tests/RunCMake/CMP0040/CMP0040-OLD-missing-target.cmake b/Tests/RunCMake/CMP0040/CMP0040-OLD-missing-target.cmake index ef7a0f7..0f5cd15 100644 --- a/Tests/RunCMake/CMP0040/CMP0040-OLD-missing-target.cmake +++ b/Tests/RunCMake/CMP0040/CMP0040-OLD-missing-target.cmake @@ -1,5 +1,5 @@ cmake_policy(SET CMP0040 OLD) add_custom_command(TARGET foobar PRE_BUILD - COMMAND "${CMAKE_COMMAND} -E echo hello world" + COMMAND ${CMAKE_COMMAND} -E echo hello world ) diff --git a/Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target.cmake b/Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target.cmake index 2c3e401..4efeaae 100644 --- a/Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target.cmake +++ b/Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target.cmake @@ -1,4 +1,4 @@ add_custom_command(TARGET foobar PRE_BUILD - COMMAND "${CMAKE_COMMAND} -E hello world" + COMMAND ${CMAKE_COMMAND} -E hello world ) ----------------------------------------------------------------------- Summary of changes: Tests/RunCMake/CMP0040/CMP0040-NEW-existing-target.cmake | 2 +- Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target.cmake | 2 +- Tests/RunCMake/CMP0040/CMP0040-OLD-existing-target.cmake | 2 +- Tests/RunCMake/CMP0040/CMP0040-OLD-missing-target.cmake | 2 +- Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target.cmake | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 11:59:10 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 11:59:10 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1397-g05a67e9 Message-ID: <20160824155910.6F094F5477@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 05a67e9379ad46bae5a2146c1530f33d888590d3 (commit) via f699323ade84bb672ed0998de73c6f0333981bc1 (commit) from dbd83843c85a8d6db2a41f4b12c0ad22162cb18e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=05a67e9379ad46bae5a2146c1530f33d888590d3 commit 05a67e9379ad46bae5a2146c1530f33d888590d3 Merge: dbd8384 f699323 Author: Brad King AuthorDate: Wed Aug 24 11:59:09 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 11:59:09 2016 -0400 Merge topic 'intel-fortran-mod-diff' into next f699323a Fortran: Fix .mod file comparison for Intel 16 format https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f699323ade84bb672ed0998de73c6f0333981bc1 commit f699323ade84bb672ed0998de73c6f0333981bc1 Author: Brad King AuthorDate: Wed Aug 24 11:51:59 2016 -0400 Commit: Brad King CommitDate: Wed Aug 24 11:55:29 2016 -0400 Fortran: Fix .mod file comparison for Intel 16 format The Intel 16 format starts with the 0x0A 0x00 sequence that we use to skip past the timestamp. This occurrence appears to be a version number. Skip the first byte to avoid matching the sequence early. Ideally we should gain a better understanding of the format and avoid depending on short sequences that are likely to appear early by coincidence, but this approach will suffice for now. Closes: #16263 diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index 38e319d..4608b5a 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -677,6 +677,12 @@ bool cmDependsFortran::ModulesDiffer(const char* modFile, const char seq[2] = { '\n', '\0' }; const int seqlen = 2; + // Skip the leading byte which appears to be a version number. + // We do not need to check for an error because the sequence search + // below will fail in that case. + finModFile.get(); + finStampFile.get(); + if (!cmFortranStreamContainsSequence(finModFile, seq, seqlen)) { // The module is of unexpected format. Assume it is different. std::cerr << compilerId << " fortran module " << modFile ----------------------------------------------------------------------- Summary of changes: Source/cmDependsFortran.cxx | 6 ++++++ 1 file changed, 6 insertions(+) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 12:00:03 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 12:00:03 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-714-g86f1d70 Message-ID: <20160824160004.D8609F5494@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 86f1d70445f8a192fbc518cac83e0d6e8db70eef (commit) via fc552ce1c70e702d26508261090a07ebe1c426a1 (commit) from 96de37092a29cb2e7a92e9cb10b0ef47bca32732 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 12:00:05 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 12:00:05 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1400-g15d79ad Message-ID: <20160824160005.1CF07F5514@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 15d79ad650d39c88120c897c40dec40ef756948f (commit) via 86f1d70445f8a192fbc518cac83e0d6e8db70eef (commit) via fc552ce1c70e702d26508261090a07ebe1c426a1 (commit) from 05a67e9379ad46bae5a2146c1530f33d888590d3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=15d79ad650d39c88120c897c40dec40ef756948f commit 15d79ad650d39c88120c897c40dec40ef756948f Merge: 05a67e9 86f1d70 Author: Brad King AuthorDate: Wed Aug 24 11:59:48 2016 -0400 Commit: Brad King CommitDate: Wed Aug 24 11:59:48 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 12:00:05 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 12:00:05 -0400 (EDT) Subject: [Cmake-commits] CMake branch, release, updated. v3.6.1-22-gfc552ce Message-ID: <20160824160005.5B1EEF45FC@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, release has been updated via fc552ce1c70e702d26508261090a07ebe1c426a1 (commit) via a2d5c25a7a2b344ba7cf74d44c43bd6054263f59 (commit) from 7da3df3fb617f4fc87d7fbc672e4968120a2ca7b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- ----------------------------------------------------------------------- Summary of changes: Modules/GetPrerequisites.cmake | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 14:23:46 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 14:23:46 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1402-g6b3d7f6 Message-ID: <20160824182346.EF9A0F562E@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 6b3d7f642cab71d8ac0fa7fba01739d86d909ac3 (commit) via dcb2e39fda75ef20b950fe293bbc989e95adbdec (commit) from 15d79ad650d39c88120c897c40dec40ef756948f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6b3d7f642cab71d8ac0fa7fba01739d86d909ac3 commit 6b3d7f642cab71d8ac0fa7fba01739d86d909ac3 Merge: 15d79ad dcb2e39 Author: Brad King AuthorDate: Wed Aug 24 14:23:44 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 14:23:44 2016 -0400 Merge topic 'update-third-party-git-2.9' into next dcb2e39f update-third-party: support Git 2.9.0's new merge restrictions https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=dcb2e39fda75ef20b950fe293bbc989e95adbdec commit dcb2e39fda75ef20b950fe293bbc989e95adbdec Author: Ben Boeckel AuthorDate: Thu Jun 16 11:21:26 2016 -0400 Commit: Brad King CommitDate: Wed Aug 24 14:16:13 2016 -0400 update-third-party: support Git 2.9.0's new merge restrictions Use the `--allow-unrelated-histories` flag to declare that we Know What We're Doing? (but only if necessary). diff --git a/Utilities/Scripts/update-third-party.bash b/Utilities/Scripts/update-third-party.bash index 6aeeccd..3b8358e 100644 --- a/Utilities/Scripts/update-third-party.bash +++ b/Utilities/Scripts/update-third-party.bash @@ -155,8 +155,14 @@ popd if [ -n "$basehash" ]; then git merge --log -s recursive "-Xsubtree=$subtree/" --no-commit "upstream-$name" else + unrelated_histories_flag="" + if git merge --help | grep -q -e allow-unrelated-histories; then + unrelated_histories_flag="--allow-unrelated-histories " + fi + readonly unrelated_histories_flag + git fetch "$extractdir" "upstream-$name:upstream-$name" - git merge --log -s ours --no-commit "upstream-$name" + git merge --log -s ours --no-commit $unrelated_histories_flag "upstream-$name" git read-tree -u --prefix="$subtree/" "upstream-$name" fi git commit --no-edit ----------------------------------------------------------------------- Summary of changes: Utilities/Scripts/update-third-party.bash | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 14:23:58 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 14:23:58 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-716-g81c3e63 Message-ID: <20160824182358.04D9BF5666@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 81c3e637ccc135068a06fa3dc72f23733f003db5 (commit) via dcb2e39fda75ef20b950fe293bbc989e95adbdec (commit) from 86f1d70445f8a192fbc518cac83e0d6e8db70eef (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=81c3e637ccc135068a06fa3dc72f23733f003db5 commit 81c3e637ccc135068a06fa3dc72f23733f003db5 Merge: 86f1d70 dcb2e39 Author: Brad King AuthorDate: Wed Aug 24 14:23:56 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 14:23:56 2016 -0400 Merge topic 'update-third-party-git-2.9' dcb2e39f update-third-party: support Git 2.9.0's new merge restrictions ----------------------------------------------------------------------- Summary of changes: Utilities/Scripts/update-third-party.bash | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 14:24:12 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 14:24:12 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1404-g075c74e Message-ID: <20160824182412.E54F1F5680@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 075c74e6b33c652222d0c63fc35010c211a4caab (commit) via 81c3e637ccc135068a06fa3dc72f23733f003db5 (commit) from 6b3d7f642cab71d8ac0fa7fba01739d86d909ac3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=075c74e6b33c652222d0c63fc35010c211a4caab commit 075c74e6b33c652222d0c63fc35010c211a4caab Merge: 6b3d7f6 81c3e63 Author: Brad King AuthorDate: Wed Aug 24 14:24:06 2016 -0400 Commit: Brad King CommitDate: Wed Aug 24 14:24:06 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From steveire at gmail.com Wed Aug 24 15:20:13 2016 From: steveire at gmail.com (Stephen Kelly) Date: Wed, 24 Aug 2016 15:20:13 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1411-g873ec69 Message-ID: <20160824192013.965BEF5216@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 873ec699047784aa9072e8fb471aa597e573d084 (commit) via 1c66f23abbcf9c9cef4b72e601893336553bc186 (commit) via 29332a3ba6593ebc2406ffda9cbf6c9e3d33a875 (commit) via 2d315d2f59e3bbd4544cc33b718750f1f3a6cea5 (commit) via c37d2ef32fff9f9d991ef78905ed2097718489c1 (commit) via 850a4ae4abbb5d5a61862bd26bdc1e9ecdb3a6e6 (commit) via db7de303c2a1e35b672016833db4bf85148c98c2 (commit) from 075c74e6b33c652222d0c63fc35010c211a4caab (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=873ec699047784aa9072e8fb471aa597e573d084 commit 873ec699047784aa9072e8fb471aa597e573d084 Merge: 075c74e 1c66f23 Author: Stephen Kelly AuthorDate: Wed Aug 24 15:20:09 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 15:20:09 2016 -0400 Merge topic 'extract-cmMessenger' into next 1c66f23a Parser: Port away from cmMakefile 29332a3b cmMessenger: Extract from cmake class 2d315d2f cmMakefile: Port nested error logic away from cmExecutionStatus c37d2ef3 cmMakefile: Simplify IssueMessage implementation 850a4ae4 Parser: Issue messages through cmake, not cmSystemTools db7de303 Parser: Store the Backtrace for use in issuing messages https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1c66f23abbcf9c9cef4b72e601893336553bc186 commit 1c66f23abbcf9c9cef4b72e601893336553bc186 Author: Stephen Kelly AuthorDate: Thu Jan 28 22:10:28 2016 +0100 Commit: Stephen Kelly CommitDate: Wed Aug 24 20:37:32 2016 +0200 Parser: Port away from cmMakefile It is an unneeded dependency. diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 9204d14..39d9e97 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -12,7 +12,7 @@ #include "cmListFileCache.h" #include "cmListFileLexer.h" -#include "cmMakefile.h" +#include "cmMessenger.h" #include "cmOutputConverter.h" #include "cmSystemTools.h" #include "cmVersion.h" @@ -21,7 +21,8 @@ struct cmListFileParser { - cmListFileParser(cmListFile* lf, cmMakefile* mf, const char* filename); + cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt, + cmMessenger* messenger, const char* filename); ~cmListFileParser(); void IssueFileOpenError(std::string const& text) const; void IssueError(std::string const& text) const; @@ -30,8 +31,8 @@ struct cmListFileParser bool AddArgument(cmListFileLexer_Token* token, cmListFileArgument::Delimiter delim); cmListFile* ListFile; - cmMakefile* Makefile; cmListFileBacktrace Backtrace; + cmMessenger* Messenger; const char* FileName; cmListFileLexer* Lexer; cmListFileFunction Function; @@ -43,11 +44,12 @@ struct cmListFileParser } Separation; }; -cmListFileParser::cmListFileParser(cmListFile* lf, cmMakefile* mf, +cmListFileParser::cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt, + cmMessenger* messenger, const char* filename) : ListFile(lf) - , Makefile(mf) - , Backtrace(mf->GetBacktrace()) + , Backtrace(lfbt) + , Messenger(messenger) , FileName(filename) , Lexer(cmListFileLexer_New()) { @@ -60,7 +62,7 @@ cmListFileParser::~cmListFileParser() void cmListFileParser::IssueFileOpenError(const std::string& text) const { - this->Makefile->IssueMessage(cmake::FATAL_ERROR, text); + this->Messenger->IssueMessage(cmake::FATAL_ERROR, text, this->Backtrace); } void cmListFileParser::IssueError(const std::string& text) const @@ -70,8 +72,7 @@ void cmListFileParser::IssueError(const std::string& text) const lfc.Line = cmListFileLexer_GetCurrentLine(this->Lexer); cmListFileBacktrace lfbt = this->Backtrace; lfbt = lfbt.Push(lfc); - this->Makefile->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, text, - lfbt); + this->Messenger->IssueMessage(cmake::FATAL_ERROR, text, lfbt); cmSystemTools::SetFatalErrorOccured(); } @@ -129,7 +130,8 @@ bool cmListFileParser::ParseFile() return true; } -bool cmListFile::ParseFile(const char* filename, cmMakefile* mf) +bool cmListFile::ParseFile(const char* filename, cmMessenger* messenger, + cmListFileBacktrace const& lfbt) { if (!cmSystemTools::FileExists(filename) || cmSystemTools::FileIsDirectory(filename)) { @@ -139,7 +141,7 @@ bool cmListFile::ParseFile(const char* filename, cmMakefile* mf) bool parseError = false; { - cmListFileParser parser(this, mf, filename); + cmListFileParser parser(this, lfbt, messenger, filename); parseError = !parser.ParseFile(); } @@ -242,8 +244,7 @@ bool cmListFileParser::ParseFunction(const char* name, long line) lfbt = lfbt.Push(lfc); error << "Parse error. Function missing ending \")\". " << "End of file reached."; - this->Makefile->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, - error.str(), lfbt); + this->Messenger->IssueMessage(cmake::FATAL_ERROR, error.str(), lfbt); return false; } @@ -269,10 +270,10 @@ bool cmListFileParser::AddArgument(cmListFileLexer_Token* token, << "Argument not separated from preceding token by whitespace."; /* clang-format on */ if (isError) { - this->Makefile->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, m.str(), lfbt); + this->Messenger->IssueMessage(cmake::FATAL_ERROR, m.str(), lfbt); return false; } - this->Makefile->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING, m.str(), lfbt); + this->Messenger->IssueMessage(cmake::AUTHOR_WARNING, m.str(), lfbt); return true; } diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index f3e6f70..cd44536 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -23,7 +23,7 @@ * cmake list files. */ -class cmMakefile; +class cmMessenger; struct cmCommandContext { @@ -158,7 +158,8 @@ private: struct cmListFile { - bool ParseFile(const char* path, cmMakefile* mf); + bool ParseFile(const char* path, cmMessenger* messenger, + cmListFileBacktrace const& lfbt); std::vector Functions; }; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 6c83b06..6e47797 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -25,6 +25,7 @@ #include "cmGlobalGenerator.h" #include "cmInstallGenerator.h" #include "cmListFileCache.h" +#include "cmMessenger.h" #include "cmSourceFile.h" #include "cmSourceFileLocation.h" #include "cmState.h" @@ -457,7 +458,8 @@ bool cmMakefile::ReadDependentFile(const char* filename, bool noPolicyScope) IncludeScope incScope(this, filenametoread, noPolicyScope); cmListFile listFile; - if (!listFile.ParseFile(filenametoread.c_str(), this)) { + if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(), + this->Backtrace)) { return false; } @@ -506,7 +508,8 @@ bool cmMakefile::ReadListFile(const char* filename) ListFileScope scope(this, filenametoread); cmListFile listFile; - if (!listFile.ParseFile(filenametoread.c_str(), this)) { + if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(), + this->Backtrace)) { return false; } @@ -1452,7 +1455,8 @@ void cmMakefile::Configure() this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentStart.c_str()); cmListFile listFile; - if (!listFile.ParseFile(currentStart.c_str(), this)) { + if (!listFile.ParseFile(currentStart.c_str(), this->GetMessenger(), + this->Backtrace)) { return; } if (this->IsRootMakefile()) { @@ -3274,6 +3278,11 @@ cmake* cmMakefile::GetCMakeInstance() const return this->GlobalGenerator->GetCMakeInstance(); } +cmMessenger* cmMakefile::GetMessenger() const +{ + return this->GetCMakeInstance()->GetMessenger(); +} + cmGlobalGenerator* cmMakefile::GetGlobalGenerator() const { return this->GlobalGenerator; diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index d082964..b3587c5 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -607,6 +607,7 @@ public: * Get the instance */ cmake* GetCMakeInstance() const; + cmMessenger* GetMessenger() const; cmGlobalGenerator* GetGlobalGenerator() const; /** https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=29332a3ba6593ebc2406ffda9cbf6c9e3d33a875 commit 29332a3ba6593ebc2406ffda9cbf6c9e3d33a875 Author: Stephen Kelly AuthorDate: Thu Jan 28 22:10:27 2016 +0100 Commit: Stephen Kelly CommitDate: Wed Aug 24 20:37:25 2016 +0200 cmMessenger: Extract from cmake class This way messages can be issued independent of the cmake instance. It is now possible to make DisplayMessage a virtual interface and override it to handle messages in the cmake-gui or future IDE interaction interfaces. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index e63bf5a..3b94df7 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -319,6 +319,8 @@ set(SRCS cmMakefileExecutableTargetGenerator.cxx cmMakefileLibraryTargetGenerator.cxx cmMakefileUtilityTargetGenerator.cxx + cmMessenger.cxx + cmMessenger.h cmOSXBundleGenerator.cxx cmOSXBundleGenerator.h cmOutputConverter.cxx diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx index 080880b..c48910e 100644 --- a/Source/cmMessageCommand.cxx +++ b/Source/cmMessageCommand.cxx @@ -11,6 +11,8 @@ ============================================================================*/ #include "cmMessageCommand.h" +#include "cmMessenger.h" + // cmLibraryCommand bool cmMessageCommand::InitialPass(std::vector const& args, cmExecutionStatus&) @@ -65,8 +67,8 @@ bool cmMessageCommand::InitialPass(std::vector const& args, if (type != cmake::MESSAGE) { // we've overriden the message type, above, so display it directly - cmake* cm = this->Makefile->GetCMakeInstance(); - cm->DisplayMessage(type, message, this->Makefile->GetBacktrace()); + cmMessenger* m = this->Makefile->GetMessenger(); + m->DisplayMessage(type, message, this->Makefile->GetBacktrace()); } else { if (status) { this->Makefile->DisplayStatus(message.c_str(), -1); diff --git a/Source/cmMessenger.cxx b/Source/cmMessenger.cxx new file mode 100644 index 0000000..43fa150 --- /dev/null +++ b/Source/cmMessenger.cxx @@ -0,0 +1,209 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmMessenger.h" +#include "cmDocumentationFormatter.h" +#include "cmMessenger.h" +#include "cmOutputConverter.h" + +#if defined(CMAKE_BUILD_WITH_CMAKE) +#include +#endif + +cmake::MessageType cmMessenger::ConvertMessageType(cmake::MessageType t) const +{ + bool warningsAsErrors; + + if (t == cmake::AUTHOR_WARNING || t == cmake::AUTHOR_ERROR) { + warningsAsErrors = this->GetDevWarningsAsErrors(); + if (warningsAsErrors && t == cmake::AUTHOR_WARNING) { + t = cmake::AUTHOR_ERROR; + } else if (!warningsAsErrors && t == cmake::AUTHOR_ERROR) { + t = cmake::AUTHOR_WARNING; + } + } else if (t == cmake::DEPRECATION_WARNING || + t == cmake::DEPRECATION_ERROR) { + warningsAsErrors = this->GetDeprecatedWarningsAsErrors(); + if (warningsAsErrors && t == cmake::DEPRECATION_WARNING) { + t = cmake::DEPRECATION_ERROR; + } else if (!warningsAsErrors && t == cmake::DEPRECATION_ERROR) { + t = cmake::DEPRECATION_WARNING; + } + } + + return t; +} + +bool cmMessenger::IsMessageTypeVisible(cmake::MessageType t) const +{ + bool isVisible = true; + + if (t == cmake::DEPRECATION_ERROR) { + if (!this->GetDeprecatedWarningsAsErrors()) { + isVisible = false; + } + } else if (t == cmake::DEPRECATION_WARNING) { + if (this->GetSuppressDeprecatedWarnings()) { + isVisible = false; + } + } else if (t == cmake::AUTHOR_ERROR) { + if (!this->GetDevWarningsAsErrors()) { + isVisible = false; + } + } else if (t == cmake::AUTHOR_WARNING) { + if (this->GetSuppressDevWarnings()) { + isVisible = false; + } + } + + return isVisible; +} + +static bool printMessagePreamble(cmake::MessageType t, std::ostream& msg) +{ + // Construct the message header. + if (t == cmake::FATAL_ERROR) { + msg << "CMake Error"; + } else if (t == cmake::INTERNAL_ERROR) { + msg << "CMake Internal Error (please report a bug)"; + } else if (t == cmake::LOG) { + msg << "CMake Debug Log"; + } else if (t == cmake::DEPRECATION_ERROR) { + msg << "CMake Deprecation Error"; + } else if (t == cmake::DEPRECATION_WARNING) { + msg << "CMake Deprecation Warning"; + } else if (t == cmake::AUTHOR_WARNING) { + msg << "CMake Warning (dev)"; + } else if (t == cmake::AUTHOR_ERROR) { + msg << "CMake Error (dev)"; + } else { + msg << "CMake Warning"; + } + return true; +} + +void printMessageText(std::ostream& msg, std::string const& text) +{ + msg << ":\n"; + cmDocumentationFormatter formatter; + formatter.SetIndent(" "); + formatter.PrintFormatted(msg, text.c_str()); +} + +void displayMessage(cmake::MessageType t, std::ostringstream& msg) +{ + // Add a note about warning suppression. + if (t == cmake::AUTHOR_WARNING) { + msg << "This warning is for project developers. Use -Wno-dev to suppress " + "it."; + } else if (t == cmake::AUTHOR_ERROR) { + msg << "This error is for project developers. Use -Wno-error=dev to " + "suppress " + "it."; + } + + // Add a terminating blank line. + msg << "\n"; + +#if defined(CMAKE_BUILD_WITH_CMAKE) + // Add a C++ stack trace to internal errors. + if (t == cmake::INTERNAL_ERROR) { + std::string stack = cmsys::SystemInformation::GetProgramStack(0, 0); + if (!stack.empty()) { + if (cmHasLiteralPrefix(stack, "WARNING:")) { + stack = "Note:" + stack.substr(8); + } + msg << stack << "\n"; + } + } +#endif + + // Output the message. + if (t == cmake::FATAL_ERROR || t == cmake::INTERNAL_ERROR || + t == cmake::DEPRECATION_ERROR || t == cmake::AUTHOR_ERROR) { + cmSystemTools::SetErrorOccured(); + cmSystemTools::Message(msg.str().c_str(), "Error"); + } else { + cmSystemTools::Message(msg.str().c_str(), "Warning"); + } +} + +cmMessenger::cmMessenger(cmState* state) + : State(state) +{ +} + +void cmMessenger::IssueMessage(cmake::MessageType t, const std::string& text, + const cmListFileBacktrace& backtrace) const +{ + bool force = false; + if (!force) { + // override the message type, if needed, for warnings and errors + cmake::MessageType override = this->ConvertMessageType(t); + if (override != t) { + t = override; + force = true; + } + } + + if (!force && !this->IsMessageTypeVisible(t)) { + return; + } + this->DisplayMessage(t, text, backtrace); +} + +void cmMessenger::DisplayMessage(cmake::MessageType t, const std::string& text, + const cmListFileBacktrace& backtrace) const +{ + std::ostringstream msg; + if (!printMessagePreamble(t, msg)) { + return; + } + + // Add the immediate context. + backtrace.PrintTitle(msg); + + printMessageText(msg, text); + + // Add the rest of the context. + backtrace.PrintCallStack(msg); + + displayMessage(t, msg); +} + +bool cmMessenger::GetSuppressDevWarnings() const +{ + const char* cacheEntryValue = + this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_WARNINGS"); + return cmSystemTools::IsOn(cacheEntryValue); +} + +bool cmMessenger::GetSuppressDeprecatedWarnings() const +{ + const char* cacheEntryValue = + this->State->GetCacheEntryValue("CMAKE_WARN_DEPRECATED"); + return cacheEntryValue && cmSystemTools::IsOff(cacheEntryValue); +} + +bool cmMessenger::GetDevWarningsAsErrors() const +{ + const char* cacheEntryValue = + this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_ERRORS"); + return cacheEntryValue && cmSystemTools::IsOff(cacheEntryValue); +} + +bool cmMessenger::GetDeprecatedWarningsAsErrors() const +{ + const char* cacheEntryValue = + this->State->GetCacheEntryValue("CMAKE_ERROR_DEPRECATED"); + return cmSystemTools::IsOn(cacheEntryValue); +} diff --git a/Source/cmMessenger.h b/Source/cmMessenger.h new file mode 100644 index 0000000..f15bf13 --- /dev/null +++ b/Source/cmMessenger.h @@ -0,0 +1,44 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmMessenger_h +#define cmMessenger_h + +#include "cmListFileCache.h" +#include "cmState.h" +#include "cmake.h" + +class cmMessenger +{ +public: + cmMessenger(cmState* state); + + void IssueMessage( + cmake::MessageType t, std::string const& text, + cmListFileBacktrace const& backtrace = cmListFileBacktrace()) const; + + void DisplayMessage(cmake::MessageType t, std::string const& text, + cmListFileBacktrace const& backtrace) const; + + bool GetSuppressDevWarnings() const; + bool GetSuppressDeprecatedWarnings() const; + bool GetDevWarningsAsErrors() const; + bool GetDeprecatedWarningsAsErrors() const; + +private: + bool IsMessageTypeVisible(cmake::MessageType t) const; + cmake::MessageType ConvertMessageType(cmake::MessageType t) const; + + cmState* State; +}; + +#endif diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 74c3f71..701a5e5 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -19,6 +19,7 @@ #include "cmFileTimeComparison.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmMessenger.h" #include "cmSourceFile.h" #include "cmState.h" #include "cmTest.h" @@ -152,6 +153,7 @@ cmake::cmake() this->State = new cmState; this->CurrentSnapshot = this->State->CreateBaseSnapshot(); + this->Messenger = new cmMessenger(this->State); #ifdef __APPLE__ struct rlimit rlp; @@ -207,6 +209,7 @@ cmake::cmake() cmake::~cmake() { delete this->State; + delete this->Messenger; if (this->GlobalGenerator) { delete this->GlobalGenerator; this->GlobalGenerator = CM_NULLPTR; @@ -2281,160 +2284,10 @@ static bool cmakeCheckStampList(const char* stampList) return true; } -cmake::MessageType cmake::ConvertMessageType(cmake::MessageType t) const -{ - bool warningsAsErrors; - - if (t == cmake::AUTHOR_WARNING || t == cmake::AUTHOR_ERROR) { - warningsAsErrors = this->GetDevWarningsAsErrors(); - if (warningsAsErrors && t == cmake::AUTHOR_WARNING) { - t = cmake::AUTHOR_ERROR; - } else if (!warningsAsErrors && t == cmake::AUTHOR_ERROR) { - t = cmake::AUTHOR_WARNING; - } - } else if (t == cmake::DEPRECATION_WARNING || - t == cmake::DEPRECATION_ERROR) { - warningsAsErrors = this->GetDeprecatedWarningsAsErrors(); - if (warningsAsErrors && t == cmake::DEPRECATION_WARNING) { - t = cmake::DEPRECATION_ERROR; - } else if (!warningsAsErrors && t == cmake::DEPRECATION_ERROR) { - t = cmake::DEPRECATION_WARNING; - } - } - - return t; -} - -bool cmake::IsMessageTypeVisible(cmake::MessageType t) const -{ - bool isVisible = true; - - if (t == cmake::DEPRECATION_ERROR) { - if (!this->GetDeprecatedWarningsAsErrors()) { - isVisible = false; - } - } else if (t == cmake::DEPRECATION_WARNING) { - if (this->GetSuppressDeprecatedWarnings()) { - isVisible = false; - } - } else if (t == cmake::AUTHOR_ERROR) { - if (!this->GetDevWarningsAsErrors()) { - isVisible = false; - } - } else if (t == cmake::AUTHOR_WARNING) { - if (this->GetSuppressDevWarnings()) { - isVisible = false; - } - } - - return isVisible; -} - -static bool printMessagePreamble(cmake::MessageType t, std::ostream& msg) -{ - // Construct the message header. - if (t == cmake::FATAL_ERROR) { - msg << "CMake Error"; - } else if (t == cmake::INTERNAL_ERROR) { - msg << "CMake Internal Error (please report a bug)"; - } else if (t == cmake::LOG) { - msg << "CMake Debug Log"; - } else if (t == cmake::DEPRECATION_ERROR) { - msg << "CMake Deprecation Error"; - } else if (t == cmake::DEPRECATION_WARNING) { - msg << "CMake Deprecation Warning"; - } else if (t == cmake::AUTHOR_WARNING) { - msg << "CMake Warning (dev)"; - } else if (t == cmake::AUTHOR_ERROR) { - msg << "CMake Error (dev)"; - } else { - msg << "CMake Warning"; - } - return true; -} - -void printMessageText(std::ostream& msg, std::string const& text) -{ - msg << ":\n"; - cmDocumentationFormatter formatter; - formatter.SetIndent(" "); - formatter.PrintFormatted(msg, text.c_str()); -} - -void displayMessage(cmake::MessageType t, std::ostringstream& msg) -{ - - // Add a note about warning suppression. - if (t == cmake::AUTHOR_WARNING) { - msg << "This warning is for project developers. Use -Wno-dev to suppress " - "it."; - } else if (t == cmake::AUTHOR_ERROR) { - msg << "This error is for project developers. Use -Wno-error=dev to " - "suppress " - "it."; - } - - // Add a terminating blank line. - msg << "\n"; - -#if defined(CMAKE_BUILD_WITH_CMAKE) - // Add a C++ stack trace to internal errors. - if (t == cmake::INTERNAL_ERROR) { - std::string stack = cmsys::SystemInformation::GetProgramStack(0, 0); - if (!stack.empty()) { - if (cmHasLiteralPrefix(stack, "WARNING:")) { - stack = "Note:" + stack.substr(8); - } - msg << stack << "\n"; - } - } -#endif - - // Output the message. - if (t == cmake::FATAL_ERROR || t == cmake::INTERNAL_ERROR || - t == cmake::DEPRECATION_ERROR || t == cmake::AUTHOR_ERROR) { - cmSystemTools::SetErrorOccured(); - cmSystemTools::Message(msg.str().c_str(), "Error"); - } else { - cmSystemTools::Message(msg.str().c_str(), "Warning"); - } -} - void cmake::IssueMessage(cmake::MessageType t, std::string const& text, cmListFileBacktrace const& backtrace) const { - bool force = false; - // override the message type, if needed, for warnings and errors - cmake::MessageType override = this->ConvertMessageType(t); - if (override != t) { - t = override; - force = true; - } - - if (!force && !this->IsMessageTypeVisible(t)) { - return; - } - - this->DisplayMessage(t, text, backtrace); -} - -void cmake::DisplayMessage(cmake::MessageType t, std::string const& text, - cmListFileBacktrace const& backtrace) const -{ - std::ostringstream msg; - if (!printMessagePreamble(t, msg)) { - return; - } - - // Add the immediate context. - backtrace.PrintTitle(msg); - - printMessageText(msg, text); - - // Add the rest of the context. - backtrace.PrintCallStack(msg); - - displayMessage(t, msg); + this->Messenger->IssueMessage(t, text, backtrace); } std::vector cmake::GetDebugConfigs() @@ -2454,6 +2307,11 @@ std::vector cmake::GetDebugConfigs() return configs; } +cmMessenger* cmake::GetMessenger() const +{ + return this->Messenger; +} + int cmake::Build(const std::string& dir, const std::string& target, const std::string& config, const std::vector& nativeOptions, bool clean) @@ -2560,9 +2418,7 @@ void cmake::RunCheckForUnusedVariables() bool cmake::GetSuppressDevWarnings() const { - const char* cacheEntryValue = - this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_WARNINGS"); - return cmSystemTools::IsOn(cacheEntryValue); + return this->Messenger->GetSuppressDevWarnings(); } void cmake::SetSuppressDevWarnings(bool b) @@ -2586,9 +2442,7 @@ void cmake::SetSuppressDevWarnings(bool b) bool cmake::GetSuppressDeprecatedWarnings() const { - const char* cacheEntryValue = - this->State->GetCacheEntryValue("CMAKE_WARN_DEPRECATED"); - return cacheEntryValue && cmSystemTools::IsOff(cacheEntryValue); + return this->Messenger->GetSuppressDeprecatedWarnings(); } void cmake::SetSuppressDeprecatedWarnings(bool b) @@ -2612,9 +2466,7 @@ void cmake::SetSuppressDeprecatedWarnings(bool b) bool cmake::GetDevWarningsAsErrors() const { - const char* cacheEntryValue = - this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_ERRORS"); - return cacheEntryValue && cmSystemTools::IsOff(cacheEntryValue); + return this->Messenger->GetDevWarningsAsErrors(); } void cmake::SetDevWarningsAsErrors(bool b) @@ -2638,9 +2490,7 @@ void cmake::SetDevWarningsAsErrors(bool b) bool cmake::GetDeprecatedWarningsAsErrors() const { - const char* cacheEntryValue = - this->State->GetCacheEntryValue("CMAKE_ERROR_DEPRECATED"); - return cmSystemTools::IsOn(cacheEntryValue); + return this->Messenger->GetDeprecatedWarningsAsErrors(); } void cmake::SetDeprecatedWarningsAsErrors(bool b) diff --git a/Source/cmake.h b/Source/cmake.h index 343d371..dbe936b 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -25,6 +25,7 @@ class cmGlobalGeneratorFactory; class cmGlobalGenerator; class cmLocalGenerator; class cmMakefile; +class cmMessenger; class cmVariableWatch; class cmFileTimeComparison; class cmExternalMakefileProjectGeneratorFactory; @@ -346,6 +347,8 @@ public: return this->CMakeEditCommand; } + cmMessenger* GetMessenger() const; + /* * Get the state of the suppression of developer (author) warnings. * Returns false, by default, if developer warnings should be shown, true @@ -395,9 +398,6 @@ public: cmake::MessageType t, std::string const& text, cmListFileBacktrace const& backtrace = cmListFileBacktrace()) const; - void DisplayMessage(cmake::MessageType t, std::string const& text, - cmListFileBacktrace const& backtrace) const; - ///! run the --build option int Build(const std::string& dir, const std::string& target, const std::string& config, @@ -491,6 +491,7 @@ private: cmState* State; cmState::Snapshot CurrentSnapshot; + cmMessenger* Messenger; std::vector TraceOnlyThisSources; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2d315d2f59e3bbd4544cc33b718750f1f3a6cea5 commit 2d315d2f59e3bbd4544cc33b718750f1f3a6cea5 Author: Stephen Kelly AuthorDate: Thu Jan 28 22:10:29 2016 +0100 Commit: Stephen Kelly CommitDate: Wed Aug 24 20:37:25 2016 +0200 cmMakefile: Port nested error logic away from cmExecutionStatus It is no longer needed. diff --git a/Source/cmExecutionStatus.h b/Source/cmExecutionStatus.h index 508c6bd..8006514 100644 --- a/Source/cmExecutionStatus.h +++ b/Source/cmExecutionStatus.h @@ -38,16 +38,12 @@ public: this->ReturnInvoked = false; this->BreakInvoked = false; this->ContinueInvoked = false; - this->NestedError = false; } - void SetNestedError(bool val) { this->NestedError = val; } - bool GetNestedError() { return this->NestedError; } private: bool ReturnInvoked; bool BreakInvoked; bool ContinueInvoked; - bool NestedError; }; #endif diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index 40c54db..f0e4854 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -76,7 +76,7 @@ public: }; bool cmFunctionHelperCommand::InvokeInitialPass( - const std::vector& args, cmExecutionStatus& inStatus) + const std::vector& args, cmExecutionStatus&) { // Expand the argument list to the function. std::vector expandedArgs; @@ -129,11 +129,11 @@ bool cmFunctionHelperCommand::InvokeInitialPass( for (unsigned int c = 0; c < this->Functions.size(); ++c) { cmExecutionStatus status; if (!this->Makefile->ExecuteCommand(this->Functions[c], status) || - status.GetNestedError()) { + (cmSystemTools::GetErrorOccuredFlag() && + !cmSystemTools::GetFatalErrorOccured())) { // The error message should have already included the call stack // so we do not need to report an error here. functionScope.Quiet(); - inStatus.SetNestedError(true); return false; } if (status.GetReturnInvoked()) { diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index ee9dc8a..9d312ee 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -159,11 +159,11 @@ bool cmMacroHelperCommand::InvokeInitialPass( } cmExecutionStatus status; if (!this->Makefile->ExecuteCommand(newLFF, status) || - status.GetNestedError()) { + (cmSystemTools::GetErrorOccuredFlag() && + !cmSystemTools::GetFatalErrorOccured())) { // The error message should have already included the call stack // so we do not need to report an error here. macroScope.Quiet(); - inStatus.SetNestedError(true); return false; } if (status.GetReturnInvoked()) { diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index d299b8b..6c83b06 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -115,10 +115,6 @@ cmMakefile::~cmMakefile() void cmMakefile::IssueMessage(cmake::MessageType t, std::string const& text) const { - assert(!this->ExecutionStatusStack.empty()); - if ((t == cmake::FATAL_ERROR) || (t == cmake::INTERNAL_ERROR)) { - this->ExecutionStatusStack.back()->SetNestedError(true); - } this->GetCMakeInstance()->IssueMessage(t, text, this->GetBacktrace()); } @@ -279,11 +275,19 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, if (this->GetCMakeInstance()->GetTrace()) { this->PrintCommandTrace(lff); } - // Try invoking the command. + + bool hadPreviousNonFatalError = cmSystemTools::GetErrorOccuredFlag() && + !cmSystemTools::GetFatalErrorOccured(); + cmSystemTools::ResetErrorOccuredFlag(); + bool invokeSucceeded = pcmd->InvokeInitialPass(lff.Arguments, status); - bool hadNestedError = status.GetNestedError(); + bool hadNestedError = cmSystemTools::GetErrorOccuredFlag() && + !cmSystemTools::GetFatalErrorOccured(); + if (hadPreviousNonFatalError) { + cmSystemTools::SetErrorOccured(); + } if (!invokeSucceeded || hadNestedError) { - if (!hadNestedError) { + if (!hadNestedError && !cmSystemTools::GetFatalErrorOccured()) { // The command invocation requested that we report an error. this->IssueMessage(cmake::FATAL_ERROR, pcmd->GetError()); } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c37d2ef32fff9f9d991ef78905ed2097718489c1 commit c37d2ef32fff9f9d991ef78905ed2097718489c1 Author: Stephen Kelly AuthorDate: Thu Jan 28 22:10:28 2016 +0100 Commit: Stephen Kelly CommitDate: Wed Aug 24 20:37:25 2016 +0200 cmMakefile: Simplify IssueMessage implementation It is only called during configure time when the execution stack is non-empty. diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index b9d71ec..d299b8b 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -115,11 +115,9 @@ cmMakefile::~cmMakefile() void cmMakefile::IssueMessage(cmake::MessageType t, std::string const& text) const { - // Collect context information. - if (!this->ExecutionStatusStack.empty()) { - if ((t == cmake::FATAL_ERROR) || (t == cmake::INTERNAL_ERROR)) { - this->ExecutionStatusStack.back()->SetNestedError(true); - } + assert(!this->ExecutionStatusStack.empty()); + if ((t == cmake::FATAL_ERROR) || (t == cmake::INTERNAL_ERROR)) { + this->ExecutionStatusStack.back()->SetNestedError(true); } this->GetCMakeInstance()->IssueMessage(t, text, this->GetBacktrace()); } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=850a4ae4abbb5d5a61862bd26bdc1e9ecdb3a6e6 commit 850a4ae4abbb5d5a61862bd26bdc1e9ecdb3a6e6 Author: Stephen Kelly AuthorDate: Thu Jan 28 22:10:23 2016 +0100 Commit: Stephen Kelly CommitDate: Wed Aug 24 20:37:23 2016 +0200 Parser: Issue messages through cmake, not cmSystemTools Make these messages uniform with regard to other messages issued by cmake. diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 1a2ddaf..9204d14 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -24,6 +24,7 @@ struct cmListFileParser cmListFileParser(cmListFile* lf, cmMakefile* mf, const char* filename); ~cmListFileParser(); void IssueFileOpenError(std::string const& text) const; + void IssueError(std::string const& text) const; bool ParseFile(); bool ParseFunction(const char* name, long line); bool AddArgument(cmListFileLexer_Token* token, @@ -62,6 +63,18 @@ void cmListFileParser::IssueFileOpenError(const std::string& text) const this->Makefile->IssueMessage(cmake::FATAL_ERROR, text); } +void cmListFileParser::IssueError(const std::string& text) const +{ + cmListFileContext lfc; + lfc.FilePath = this->FileName; + lfc.Line = cmListFileLexer_GetCurrentLine(this->Lexer); + cmListFileBacktrace lfbt = this->Backtrace; + lfbt = lfbt.Push(lfc); + this->Makefile->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, text, + lfbt); + cmSystemTools::SetFatalErrorOccured(); +} + bool cmListFileParser::ParseFile() { // Open the file. @@ -98,22 +111,18 @@ bool cmListFileParser::ParseFile() } } else { std::ostringstream error; - error << "Error in cmake code at\n" - << this->FileName << ":" << token->line << ":\n" - << "Parse error. Expected a newline, got " + error << "Parse error. Expected a newline, got " << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) << " with text \"" << token->text << "\"."; - cmSystemTools::Error(error.str().c_str()); + this->IssueError(error.str()); return false; } } else { std::ostringstream error; - error << "Error in cmake code at\n" - << this->FileName << ":" << token->line << ":\n" - << "Parse error. Expected a command name, got " + error << "Parse error. Expected a command name, got " << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) << " with text \"" << token->text << "\"."; - cmSystemTools::Error(error.str().c_str()); + this->IssueError(error.str()); return false; } } @@ -156,18 +165,15 @@ bool cmListFileParser::ParseFunction(const char* name, long line) << cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n" << "Parse error. Function missing opening \"(\"."; /* clang-format on */ - cmSystemTools::Error(error.str().c_str()); + this->IssueError(error.str()); return false; } if (token->type != cmListFileLexer_Token_ParenLeft) { std::ostringstream error; - error << "Error in cmake code at\n" - << this->FileName << ":" - << cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n" - << "Parse error. Expected \"(\", got " + error << "Parse error. Expected \"(\", got " << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) << " with text \"" << token->text << "\"."; - cmSystemTools::Error(error.str().c_str()); + this->IssueError(error.str()); return false; } @@ -219,25 +225,25 @@ bool cmListFileParser::ParseFunction(const char* name, long line) } else { // Error. std::ostringstream error; - error << "Error in cmake code at\n" - << this->FileName << ":" - << cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n" - << "Parse error. Function missing ending \")\". " + error << "Parse error. Function missing ending \")\". " << "Instead found " << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) << " with text \"" << token->text << "\"."; - cmSystemTools::Error(error.str().c_str()); + this->IssueError(error.str()); return false; } } std::ostringstream error; - error << "Error in cmake code at\n" - << this->FileName << ":" << lastLine << ":\n" - << "Parse error. Function missing ending \")\". " + cmListFileContext lfc; + lfc.FilePath = this->FileName; + lfc.Line = lastLine; + cmListFileBacktrace lfbt = this->Backtrace; + lfbt = lfbt.Push(lfc); + error << "Parse error. Function missing ending \")\". " << "End of file reached."; - cmSystemTools::Error(error.str().c_str()); - + this->Makefile->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, + error.str(), lfbt); return false; } @@ -252,17 +258,21 @@ bool cmListFileParser::AddArgument(cmListFileLexer_Token* token, bool isError = (this->Separation == SeparationError || delim == cmListFileArgument::Bracket); std::ostringstream m; - /* clang-format off */ - m << "Syntax " << (isError? "Error":"Warning") << " in cmake code at\n" - << " " << this->FileName << ":" << token->line << ":" - << token->column << "\n" + cmListFileContext lfc; + lfc.FilePath = this->FileName; + lfc.Line = token->line; + cmListFileBacktrace lfbt = this->Backtrace; + lfbt = lfbt.Push(lfc); + + m << "Syntax " << (isError ? "Error" : "Warning") << " in cmake code at " + << "column " << token->column << "\n" << "Argument not separated from preceding token by whitespace."; /* clang-format on */ if (isError) { - this->Makefile->IssueMessage(cmake::FATAL_ERROR, m.str()); + this->Makefile->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, m.str(), lfbt); return false; } - this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, m.str()); + this->Makefile->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING, m.str(), lfbt); return true; } diff --git a/Tests/RunCMake/Syntax/BracketComment4-stderr.txt b/Tests/RunCMake/Syntax/BracketComment4-stderr.txt index 8ba32c2..6bbb980 100644 --- a/Tests/RunCMake/Syntax/BracketComment4-stderr.txt +++ b/Tests/RunCMake/Syntax/BracketComment4-stderr.txt @@ -1,7 +1,4 @@ -CMake Error: Error in cmake code at -.*/Tests/RunCMake/Syntax/BracketComment4.cmake:3: -Parse error. Expected a newline, got identifier with text "message". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: - - BracketComment4.cmake +CMake Error at BracketComment4.cmake:3: + Parse error. Expected a newline, got identifier with text "message". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/BracketNoSpace0-stderr.txt b/Tests/RunCMake/Syntax/BracketNoSpace0-stderr.txt index a288280..0a52022 100644 --- a/Tests/RunCMake/Syntax/BracketNoSpace0-stderr.txt +++ b/Tests/RunCMake/Syntax/BracketNoSpace0-stderr.txt @@ -1,7 +1,5 @@ -CMake Error in BracketNoSpace0.cmake: - Syntax Error in cmake code at - - .*/Tests/RunCMake/Syntax/BracketNoSpace0.cmake:1:27 +CMake Error at BracketNoSpace0.cmake:1: + Syntax Error in cmake code at column 27 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/BracketNoSpace1-stderr.txt b/Tests/RunCMake/Syntax/BracketNoSpace1-stderr.txt index 391e11b..43bf995 100644 --- a/Tests/RunCMake/Syntax/BracketNoSpace1-stderr.txt +++ b/Tests/RunCMake/Syntax/BracketNoSpace1-stderr.txt @@ -1,7 +1,5 @@ -CMake Error in BracketNoSpace1.cmake: - Syntax Error in cmake code at - - .*/Tests/RunCMake/Syntax/BracketNoSpace1.cmake:1:24 +CMake Error at BracketNoSpace1.cmake:1: + Syntax Error in cmake code at column 24 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/BracketNoSpace2-stderr.txt b/Tests/RunCMake/Syntax/BracketNoSpace2-stderr.txt index acaf7fe..f78b4bd 100644 --- a/Tests/RunCMake/Syntax/BracketNoSpace2-stderr.txt +++ b/Tests/RunCMake/Syntax/BracketNoSpace2-stderr.txt @@ -1,7 +1,5 @@ -CMake Error in BracketNoSpace2.cmake: - Syntax Error in cmake code at - - .*/Tests/RunCMake/Syntax/BracketNoSpace2.cmake:1:44 +CMake Error at BracketNoSpace2.cmake:1: + Syntax Error in cmake code at column 44 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/BracketNoSpace3-stderr.txt b/Tests/RunCMake/Syntax/BracketNoSpace3-stderr.txt index f12b2e5..63ca600 100644 --- a/Tests/RunCMake/Syntax/BracketNoSpace3-stderr.txt +++ b/Tests/RunCMake/Syntax/BracketNoSpace3-stderr.txt @@ -1,7 +1,5 @@ -CMake Error in BracketNoSpace3.cmake: - Syntax Error in cmake code at - - .*/Tests/RunCMake/Syntax/BracketNoSpace3.cmake:1:45 +CMake Error at BracketNoSpace3.cmake:1: + Syntax Error in cmake code at column 45 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/BracketNoSpace4-stderr.txt b/Tests/RunCMake/Syntax/BracketNoSpace4-stderr.txt index 7157763..318b0e3 100644 --- a/Tests/RunCMake/Syntax/BracketNoSpace4-stderr.txt +++ b/Tests/RunCMake/Syntax/BracketNoSpace4-stderr.txt @@ -1,7 +1,5 @@ -CMake Error in BracketNoSpace4.cmake: - Syntax Error in cmake code at - - .*/Tests/RunCMake/Syntax/BracketNoSpace4.cmake:1:44 +CMake Error at BracketNoSpace4.cmake:1: + Syntax Error in cmake code at column 44 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/BracketNoSpace5-stderr.txt b/Tests/RunCMake/Syntax/BracketNoSpace5-stderr.txt index c13969d..a68478a 100644 --- a/Tests/RunCMake/Syntax/BracketNoSpace5-stderr.txt +++ b/Tests/RunCMake/Syntax/BracketNoSpace5-stderr.txt @@ -1,7 +1,5 @@ -CMake Error in BracketNoSpace5.cmake: - Syntax Error in cmake code at - - .*/Tests/RunCMake/Syntax/BracketNoSpace5.cmake:1:45 +CMake Error at BracketNoSpace5.cmake:1: + Syntax Error in cmake code at column 45 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/CommandError0-stderr.txt b/Tests/RunCMake/Syntax/CommandError0-stderr.txt index 24d7997..e584fb0 100644 --- a/Tests/RunCMake/Syntax/CommandError0-stderr.txt +++ b/Tests/RunCMake/Syntax/CommandError0-stderr.txt @@ -1,8 +1,6 @@ -CMake Error: Error in cmake code at -.*/Tests/RunCMake/Syntax/CommandError0.cmake:2: -Parse error. Expected "\(", got newline with text " -". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: +CMake Error at CommandError0.cmake:2: + Parse error. Expected "\(", got newline with text " - CommandError0.cmake + ". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/CommandError1-stderr.txt b/Tests/RunCMake/Syntax/CommandError1-stderr.txt index 599f600..c3bf93c 100644 --- a/Tests/RunCMake/Syntax/CommandError1-stderr.txt +++ b/Tests/RunCMake/Syntax/CommandError1-stderr.txt @@ -1,7 +1,4 @@ -CMake Error: Error in cmake code at -.*/Tests/RunCMake/Syntax/CommandError1.cmake:1: -Parse error. Expected a newline, got identifier with text "message". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: - - CommandError1.cmake +CMake Error at CommandError1.cmake:1: + Parse error. Expected a newline, got identifier with text "message". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/CommandError2-stderr.txt b/Tests/RunCMake/Syntax/CommandError2-stderr.txt index f4dfc77..4fe28a9 100644 --- a/Tests/RunCMake/Syntax/CommandError2-stderr.txt +++ b/Tests/RunCMake/Syntax/CommandError2-stderr.txt @@ -1,7 +1,5 @@ -CMake Error: Error in cmake code at -.*/Tests/RunCMake/Syntax/CommandError2.cmake:1: -Parse error. Expected a command name, got bracket argument with text "oops-not-a-comment". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: - - CommandError2.cmake +CMake Error at CommandError2.cmake:1: + Parse error. Expected a command name, got bracket argument with text + "oops-not-a-comment". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/ParenInENV-stderr.txt b/Tests/RunCMake/Syntax/ParenInENV-stderr.txt index 37c5d6e..d7861e2 100644 --- a/Tests/RunCMake/Syntax/ParenInENV-stderr.txt +++ b/Tests/RunCMake/Syntax/ParenInENV-stderr.txt @@ -1,7 +1,5 @@ -CMake Warning \(dev\) in ParenInENV.cmake: - Syntax Warning in cmake code at - - .*/Tests/RunCMake/Syntax/ParenInENV.cmake:2:21 +CMake Warning \(dev\) at ParenInENV.cmake:2: + Syntax Warning in cmake code at column 21 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): @@ -11,7 +9,7 @@ This warning is for project developers. Use -Wno-dev to suppress it. CMake Error at ParenInENV.cmake:2 \(message\): Syntax error in cmake code at - .*/Tests/RunCMake/Syntax/ParenInENV.cmake:2 + .*Tests/RunCMake/Syntax/ParenInENV.cmake:2 when parsing string diff --git a/Tests/RunCMake/Syntax/ParenNoSpace1-stderr.txt b/Tests/RunCMake/Syntax/ParenNoSpace1-stderr.txt index 45b2e6a..7958249 100644 --- a/Tests/RunCMake/Syntax/ParenNoSpace1-stderr.txt +++ b/Tests/RunCMake/Syntax/ParenNoSpace1-stderr.txt @@ -1,27 +1,21 @@ -CMake Warning \(dev\) in ParenNoSpace1.cmake: - Syntax Warning in cmake code at - - .*/Tests/RunCMake/Syntax/ParenNoSpace1.cmake:1:26 +CMake Warning \(dev\) at ParenNoSpace1.cmake:1: + Syntax Warning in cmake code at column 26 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) This warning is for project developers. Use -Wno-dev to suppress it. -CMake Warning \(dev\) in ParenNoSpace1.cmake: - Syntax Warning in cmake code at - - .*/Tests/RunCMake/Syntax/ParenNoSpace1.cmake:2:26 +CMake Warning \(dev\) at ParenNoSpace1.cmake:2: + Syntax Warning in cmake code at column 26 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) This warning is for project developers. Use -Wno-dev to suppress it. -CMake Error in ParenNoSpace1.cmake: - Syntax Error in cmake code at - - .*/Tests/RunCMake/Syntax/ParenNoSpace1.cmake:3:29 +CMake Error at ParenNoSpace1.cmake:3: + Syntax Error in cmake code at column 29 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/StringNoSpace-stderr.txt b/Tests/RunCMake/Syntax/StringNoSpace-stderr.txt index a4ec6e7..817fcfa 100644 --- a/Tests/RunCMake/Syntax/StringNoSpace-stderr.txt +++ b/Tests/RunCMake/Syntax/StringNoSpace-stderr.txt @@ -1,17 +1,13 @@ -CMake Warning \(dev\) in StringNoSpace.cmake: - Syntax Warning in cmake code at - - .*/Tests/RunCMake/Syntax/StringNoSpace.cmake:2:28 +CMake Warning \(dev\) at StringNoSpace.cmake:2: + Syntax Warning in cmake code at column 28 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) This warning is for project developers. Use -Wno-dev to suppress it. -CMake Warning \(dev\) in StringNoSpace.cmake: - Syntax Warning in cmake code at - - .*/Tests/RunCMake/Syntax/StringNoSpace.cmake:2:31 +CMake Warning \(dev\) at StringNoSpace.cmake:2: + Syntax Warning in cmake code at column 31 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/UnterminatedBracket0-stderr.txt b/Tests/RunCMake/Syntax/UnterminatedBracket0-stderr.txt index 3559c18..2fca570 100644 --- a/Tests/RunCMake/Syntax/UnterminatedBracket0-stderr.txt +++ b/Tests/RunCMake/Syntax/UnterminatedBracket0-stderr.txt @@ -1,8 +1,5 @@ -CMake Error: Error in cmake code at -.*/Syntax/UnterminatedBracket0.cmake:2: -Parse error. Function missing ending "\)". Instead found unterminated bracket with text "\) -". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: +CMake Error at UnterminatedBracket0.cmake:2: + Parse error. Function missing ending "\)". Instead found unterminated + bracket with text "\) - UnterminatedBracket0.cmake$ + ". diff --git a/Tests/RunCMake/Syntax/UnterminatedBracket1-stderr.txt b/Tests/RunCMake/Syntax/UnterminatedBracket1-stderr.txt index 55d458b..86bfa2a 100644 --- a/Tests/RunCMake/Syntax/UnterminatedBracket1-stderr.txt +++ b/Tests/RunCMake/Syntax/UnterminatedBracket1-stderr.txt @@ -1,8 +1,7 @@ -CMake Error: Error in cmake code at -.*/Syntax/UnterminatedBracket1.cmake:2: -Parse error. Function missing ending "\)". Instead found unterminated bracket with text "\]\]\) -". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: +CMake Error at UnterminatedBracket1.cmake:2: + Parse error. Function missing ending "\)". Instead found unterminated + bracket with text "]]\) - UnterminatedBracket1.cmake$ + ". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/UnterminatedBracketComment-stderr.txt b/Tests/RunCMake/Syntax/UnterminatedBracketComment-stderr.txt index 0a799eb..4ec78a1 100644 --- a/Tests/RunCMake/Syntax/UnterminatedBracketComment-stderr.txt +++ b/Tests/RunCMake/Syntax/UnterminatedBracketComment-stderr.txt @@ -1,8 +1,7 @@ -CMake Error: Error in cmake code at -.*/Syntax/UnterminatedBracketComment.cmake:1: -Parse error. Expected a command name, got unterminated bracket with text "#\]\] -". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: +CMake Error at UnterminatedBracketComment.cmake:3: + Parse error. Expected a command name, got unterminated bracket with text + "#]] - UnterminatedBracketComment.cmake + ". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt b/Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt index 281ce0d..3f52244 100644 --- a/Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt +++ b/Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt @@ -1,7 +1,4 @@ -CMake Error: Error in cmake code at -.*/Syntax/UnterminatedCall1.cmake:2: -Parse error. Function missing ending "\)". End of file reached. -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: - - UnterminatedCall1.cmake +CMake Error at UnterminatedCall1.cmake:2: + Parse error. Function missing ending "\)". End of file reached. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt b/Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt index 065de30..18656f7 100644 --- a/Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt +++ b/Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt @@ -1,7 +1,4 @@ -CMake Error: Error in cmake code at -.*/Syntax/UnterminatedCall2.cmake:4: -Parse error. Function missing ending "\)". End of file reached. -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: - - UnterminatedCall2.cmake +CMake Error at UnterminatedCall2.cmake:4: + Parse error. Function missing ending "\)". End of file reached. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/UnterminatedString-stderr.txt b/Tests/RunCMake/Syntax/UnterminatedString-stderr.txt index d925032..79c3fd2 100644 --- a/Tests/RunCMake/Syntax/UnterminatedString-stderr.txt +++ b/Tests/RunCMake/Syntax/UnterminatedString-stderr.txt @@ -1,8 +1,7 @@ -CMake Error: Error in cmake code at -.*/Syntax/UnterminatedString.cmake:2: -Parse error. Function missing ending "\)". Instead found unterminated string with text "\) -". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: +CMake Error at UnterminatedString.cmake:2: + Parse error. Function missing ending "\)". Instead found unterminated + string with text "\) - UnterminatedString.cmake$ + ". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=db7de303c2a1e35b672016833db4bf85148c98c2 commit db7de303c2a1e35b672016833db4bf85148c98c2 Author: Stephen Kelly AuthorDate: Thu Jan 28 22:10:24 2016 +0100 Commit: Stephen Kelly CommitDate: Wed Aug 24 19:19:37 2016 +0200 Parser: Store the Backtrace for use in issuing messages diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 1967d2a..1a2ddaf 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -30,6 +30,7 @@ struct cmListFileParser cmListFileArgument::Delimiter delim); cmListFile* ListFile; cmMakefile* Makefile; + cmListFileBacktrace Backtrace; const char* FileName; cmListFileLexer* Lexer; cmListFileFunction Function; @@ -45,6 +46,7 @@ cmListFileParser::cmListFileParser(cmListFile* lf, cmMakefile* mf, const char* filename) : ListFile(lf) , Makefile(mf) + , Backtrace(mf->GetBacktrace()) , FileName(filename) , Lexer(cmListFileLexer_New()) { ----------------------------------------------------------------------- Summary of changes: Source/CMakeLists.txt | 2 + Source/cmExecutionStatus.h | 4 - Source/cmFunctionCommand.cxx | 6 +- Source/cmListFileCache.cxx | 89 +++++---- Source/cmListFileCache.h | 5 +- Source/cmMacroCommand.cxx | 4 +- Source/cmMakefile.cxx | 35 ++-- Source/cmMakefile.h | 1 + Source/cmMessageCommand.cxx | 6 +- Source/cmMessenger.cxx | 209 ++++++++++++++++++++ Source/cmMessenger.h | 44 +++++ Source/cmake.cxx | 176 ++--------------- Source/cmake.h | 7 +- Tests/RunCMake/Syntax/BracketComment4-stderr.txt | 11 +- Tests/RunCMake/Syntax/BracketNoSpace0-stderr.txt | 6 +- Tests/RunCMake/Syntax/BracketNoSpace1-stderr.txt | 6 +- Tests/RunCMake/Syntax/BracketNoSpace2-stderr.txt | 6 +- Tests/RunCMake/Syntax/BracketNoSpace3-stderr.txt | 6 +- Tests/RunCMake/Syntax/BracketNoSpace4-stderr.txt | 6 +- Tests/RunCMake/Syntax/BracketNoSpace5-stderr.txt | 6 +- Tests/RunCMake/Syntax/CommandError0-stderr.txt | 12 +- Tests/RunCMake/Syntax/CommandError1-stderr.txt | 11 +- Tests/RunCMake/Syntax/CommandError2-stderr.txt | 12 +- Tests/RunCMake/Syntax/ParenInENV-stderr.txt | 8 +- Tests/RunCMake/Syntax/ParenNoSpace1-stderr.txt | 18 +- Tests/RunCMake/Syntax/StringNoSpace-stderr.txt | 12 +- .../Syntax/UnterminatedBracket0-stderr.txt | 11 +- .../Syntax/UnterminatedBracket1-stderr.txt | 13 +- .../Syntax/UnterminatedBracketComment-stderr.txt | 13 +- Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt | 11 +- Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt | 11 +- .../RunCMake/Syntax/UnterminatedString-stderr.txt | 13 +- 32 files changed, 432 insertions(+), 348 deletions(-) create mode 100644 Source/cmMessenger.cxx create mode 100644 Source/cmMessenger.h hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 24 15:54:39 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 24 Aug 2016 15:54:39 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1413-g0ad6db5 Message-ID: <20160824195439.D5C5FF4111@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 0ad6db5d64d0a4554c57603f3e5be4c4d9ce2f7e (commit) via c6eb99abd626f42c980712ac9732eae0489149fa (commit) from 873ec699047784aa9072e8fb471aa597e573d084 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0ad6db5d64d0a4554c57603f3e5be4c4d9ce2f7e commit 0ad6db5d64d0a4554c57603f3e5be4c4d9ce2f7e Merge: 873ec69 c6eb99a Author: Brad King AuthorDate: Wed Aug 24 15:54:38 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 15:54:38 2016 -0400 Merge topic 'extract-cmMessenger' into next c6eb99ab fixup! Parser: Issue messages through cmake, not cmSystemTools https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c6eb99abd626f42c980712ac9732eae0489149fa commit c6eb99abd626f42c980712ac9732eae0489149fa Author: Brad King AuthorDate: Wed Aug 24 15:54:19 2016 -0400 Commit: Brad King CommitDate: Wed Aug 24 15:54:19 2016 -0400 fixup! Parser: Issue messages through cmake, not cmSystemTools diff --git a/Tests/RunCMake/Syntax/UnterminatedBracket0-stderr.txt b/Tests/RunCMake/Syntax/UnterminatedBracket0-stderr.txt index 2fca570..de33f7d 100644 --- a/Tests/RunCMake/Syntax/UnterminatedBracket0-stderr.txt +++ b/Tests/RunCMake/Syntax/UnterminatedBracket0-stderr.txt @@ -3,3 +3,5 @@ CMake Error at UnterminatedBracket0.cmake:2: bracket with text "\) ". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ----------------------------------------------------------------------- Summary of changes: Tests/RunCMake/Syntax/UnterminatedBracket0-stderr.txt | 2 ++ 1 file changed, 2 insertions(+) hooks/post-receive -- CMake From daniel at pfeifer-mail.de Wed Aug 24 16:02:47 2016 From: daniel at pfeifer-mail.de (Daniel Pfeifer) Date: Wed, 24 Aug 2016 16:02:47 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1415-ga035078 Message-ID: <20160824200247.EF010F58F8@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via a03507820e8b11bc65bd678433c173b92b3549f6 (commit) via 182a9161f714d4f122cc4c2d31abc0d795f2f9e4 (commit) from 0ad6db5d64d0a4554c57603f3e5be4c4d9ce2f7e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a03507820e8b11bc65bd678433c173b92b3549f6 commit a03507820e8b11bc65bd678433c173b92b3549f6 Merge: 0ad6db5 182a916 Author: Daniel Pfeifer AuthorDate: Wed Aug 24 16:02:45 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 16:02:45 2016 -0400 Merge topic 'include-what-you-use' into next 182a9161 CTest: fix include-what-you-use violations https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=182a9161f714d4f122cc4c2d31abc0d795f2f9e4 commit 182a9161f714d4f122cc4c2d31abc0d795f2f9e4 Author: Daniel Pfeifer AuthorDate: Wed Aug 24 22:01:40 2016 +0200 Commit: Daniel Pfeifer CommitDate: Wed Aug 24 22:02:22 2016 +0200 CTest: fix include-what-you-use violations diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx index 7baf7a3..413cada 100644 --- a/Source/CTest/cmCTestBZR.cxx +++ b/Source/CTest/cmCTestBZR.cxx @@ -12,12 +12,18 @@ #include "cmCTestBZR.h" #include "cmCTest.h" +#include "cmCTestVC.h" +#include "cmProcessTools.h" #include "cmSystemTools.h" #include "cmXMLParser.h" -#include - #include +#include +#include +#include +#include +#include +#include extern "C" int cmBZRXMLParserUnknownEncodingHandler(void* /*unused*/, const XML_Char* name, diff --git a/Source/CTest/cmCTestBZR.h b/Source/CTest/cmCTestBZR.h index 0f05d38..e2ee8b7 100644 --- a/Source/CTest/cmCTestBZR.h +++ b/Source/CTest/cmCTestBZR.h @@ -12,8 +12,15 @@ #ifndef cmCTestBZR_h #define cmCTestBZR_h +#include + #include "cmCTestGlobalVC.h" +#include +#include + +class cmCTest; + /** \class cmCTestBZR * \brief Interaction with bzr command-line tool * @@ -41,13 +48,14 @@ private: // Parsing helper classes. class InfoParser; - class RevnoParser; class LogParser; - class UpdateParser; + class RevnoParser; class StatusParser; + class UpdateParser; + friend class InfoParser; - friend class RevnoParser; friend class LogParser; + friend class RevnoParser; friend class UpdateParser; friend class StatusParser; }; diff --git a/Source/CTest/cmCTestBatchTestHandler.cxx b/Source/CTest/cmCTestBatchTestHandler.cxx index 70f84cb..bf4ead4 100644 --- a/Source/CTest/cmCTestBatchTestHandler.cxx +++ b/Source/CTest/cmCTestBatchTestHandler.cxx @@ -13,10 +13,14 @@ #include "cmCTestBatchTestHandler.h" #include "cmCTest.h" +#include "cmCTestMultiProcessHandler.h" +#include "cmCTestTestHandler.h" #include "cmProcess.h" -#include "cmStandardIncludes.h" #include "cmSystemTools.h" -#include + +#include +#include +#include cmCTestBatchTestHandler::~cmCTestBatchTestHandler() { diff --git a/Source/CTest/cmCTestBatchTestHandler.h b/Source/CTest/cmCTestBatchTestHandler.h index 17cc234..da10824 100644 --- a/Source/CTest/cmCTestBatchTestHandler.h +++ b/Source/CTest/cmCTestBatchTestHandler.h @@ -13,12 +13,11 @@ #ifndef cmCTestBatchTestHandler_h #define cmCTestBatchTestHandler_h -#include +#include #include -#include -#include #include +#include /** \class cmCTestBatchTestHandler * \brief run parallel ctest diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index 9dab98a..9da2848 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -17,7 +17,9 @@ #include "cmGlobalGenerator.h" #include "cmSystemTools.h" #include "cmake.h" + #include +#include cmCTestBuildAndTestHandler::cmCTestBuildAndTestHandler() { diff --git a/Source/CTest/cmCTestBuildAndTestHandler.h b/Source/CTest/cmCTestBuildAndTestHandler.h index 2aa90a4..f917fb0 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.h +++ b/Source/CTest/cmCTestBuildAndTestHandler.h @@ -13,8 +13,15 @@ #ifndef cmCTestBuildAndTestHandler_h #define cmCTestBuildAndTestHandler_h +#include + #include "cmCTestGenericHandler.h" -#include "cmListFileCache.h" +#include "cmTypeMacro.h" + +#include +#include +#include +#include class cmake; diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx index 408a1a8..91603d7 100644 --- a/Source/CTest/cmCTestBuildCommand.cxx +++ b/Source/CTest/cmCTestBuildCommand.cxx @@ -15,8 +15,15 @@ #include "cmCTestBuildHandler.h" #include "cmCTestGenericHandler.h" #include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" #include "cmake.h" +#include +#include + +class cmExecutionStatus; + cmCTestBuildCommand::cmCTestBuildCommand() { this->GlobalGenerator = CM_NULLPTR; diff --git a/Source/CTest/cmCTestBuildCommand.h b/Source/CTest/cmCTestBuildCommand.h index 92ae216..393c66e 100644 --- a/Source/CTest/cmCTestBuildCommand.h +++ b/Source/CTest/cmCTestBuildCommand.h @@ -12,10 +12,19 @@ #ifndef cmCTestBuildCommand_h #define cmCTestBuildCommand_h +#include + #include "cmCTestHandlerCommand.h" +#include "cmTypeMacro.h" + +#include +#include -class cmGlobalGenerator; class cmCTestBuildHandler; +class cmCTestGenericHandler; +class cmCommand; +class cmExecutionStatus; +class cmGlobalGenerator; /** \class cmCTestBuild * \brief Run a ctest script diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index 230e8c5..cdf292c 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -16,25 +16,16 @@ #include "cmCTest.h" #include "cmFileTimeComparison.h" #include "cmGeneratedFileStream.h" -#include "cmGlobalGenerator.h" #include "cmMakefile.h" +#include "cmSystemTools.h" #include "cmXMLWriter.h" -#include "cmake.h" -//#include #include #include #include - -// used for sleep -#ifdef _WIN32 -#include "windows.h" -#endif - -#include -#include +#include #include -#include +#include static const char* cmCTestErrorMatches[] = { "^[Bb]us [Ee]rror", diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h index 8cc5f01..764dfed 100644 --- a/Source/CTest/cmCTestBuildHandler.h +++ b/Source/CTest/cmCTestBuildHandler.h @@ -13,13 +13,17 @@ #ifndef cmCTestBuildHandler_h #define cmCTestBuildHandler_h -#include "cmCTestGenericHandler.h" +#include -#include "cmListFileCache.h" +#include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" #include - #include +#include +#include +#include +#include class cmMakefile; class cmXMLWriter; @@ -148,6 +152,7 @@ private: bool UseCTestLaunch; std::string CTestLaunchDir; class LaunchHelper; + friend class LaunchHelper; class FragmentCompare; }; diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx index fb96308..64054d3 100644 --- a/Source/CTest/cmCTestCVS.cxx +++ b/Source/CTest/cmCTestCVS.cxx @@ -12,11 +12,13 @@ #include "cmCTestCVS.h" #include "cmCTest.h" +#include "cmProcessTools.h" #include "cmSystemTools.h" #include "cmXMLWriter.h" #include #include +#include cmCTestCVS::cmCTestCVS(cmCTest* ct, std::ostream& log) : cmCTestVC(ct, log) diff --git a/Source/CTest/cmCTestCVS.h b/Source/CTest/cmCTestCVS.h index 67d162d..c1450b1 100644 --- a/Source/CTest/cmCTestCVS.h +++ b/Source/CTest/cmCTestCVS.h @@ -12,11 +12,18 @@ #ifndef cmCTestCVS_h #define cmCTestCVS_h +#include + #include "cmCTestVC.h" +#include #include +#include #include +class cmCTest; +class cmXMLWriter; + /** \class cmCTestCVS * \brief Interaction with cvs command-line tool * @@ -47,10 +54,11 @@ private: Directory const& dir); // Parsing helper classes. - class UpdateParser; class LogParser; - friend class UpdateParser; + class UpdateParser; + friend class LogParser; + friend class UpdateParser; }; #endif diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx index a823704..98e38d3 100644 --- a/Source/CTest/cmCTestConfigureCommand.cxx +++ b/Source/CTest/cmCTestConfigureCommand.cxx @@ -14,6 +14,13 @@ #include "cmCTest.h" #include "cmCTestGenericHandler.h" #include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" +#include "cmake.h" + +#include +#include +#include cmCTestConfigureCommand::cmCTestConfigureCommand() { diff --git a/Source/CTest/cmCTestConfigureCommand.h b/Source/CTest/cmCTestConfigureCommand.h index a97f9f0..9027b6b 100644 --- a/Source/CTest/cmCTestConfigureCommand.h +++ b/Source/CTest/cmCTestConfigureCommand.h @@ -12,7 +12,15 @@ #ifndef cmCTestConfigureCommand_h #define cmCTestConfigureCommand_h +#include + #include "cmCTestHandlerCommand.h" +#include "cmTypeMacro.h" + +#include + +class cmCTestGenericHandler; +class cmCommand; /** \class cmCTestConfigure * \brief Run a ctest script diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx index b99455f..78fa910 100644 --- a/Source/CTest/cmCTestConfigureHandler.cxx +++ b/Source/CTest/cmCTestConfigureHandler.cxx @@ -14,9 +14,11 @@ #include "cmCTest.h" #include "cmGeneratedFileStream.h" +#include "cmSystemTools.h" #include "cmXMLWriter.h" -#include "cmake.h" -#include + +#include +#include cmCTestConfigureHandler::cmCTestConfigureHandler() { diff --git a/Source/CTest/cmCTestConfigureHandler.h b/Source/CTest/cmCTestConfigureHandler.h index a7de939..a7d2167 100644 --- a/Source/CTest/cmCTestConfigureHandler.h +++ b/Source/CTest/cmCTestConfigureHandler.h @@ -13,9 +13,10 @@ #ifndef cmCTestConfigureHandler_h #define cmCTestConfigureHandler_h -#include "cmCTestGenericHandler.h" +#include -#include "cmListFileCache.h" +#include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" /** \class cmCTestConfigureHandler * \brief A class that handles ctest -S invocations diff --git a/Source/CTest/cmCTestCoverageCommand.cxx b/Source/CTest/cmCTestCoverageCommand.cxx index 86e3ce4..7a4271e 100644 --- a/Source/CTest/cmCTestCoverageCommand.cxx +++ b/Source/CTest/cmCTestCoverageCommand.cxx @@ -14,6 +14,8 @@ #include "cmCTest.h" #include "cmCTestCoverageHandler.h" +class cmCTestGenericHandler; + cmCTestCoverageCommand::cmCTestCoverageCommand() { this->LabelsMentioned = false; diff --git a/Source/CTest/cmCTestCoverageCommand.h b/Source/CTest/cmCTestCoverageCommand.h index ffd5fec..b9ef53d 100644 --- a/Source/CTest/cmCTestCoverageCommand.h +++ b/Source/CTest/cmCTestCoverageCommand.h @@ -12,7 +12,16 @@ #ifndef cmCTestCoverageCommand_h #define cmCTestCoverageCommand_h +#include + #include "cmCTestHandlerCommand.h" +#include "cmTypeMacro.h" + +#include +#include + +class cmCTestGenericHandler; +class cmCommand; /** \class cmCTestCoverage * \brief Run a ctest script diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index dd6eb3a..2eb64bf 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -13,7 +13,6 @@ #include "cmCTest.h" #include "cmGeneratedFileStream.h" -#include "cmMakefile.h" #include "cmParseBlanketJSCoverage.h" #include "cmParseCacheCoverage.h" #include "cmParseCoberturaCoverage.h" @@ -25,14 +24,19 @@ #include "cmXMLWriter.h" #include "cmake.h" +#include #include #include #include #include - -#include -#include +#include +#include +#include +#include #include +#include + +class cmMakefile; #define SAFEDIV(x, y) (((y) != 0) ? ((x) / (y)) : (0)) diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h index 60fea48..12a7e19 100644 --- a/Source/CTest/cmCTestCoverageHandler.h +++ b/Source/CTest/cmCTestCoverageHandler.h @@ -13,14 +13,22 @@ #ifndef cmCTestCoverageHandler_h #define cmCTestCoverageHandler_h -#include "cmCTestGenericHandler.h" +#include -#include "cmListFileCache.h" +#include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" #include +#include +#include +#include +#include +#include class cmGeneratedFileStream; +class cmMakefile; class cmXMLWriter; + class cmCTestCoverageHandlerContainer { public: diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx index 6910f6f..941df29 100644 --- a/Source/CTest/cmCTestCurl.cxx +++ b/Source/CTest/cmCTestCurl.cxx @@ -14,6 +14,10 @@ #include "cmCTest.h" #include "cmSystemTools.h" +#include +#include +#include + cmCTestCurl::cmCTestCurl(cmCTest* ctest) { this->CTest = ctest; diff --git a/Source/CTest/cmCTestCurl.h b/Source/CTest/cmCTestCurl.h index 82601e3..c91c88c 100644 --- a/Source/CTest/cmCTestCurl.h +++ b/Source/CTest/cmCTestCurl.h @@ -12,9 +12,11 @@ #ifndef cmCTestCurl_h #define cmCTestCurl_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep -#include "cm_curl.h" +#include +#include +#include class cmCTest; diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx index 09ae1fc..cc0b013 100644 --- a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx +++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx @@ -13,6 +13,10 @@ #include "cmCTestScriptHandler.h" +#include + +class cmExecutionStatus; + bool cmCTestEmptyBinaryDirectoryCommand::InitialPass( std::vector const& args, cmExecutionStatus& /*unused*/) { diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h index acacbcb..a64e55a 100644 --- a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h +++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h @@ -12,7 +12,16 @@ #ifndef cmCTestEmptyBinaryDirectoryCommand_h #define cmCTestEmptyBinaryDirectoryCommand_h +#include + #include "cmCTestCommand.h" +#include "cmTypeMacro.h" + +#include +#include + +class cmCommand; +class cmExecutionStatus; /** \class cmCTestEmptyBinaryDirectory * \brief Run a ctest script diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx index 61dbe33..cec871f 100644 --- a/Source/CTest/cmCTestGIT.cxx +++ b/Source/CTest/cmCTestGIT.cxx @@ -13,15 +13,17 @@ #include "cmAlgorithms.h" #include "cmCTest.h" +#include "cmCTestVC.h" +#include "cmProcessTools.h" #include "cmSystemTools.h" #include #include -#include - #include -#include +#include +#include #include +#include static unsigned int cmCTestGITVersion(unsigned int epic, unsigned int major, unsigned int minor, unsigned int fix) diff --git a/Source/CTest/cmCTestGIT.h b/Source/CTest/cmCTestGIT.h index 85298cb..d61d155 100644 --- a/Source/CTest/cmCTestGIT.h +++ b/Source/CTest/cmCTestGIT.h @@ -12,8 +12,15 @@ #ifndef cmCTestGIT_h #define cmCTestGIT_h +#include + #include "cmCTestGlobalVC.h" +#include +#include + +class cmCTest; + /** \class cmCTestGIT * \brief Interaction with git command-line tool * @@ -47,12 +54,13 @@ private: // "public" needed by older Sun compilers public: // Parsing helper classes. - class OneLineParser; - class DiffParser; class CommitParser; - friend class OneLineParser; - friend class DiffParser; + class DiffParser; + class OneLineParser; + friend class CommitParser; + friend class DiffParser; + friend class OneLineParser; }; #endif diff --git a/Source/CTest/cmCTestGenericHandler.cxx b/Source/CTest/cmCTestGenericHandler.cxx index 7755ee9..aab1781 100644 --- a/Source/CTest/cmCTestGenericHandler.cxx +++ b/Source/CTest/cmCTestGenericHandler.cxx @@ -12,9 +12,11 @@ #include "cmCTestGenericHandler.h" +#include "cmCTest.h" #include "cmSystemTools.h" -#include "cmCTest.h" +#include +#include cmCTestGenericHandler::cmCTestGenericHandler() { diff --git a/Source/CTest/cmCTestGenericHandler.h b/Source/CTest/cmCTestGenericHandler.h index 9949c3a..88905ed 100644 --- a/Source/CTest/cmCTestGenericHandler.h +++ b/Source/CTest/cmCTestGenericHandler.h @@ -13,14 +13,20 @@ #ifndef cmCTestGenericHandler_h #define cmCTestGenericHandler_h -#include "cmObject.h" +#include #include "cmCTest.h" -#include "cmSystemTools.h" //OutputOption +#include "cmObject.h" +#include "cmSystemTools.h" + +#include +#include +#include +#include -class cmMakefile; class cmCTestCommand; class cmGeneratedFileStream; +class cmMakefile; /** \class cmCTestGenericHandler * \brief A superclass of all CTest Handlers diff --git a/Source/CTest/cmCTestGlobalVC.cxx b/Source/CTest/cmCTestGlobalVC.cxx index 0c7ca4d..c575853 100644 --- a/Source/CTest/cmCTestGlobalVC.cxx +++ b/Source/CTest/cmCTestGlobalVC.cxx @@ -15,7 +15,8 @@ #include "cmSystemTools.h" #include "cmXMLWriter.h" -#include +#include +#include cmCTestGlobalVC::cmCTestGlobalVC(cmCTest* ct, std::ostream& log) : cmCTestVC(ct, log) diff --git a/Source/CTest/cmCTestGlobalVC.h b/Source/CTest/cmCTestGlobalVC.h index d42d2f2..b48b835 100644 --- a/Source/CTest/cmCTestGlobalVC.h +++ b/Source/CTest/cmCTestGlobalVC.h @@ -12,12 +12,19 @@ #ifndef cmCTestGlobalVC_h #define cmCTestGlobalVC_h +#include + #include "cmCTestVC.h" +#include #include #include +#include #include +class cmCTest; +class cmXMLWriter; + /** \class cmCTestGlobalVC * \brief Base class for handling globally-versioned trees * diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx index 3e62a1a..c576cf0 100644 --- a/Source/CTest/cmCTestHG.cxx +++ b/Source/CTest/cmCTestHG.cxx @@ -12,10 +12,14 @@ #include "cmCTestHG.h" #include "cmCTest.h" +#include "cmCTestVC.h" +#include "cmProcessTools.h" #include "cmSystemTools.h" #include "cmXMLParser.h" #include +#include +#include cmCTestHG::cmCTestHG(cmCTest* ct, std::ostream& log) : cmCTestGlobalVC(ct, log) diff --git a/Source/CTest/cmCTestHG.h b/Source/CTest/cmCTestHG.h index c4ce08c..08b479c 100644 --- a/Source/CTest/cmCTestHG.h +++ b/Source/CTest/cmCTestHG.h @@ -12,8 +12,15 @@ #ifndef cmCTestHG_h #define cmCTestHG_h +#include + #include "cmCTestGlobalVC.h" +#include +#include + +class cmCTest; + /** \class cmCTestHG * \brief Interaction with Mercurial command-line tool * @@ -37,11 +44,12 @@ private: // Parsing helper classes. class IdentifyParser; - class StatusParser; class LogParser; + class StatusParser; + friend class IdentifyParser; - friend class StatusParser; friend class LogParser; + friend class StatusParser; }; #endif diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index 325f8a3..e8e2956 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -13,6 +13,14 @@ #include "cmCTest.h" #include "cmCTestGenericHandler.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" +#include "cmake.h" + +#include +#include + +class cmExecutionStatus; cmCTestHandlerCommand::cmCTestHandlerCommand() { diff --git a/Source/CTest/cmCTestHandlerCommand.h b/Source/CTest/cmCTestHandlerCommand.h index 0468bbc..7c9fd50 100644 --- a/Source/CTest/cmCTestHandlerCommand.h +++ b/Source/CTest/cmCTestHandlerCommand.h @@ -12,9 +12,17 @@ #ifndef cmCTestHandlerCommand_h #define cmCTestHandlerCommand_h +#include + #include "cmCTestCommand.h" +#include "cmTypeMacro.h" + +#include +#include +#include class cmCTestGenericHandler; +class cmExecutionStatus; /** \class cmCTestHandler * \brief Run a ctest script diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx index fedcb1f..333f4a0 100644 --- a/Source/CTest/cmCTestLaunch.cxx +++ b/Source/CTest/cmCTestLaunch.cxx @@ -11,15 +11,24 @@ ============================================================================*/ #include "cmCTestLaunch.h" +#include + #include "cmGeneratedFileStream.h" +#include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmState.h" #include "cmSystemTools.h" #include "cmXMLWriter.h" #include "cmake.h" +#include #include #include #include #include +#include +#include +#include #ifdef _WIN32 #include // for _O_BINARY @@ -608,10 +617,6 @@ int cmCTestLaunch::Main(int argc, const char* const argv[]) return self.Run(); } -#include "cmGlobalGenerator.h" -#include "cmMakefile.h" -#include "cmake.h" -#include void cmCTestLaunch::LoadConfig() { cmake cm; diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h index cbcc9ec..5f465ac 100644 --- a/Source/CTest/cmCTestLaunch.h +++ b/Source/CTest/cmCTestLaunch.h @@ -12,9 +12,12 @@ #ifndef cmCTestLaunch_h #define cmCTestLaunch_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include +#include +#include +#include class cmXMLWriter; diff --git a/Source/CTest/cmCTestMemCheckCommand.h b/Source/CTest/cmCTestMemCheckCommand.h index 2ba33ae..69f77af 100644 --- a/Source/CTest/cmCTestMemCheckCommand.h +++ b/Source/CTest/cmCTestMemCheckCommand.h @@ -12,9 +12,15 @@ #ifndef cmCTestMemCheckCommand_h #define cmCTestMemCheckCommand_h +#include + #include "cmCTestTestCommand.h" +#include "cmTypeMacro.h" + +#include class cmCTestGenericHandler; +class cmCommand; /** \class cmCTestMemCheck * \brief Run a ctest script diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index 7d0715f..7a975dd 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -13,20 +13,16 @@ #include "cmCTestMemCheckHandler.h" #include "cmCTest.h" -#include "cmGeneratedFileStream.h" -#include "cmMakefile.h" +#include "cmSystemTools.h" #include "cmXMLParser.h" #include "cmXMLWriter.h" -#include "cmake.h" -#include + #include #include -#include #include - -#include -#include -#include +#include +#include +#include struct CatToErrorType { diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h index a005d54..a4ff684 100644 --- a/Source/CTest/cmCTestMemCheckHandler.h +++ b/Source/CTest/cmCTestMemCheckHandler.h @@ -13,9 +13,11 @@ #ifndef cmCTestMemCheckHandler_h #define cmCTestMemCheckHandler_h +#include + #include "cmCTestTestHandler.h" +#include "cmTypeMacro.h" -#include "cmListFileCache.h" #include #include diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 2632870..d65c915 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -12,17 +12,22 @@ #include "cmCTestMultiProcessHandler.h" #include "cmCTest.h" +#include "cmCTestRunTest.h" #include "cmCTestScriptHandler.h" -#include "cmProcess.h" -#include "cmStandardIncludes.h" +#include "cmCTestTestHandler.h" #include "cmSystemTools.h" + +#include #include +#include #include -#include +#include #include #include +#include #include #include +#include class TestComparator { diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h index 9ec1528..08068c5 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.h +++ b/Source/CTest/cmCTestMultiProcessHandler.h @@ -12,9 +12,17 @@ #ifndef cmCTestMultiProcessHandler_h #define cmCTestMultiProcessHandler_h -#include +#include // IWYU pragma: keep -#include +#include +#include +#include +#include +#include +#include + +class cmCTest; +class cmCTestRunTest; /** \class cmCTestMultiProcessHandler * \brief run parallel ctest diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx index 82422a3..cf7b2ca 100644 --- a/Source/CTest/cmCTestP4.cxx +++ b/Source/CTest/cmCTestP4.cxx @@ -12,14 +12,15 @@ #include "cmCTestP4.h" #include "cmCTest.h" +#include "cmCTestVC.h" +#include "cmProcessTools.h" #include "cmSystemTools.h" -#include +#include #include - -#include -#include +#include #include +#include cmCTestP4::cmCTestP4(cmCTest* ct, std::ostream& log) : cmCTestGlobalVC(ct, log) diff --git a/Source/CTest/cmCTestP4.h b/Source/CTest/cmCTestP4.h index 84e4f96..549936b 100644 --- a/Source/CTest/cmCTestP4.h +++ b/Source/CTest/cmCTestP4.h @@ -12,11 +12,17 @@ #ifndef cmCTestP4_h #define cmCTestP4_h +#include + #include "cmCTestGlobalVC.h" +#include #include +#include #include +class cmCTest; + /** \class cmCTestP4 * \brief Interaction with the Perforce command-line tool * @@ -62,12 +68,13 @@ private: void LoadRevisions() CM_OVERRIDE; void LoadModifications() CM_OVERRIDE; - // Parsing helper classes. - class IdentifyParser; class ChangesParser; - class UserParser; class DescribeParser; class DiffParser; + // Parsing helper classes. + class IdentifyParser; + class UserParser; + friend class IdentifyParser; friend class ChangesParser; friend class UserParser; diff --git a/Source/CTest/cmCTestReadCustomFilesCommand.cxx b/Source/CTest/cmCTestReadCustomFilesCommand.cxx index 24e985d..50a00f6 100644 --- a/Source/CTest/cmCTestReadCustomFilesCommand.cxx +++ b/Source/CTest/cmCTestReadCustomFilesCommand.cxx @@ -13,6 +13,8 @@ #include "cmCTest.h" +class cmExecutionStatus; + bool cmCTestReadCustomFilesCommand::InitialPass( std::vector const& args, cmExecutionStatus& /*unused*/) { diff --git a/Source/CTest/cmCTestReadCustomFilesCommand.h b/Source/CTest/cmCTestReadCustomFilesCommand.h index 6cce7c8..4dcde62 100644 --- a/Source/CTest/cmCTestReadCustomFilesCommand.h +++ b/Source/CTest/cmCTestReadCustomFilesCommand.h @@ -12,7 +12,16 @@ #ifndef cmCTestReadCustomFilesCommand_h #define cmCTestReadCustomFilesCommand_h +#include + #include "cmCTestCommand.h" +#include "cmTypeMacro.h" + +#include +#include + +class cmCommand; +class cmExecutionStatus; /** \class cmCTestReadCustomFiles * \brief Run a ctest script diff --git a/Source/CTest/cmCTestRunScriptCommand.cxx b/Source/CTest/cmCTestRunScriptCommand.cxx index 32bf28f..29aa279 100644 --- a/Source/CTest/cmCTestRunScriptCommand.cxx +++ b/Source/CTest/cmCTestRunScriptCommand.cxx @@ -12,6 +12,11 @@ #include "cmCTestRunScriptCommand.h" #include "cmCTestScriptHandler.h" +#include "cmMakefile.h" + +#include + +class cmExecutionStatus; bool cmCTestRunScriptCommand::InitialPass(std::vector const& args, cmExecutionStatus& /*unused*/) diff --git a/Source/CTest/cmCTestRunScriptCommand.h b/Source/CTest/cmCTestRunScriptCommand.h index 9ea0999..9705f57 100644 --- a/Source/CTest/cmCTestRunScriptCommand.h +++ b/Source/CTest/cmCTestRunScriptCommand.h @@ -12,7 +12,16 @@ #ifndef cmCTestRunScriptCommand_h #define cmCTestRunScriptCommand_h +#include + #include "cmCTestCommand.h" +#include "cmTypeMacro.h" + +#include +#include + +class cmCommand; +class cmExecutionStatus; /** \class cmCTestRunScript * \brief Run a ctest script diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 49acbbf..e7e51d5 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -14,11 +14,21 @@ #include "cmCTest.h" #include "cmCTestMemCheckHandler.h" +#include "cmCTestTestHandler.h" +#include "cmProcess.h" #include "cmSystemTools.h" -#include "cm_curl.h" +#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler) { diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index 3dcc026..0ca434d 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -12,9 +12,15 @@ #ifndef cmCTestRunTest_h #define cmCTestRunTest_h +#include // IWYU pragma: keep + #include +#include +#include +#include -#include +class cmCTest; +class cmProcess; /** \class cmRunTest * \brief represents a single test to be run diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx index bee8296..f680612 100644 --- a/Source/CTest/cmCTestSVN.cxx +++ b/Source/CTest/cmCTestSVN.cxx @@ -12,11 +12,17 @@ #include "cmCTestSVN.h" #include "cmCTest.h" +#include "cmCTestVC.h" +#include "cmProcessTools.h" #include "cmSystemTools.h" #include "cmXMLParser.h" #include "cmXMLWriter.h" #include +#include +#include +#include +#include struct cmCTestSVN::Revision : public cmCTestVC::Revision { diff --git a/Source/CTest/cmCTestSVN.h b/Source/CTest/cmCTestSVN.h index 4f3eb88..6f2374d 100644 --- a/Source/CTest/cmCTestSVN.h +++ b/Source/CTest/cmCTestSVN.h @@ -12,9 +12,17 @@ #ifndef cmCTestSVN_h #define cmCTestSVN_h +#include + #include "cmCTestGlobalVC.h" +#include #include +#include +#include + +class cmCTest; +class cmXMLWriter; /** \class cmCTestSVN * \brief Interaction with subversion command-line tool @@ -68,6 +76,7 @@ private: // Extended revision structure to include info about external it refers to. struct Revision; + friend struct Revision; // Info of all the repositories (root, externals and nested ones). @@ -89,12 +98,13 @@ private: void WriteXMLGlobal(cmXMLWriter& xml) CM_OVERRIDE; + class ExternalParser; // Parsing helper classes. class InfoParser; class LogParser; class StatusParser; class UpdateParser; - class ExternalParser; + friend class InfoParser; friend class LogParser; friend class StatusParser; diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index 44427b0..a31d789 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -13,32 +13,8 @@ #include "cmCTestScriptHandler.h" #include "cmCTest.h" -#include "cmFunctionBlocker.h" -#include "cmGeneratedFileStream.h" -#include "cmGlobalGenerator.h" -#include "cmMakefile.h" -#include "cmake.h" - -//#include -#include -#include - -// used for sleep -#ifdef _WIN32 -#include "windows.h" -#endif - -#include -#include -#include -#include - -// needed for sleep -#if !defined(_WIN32) -#include -#endif - #include "cmCTestBuildCommand.h" +#include "cmCTestCommand.h" #include "cmCTestConfigureCommand.h" #include "cmCTestCoverageCommand.h" #include "cmCTestEmptyBinaryDirectoryCommand.h" @@ -51,6 +27,31 @@ #include "cmCTestTestCommand.h" #include "cmCTestUpdateCommand.h" #include "cmCTestUploadCommand.h" +#include "cmFunctionBlocker.h" +#include "cmGeneratedFileStream.h" +#include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmState.h" +#include "cmSystemTools.h" +#include "cmake.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +class cmExecutionStatus; +struct cmListFileFunction; #define CTEST_INITIAL_CMAKE_OUTPUT_FILE_NAME "CTestInitialCMakeOutput.log" diff --git a/Source/CTest/cmCTestScriptHandler.h b/Source/CTest/cmCTestScriptHandler.h index 4403030..17d7aef 100644 --- a/Source/CTest/cmCTestScriptHandler.h +++ b/Source/CTest/cmCTestScriptHandler.h @@ -13,14 +13,19 @@ #ifndef cmCTestScriptHandler_h #define cmCTestScriptHandler_h +#include + #include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" -#include "cmListFileCache.h" +#include +#include -class cmMakefile; +class cmCTest; +class cmCTestCommand; class cmGlobalGenerator; +class cmMakefile; class cmake; -class cmCTestCommand; /** \class cmCTestScriptHandler * \brief A class that handles ctest -S invocations diff --git a/Source/CTest/cmCTestSleepCommand.cxx b/Source/CTest/cmCTestSleepCommand.cxx index 464f025..0954a7e 100644 --- a/Source/CTest/cmCTestSleepCommand.cxx +++ b/Source/CTest/cmCTestSleepCommand.cxx @@ -12,7 +12,10 @@ #include "cmCTestSleepCommand.h" #include "cmCTestScriptHandler.h" -#include // required for atoi + +#include + +class cmExecutionStatus; bool cmCTestSleepCommand::InitialPass(std::vector const& args, cmExecutionStatus& /*unused*/) diff --git a/Source/CTest/cmCTestSleepCommand.h b/Source/CTest/cmCTestSleepCommand.h index 7981fa2..2a3fa00 100644 --- a/Source/CTest/cmCTestSleepCommand.h +++ b/Source/CTest/cmCTestSleepCommand.h @@ -12,7 +12,16 @@ #ifndef cmCTestSleepCommand_h #define cmCTestSleepCommand_h +#include + #include "cmCTestCommand.h" +#include "cmTypeMacro.h" + +#include +#include + +class cmCommand; +class cmExecutionStatus; /** \class cmCTestSleep * \brief Run a ctest script diff --git a/Source/CTest/cmCTestStartCommand.cxx b/Source/CTest/cmCTestStartCommand.cxx index 04d2f03..803e01c 100644 --- a/Source/CTest/cmCTestStartCommand.cxx +++ b/Source/CTest/cmCTestStartCommand.cxx @@ -14,7 +14,13 @@ #include "cmCTest.h" #include "cmCTestVC.h" #include "cmGeneratedFileStream.h" -#include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" + +#include +#include + +class cmExecutionStatus; cmCTestStartCommand::cmCTestStartCommand() { diff --git a/Source/CTest/cmCTestStartCommand.h b/Source/CTest/cmCTestStartCommand.h index e3f8f8b..22035fa 100644 --- a/Source/CTest/cmCTestStartCommand.h +++ b/Source/CTest/cmCTestStartCommand.h @@ -12,7 +12,17 @@ #ifndef cmCTestStartCommand_h #define cmCTestStartCommand_h +#include + #include "cmCTestCommand.h" +#include "cmTypeMacro.h" + +#include +#include +#include + +class cmCommand; +class cmExecutionStatus; /** \class cmCTestStart * \brief Run a ctest script diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx index 54da383..c7c3584 100644 --- a/Source/CTest/cmCTestSubmitCommand.cxx +++ b/Source/CTest/cmCTestSubmitCommand.cxx @@ -14,6 +14,13 @@ #include "cmCTest.h" #include "cmCTestGenericHandler.h" #include "cmCTestSubmitHandler.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" +#include "cmake.h" + +#include + +class cmExecutionStatus; cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler() { diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h index 7c3d6cd..03165bf 100644 --- a/Source/CTest/cmCTestSubmitCommand.h +++ b/Source/CTest/cmCTestSubmitCommand.h @@ -12,9 +12,19 @@ #ifndef cmCTestSubmitCommand_h #define cmCTestSubmitCommand_h -#include "cmCTestHandlerCommand.h" +#include #include "cmCTest.h" +#include "cmCTestHandlerCommand.h" +#include "cmTypeMacro.h" + +#include +#include +#include + +class cmCTestGenericHandler; +class cmCommand; +class cmExecutionStatus; /** \class cmCTestSubmit * \brief Run a ctest script diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 42727d0..7c42fd0 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -12,26 +12,22 @@ #include "cmCTestSubmitHandler.h" #include "cmCTest.h" +#include "cmCTestCurl.h" #include "cmCTestScriptHandler.h" +#include "cmCurl.h" #include "cmGeneratedFileStream.h" #include "cmState.h" #include "cmSystemTools.h" -#include "cmVersion.h" #include "cmXMLParser.h" #include "cmake.h" -#include -#include - -// For XML-RPC submission -#include "cm_xmlrpc.h" - +#include #include -// For curl submission -#include "cmCTestCurl.h" -#include "cmCurl.h" - -#include +#include +#include +#include +#include +#include #define SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT 120 diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h index 4cca6eb..0e5aea6 100644 --- a/Source/CTest/cmCTestSubmitHandler.h +++ b/Source/CTest/cmCTestSubmitHandler.h @@ -12,7 +12,16 @@ #ifndef cmCTestSubmitHandler_h #define cmCTestSubmitHandler_h +#include + +#include "cmCTest.h" #include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" + +#include +#include +#include +#include /** \class cmCTestSubmitHandler * \brief Helper class for CTest @@ -84,6 +93,7 @@ private: std::string GetSubmitResultsPrefix(); class ResponseParser; + std::string HTTPProxy; int HTTPProxyType; std::string HTTPProxyAuth; diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx index 1d064db..8ac4c69 100644 --- a/Source/CTest/cmCTestTestCommand.cxx +++ b/Source/CTest/cmCTestTestCommand.cxx @@ -13,6 +13,12 @@ #include "cmCTest.h" #include "cmCTestGenericHandler.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" + +#include +#include +#include cmCTestTestCommand::cmCTestTestCommand() { diff --git a/Source/CTest/cmCTestTestCommand.h b/Source/CTest/cmCTestTestCommand.h index f652971..89e37b9 100644 --- a/Source/CTest/cmCTestTestCommand.h +++ b/Source/CTest/cmCTestTestCommand.h @@ -12,7 +12,15 @@ #ifndef cmCTestTestCommand_h #define cmCTestTestCommand_h +#include + #include "cmCTestHandlerCommand.h" +#include "cmTypeMacro.h" + +#include + +class cmCTestGenericHandler; +class cmCommand; /** \class cmCTestTest * \brief Run a ctest script diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 3ce0317..479c516 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -15,26 +15,32 @@ #include "cmCTest.h" #include "cmCTestBatchTestHandler.h" #include "cmCTestMultiProcessHandler.h" -#include "cmCTestRunTest.h" #include "cmCommand.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" +#include "cmState.h" #include "cmSystemTools.h" #include "cmXMLWriter.h" +#include "cm_auto_ptr.hxx" #include "cm_utf8.h" #include "cmake.h" + +#include #include #include #include -#include #include - -#include -#include +#include +#include +#include +#include +#include #include +#include +#include -#include +class cmExecutionStatus; class cmCTestSubdirCommand : public cmCommand { diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index a085a82..a5e62dc 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -13,10 +13,21 @@ #ifndef cmCTestTestHandler_h #define cmCTestTestHandler_h +#include + #include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" #include - +#include +#include +#include +#include +#include +#include +#include + +class cmCTest; class cmMakefile; class cmXMLWriter; diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx index bc06da6..53382c9 100644 --- a/Source/CTest/cmCTestUpdateCommand.cxx +++ b/Source/CTest/cmCTestUpdateCommand.cxx @@ -13,6 +13,10 @@ #include "cmCTest.h" #include "cmCTestGenericHandler.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" + +#include cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler() { diff --git a/Source/CTest/cmCTestUpdateCommand.h b/Source/CTest/cmCTestUpdateCommand.h index 6b5bbab..89470e1 100644 --- a/Source/CTest/cmCTestUpdateCommand.h +++ b/Source/CTest/cmCTestUpdateCommand.h @@ -12,7 +12,15 @@ #ifndef cmCTestUpdateCommand_h #define cmCTestUpdateCommand_h +#include + #include "cmCTestHandlerCommand.h" +#include "cmTypeMacro.h" + +#include + +class cmCTestGenericHandler; +class cmCommand; /** \class cmCTestUpdate * \brief Run a ctest script diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx index ac7eb05..bbb9430 100644 --- a/Source/CTest/cmCTestUpdateHandler.cxx +++ b/Source/CTest/cmCTestUpdateHandler.cxx @@ -14,14 +14,6 @@ #include "cmCLocaleEnvironmentScope.h" #include "cmCTest.h" -#include "cmGeneratedFileStream.h" -#include "cmGlobalGenerator.h" -#include "cmMakefile.h" -#include "cmVersion.h" -#include "cmXMLParser.h" -#include "cmXMLWriter.h" -#include "cmake.h" - #include "cmCTestBZR.h" #include "cmCTestCVS.h" #include "cmCTestGIT.h" @@ -29,20 +21,13 @@ #include "cmCTestP4.h" #include "cmCTestSVN.h" #include "cmCTestVC.h" +#include "cmGeneratedFileStream.h" +#include "cmSystemTools.h" +#include "cmVersion.h" +#include "cmXMLWriter.h" #include - -//#include -#include - -// used for sleep -#ifdef _WIN32 -#include "windows.h" -#endif - -#include -#include -#include +#include static const char* cmCTestUpdateHandlerUpdateStrings[] = { "Unknown", "CVS", "SVN", "BZR", "GIT", "HG", "P4" diff --git a/Source/CTest/cmCTestUpdateHandler.h b/Source/CTest/cmCTestUpdateHandler.h index 6733c8c..838ef0e 100644 --- a/Source/CTest/cmCTestUpdateHandler.h +++ b/Source/CTest/cmCTestUpdateHandler.h @@ -13,9 +13,14 @@ #ifndef cmCTestUpdateHandler_h #define cmCTestUpdateHandler_h +#include + #include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" -#include "cmListFileCache.h" +#include +#include +#include /** \class cmCTestUpdateHandler * \brief A class that handles ctest -S invocations diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx index 016b32b..5ea637e 100644 --- a/Source/CTest/cmCTestUploadCommand.cxx +++ b/Source/CTest/cmCTestUploadCommand.cxx @@ -14,6 +14,11 @@ #include "cmCTest.h" #include "cmCTestGenericHandler.h" #include "cmCTestUploadHandler.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" +#include "cmake.h" + +#include cmCTestGenericHandler* cmCTestUploadCommand::InitializeHandler() { diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h index 923995d..da291f3 100644 --- a/Source/CTest/cmCTestUploadCommand.h +++ b/Source/CTest/cmCTestUploadCommand.h @@ -12,9 +12,16 @@ #ifndef cmCTestUploadCommand_h #define cmCTestUploadCommand_h -#include "cmCTestHandlerCommand.h" +#include #include "cmCTest.h" +#include "cmCTestHandlerCommand.h" +#include "cmTypeMacro.h" + +#include + +class cmCTestGenericHandler; +class cmCommand; /** \class cmCTestUpload * \brief Run a ctest script diff --git a/Source/CTest/cmCTestUploadHandler.cxx b/Source/CTest/cmCTestUploadHandler.cxx index 6a3b830..07d3ad7 100644 --- a/Source/CTest/cmCTestUploadHandler.cxx +++ b/Source/CTest/cmCTestUploadHandler.cxx @@ -15,6 +15,10 @@ #include "cmVersion.h" #include "cmXMLWriter.h" +#include +#include +#include + cmCTestUploadHandler::cmCTestUploadHandler() { this->Initialize(); diff --git a/Source/CTest/cmCTestUploadHandler.h b/Source/CTest/cmCTestUploadHandler.h index 8b824d6..6503d08 100644 --- a/Source/CTest/cmCTestUploadHandler.h +++ b/Source/CTest/cmCTestUploadHandler.h @@ -12,7 +12,11 @@ #ifndef cmCTestUploadHandler_h #define cmCTestUploadHandler_h +#include + +#include "cmCTest.h" #include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" /** \class cmCTestUploadHandler * \brief Helper class for CTest diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx index 24557aa..182364b 100644 --- a/Source/CTest/cmCTestVC.cxx +++ b/Source/CTest/cmCTestVC.cxx @@ -16,6 +16,10 @@ #include "cmXMLWriter.h" #include +#include +#include +#include +#include cmCTestVC::cmCTestVC(cmCTest* ct, std::ostream& log) : CTest(ct) diff --git a/Source/CTest/cmCTestVC.h b/Source/CTest/cmCTestVC.h index eb85a23..8063e40 100644 --- a/Source/CTest/cmCTestVC.h +++ b/Source/CTest/cmCTestVC.h @@ -12,8 +12,13 @@ #ifndef cmCTestVC_h #define cmCTestVC_h +#include + #include "cmProcessTools.h" +#include +#include + class cmCTest; class cmXMLWriter; @@ -93,7 +98,6 @@ public: }; protected: - struct File; friend struct File; /** Represent change to one file. */ diff --git a/Source/CTest/cmParseBlanketJSCoverage.cxx b/Source/CTest/cmParseBlanketJSCoverage.cxx index 976a92d..28077ff 100644 --- a/Source/CTest/cmParseBlanketJSCoverage.cxx +++ b/Source/CTest/cmParseBlanketJSCoverage.cxx @@ -11,10 +11,11 @@ ============================================================================*/ #include "cmParseBlanketJSCoverage.h" +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" -#include + #include -#include #include #include diff --git a/Source/CTest/cmParseBlanketJSCoverage.h b/Source/CTest/cmParseBlanketJSCoverage.h index a4f6670..ece1efa 100644 --- a/Source/CTest/cmParseBlanketJSCoverage.h +++ b/Source/CTest/cmParseBlanketJSCoverage.h @@ -13,7 +13,13 @@ #ifndef cmParseBlanketJSCoverage_h #define cmParseBlanketJSCoverage_h -#include "cmCTestCoverageHandler.h" +#include // IWYU pragma: keep + +#include +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; /** \class cmParseBlanketJSCoverage * \brief Parse BlanketJS coverage information @@ -39,6 +45,7 @@ public: protected: class JSONParser; + cmCTestCoverageHandlerContainer& Coverage; cmCTest* CTest; }; diff --git a/Source/CTest/cmParseCacheCoverage.cxx b/Source/CTest/cmParseCacheCoverage.cxx index 0916da2..23176b5 100644 --- a/Source/CTest/cmParseCacheCoverage.cxx +++ b/Source/CTest/cmParseCacheCoverage.cxx @@ -1,11 +1,15 @@ #include "cmParseCacheCoverage.h" +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" + #include #include -#include +#include #include #include +#include cmParseCacheCoverage::cmParseCacheCoverage( cmCTestCoverageHandlerContainer& cont, cmCTest* ctest) diff --git a/Source/CTest/cmParseCacheCoverage.h b/Source/CTest/cmParseCacheCoverage.h index 65b1d10..4fa6c26 100644 --- a/Source/CTest/cmParseCacheCoverage.h +++ b/Source/CTest/cmParseCacheCoverage.h @@ -13,8 +13,16 @@ #ifndef cmParseCacheCoverage_h #define cmParseCacheCoverage_h +#include + #include "cmParseMumpsCoverage.h" +#include +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; + /** \class cmParseCacheCoverage * \brief Parse Cache coverage information * diff --git a/Source/CTest/cmParseCoberturaCoverage.cxx b/Source/CTest/cmParseCoberturaCoverage.cxx index 1a3fe3c..0b6d3ce 100644 --- a/Source/CTest/cmParseCoberturaCoverage.cxx +++ b/Source/CTest/cmParseCoberturaCoverage.cxx @@ -1,9 +1,14 @@ #include "cmParseCoberturaCoverage.h" +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" #include "cmXMLParser.h" -#include + +#include #include +#include +#include class cmParseCoberturaCoverage::XMLParser : public cmXMLParser { diff --git a/Source/CTest/cmParseCoberturaCoverage.h b/Source/CTest/cmParseCoberturaCoverage.h index 4fa6d10..f45ec95 100644 --- a/Source/CTest/cmParseCoberturaCoverage.h +++ b/Source/CTest/cmParseCoberturaCoverage.h @@ -13,7 +13,13 @@ #ifndef cmParseCoberturaCoverage_h #define cmParseCoberturaCoverage_h -#include "cmCTestCoverageHandler.h" +#include // IWYU pragma: keep + +#include +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; /** \class cmParsePythonCoverage * \brief Parse coverage.py Python coverage information @@ -40,6 +46,7 @@ public: private: class XMLParser; + cmCTestCoverageHandlerContainer& Coverage; cmCTest* CTest; std::string CurFileName; diff --git a/Source/CTest/cmParseDelphiCoverage.cxx b/Source/CTest/cmParseDelphiCoverage.cxx index 9d86ce9..7fe91f4 100644 --- a/Source/CTest/cmParseDelphiCoverage.cxx +++ b/Source/CTest/cmParseDelphiCoverage.cxx @@ -1,8 +1,9 @@ #include "cmParseDelphiCoverage.h" +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" -#include "cmXMLParser.h" -#include + #include #include #include diff --git a/Source/CTest/cmParseDelphiCoverage.h b/Source/CTest/cmParseDelphiCoverage.h index c1c495c..82557d9 100644 --- a/Source/CTest/cmParseDelphiCoverage.h +++ b/Source/CTest/cmParseDelphiCoverage.h @@ -13,7 +13,13 @@ #ifndef cmParseDelphiCoverage_h #define cmParseDelphiCoverage_h -#include "cmCTestCoverageHandler.h" +#include // IWYU pragma: keep + +#include +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; /** \class cmParseDelphiCoverage * \brief Parse Delphi coverage information @@ -35,6 +41,7 @@ public: protected: class HTMLParser; + cmCTestCoverageHandlerContainer& Coverage; cmCTest* CTest; }; diff --git a/Source/CTest/cmParseGTMCoverage.cxx b/Source/CTest/cmParseGTMCoverage.cxx index 33ad839..214ce5a 100644 --- a/Source/CTest/cmParseGTMCoverage.cxx +++ b/Source/CTest/cmParseGTMCoverage.cxx @@ -1,11 +1,15 @@ #include "cmParseGTMCoverage.h" +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" + #include #include -#include +#include #include #include +#include cmParseGTMCoverage::cmParseGTMCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest) diff --git a/Source/CTest/cmParseGTMCoverage.h b/Source/CTest/cmParseGTMCoverage.h index 4188689..623cd5a 100644 --- a/Source/CTest/cmParseGTMCoverage.h +++ b/Source/CTest/cmParseGTMCoverage.h @@ -13,8 +13,15 @@ #ifndef cmParseGTMCoverage_h #define cmParseGTMCoverage_h +#include + #include "cmParseMumpsCoverage.h" +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; + /** \class cmParseGTMCoverage * \brief Parse GTM coverage information * diff --git a/Source/CTest/cmParseJacocoCoverage.cxx b/Source/CTest/cmParseJacocoCoverage.cxx index bc05666..0e36c01 100644 --- a/Source/CTest/cmParseJacocoCoverage.cxx +++ b/Source/CTest/cmParseJacocoCoverage.cxx @@ -1,12 +1,17 @@ #include "cmParseJacocoCoverage.h" +#include + +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" #include "cmXMLParser.h" + #include #include #include -#include #include +#include class cmParseJacocoCoverage::XMLParser : public cmXMLParser { diff --git a/Source/CTest/cmParseJacocoCoverage.h b/Source/CTest/cmParseJacocoCoverage.h index bcd472e..4b94725 100644 --- a/Source/CTest/cmParseJacocoCoverage.h +++ b/Source/CTest/cmParseJacocoCoverage.h @@ -13,7 +13,14 @@ #ifndef cmParseJacocoCoverage_h #define cmParseJacocoCoverage_h -#include "cmCTestCoverageHandler.h" +#include // IWYU pragma: keep + +#include +#include +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; /** \class cmParseJacocoCoverage * \brief Parse JaCoCO coverage information @@ -47,6 +54,7 @@ private: bool LoadSource(std::string d); class XMLParser; + std::map RoutineToDirectory; cmCTestCoverageHandlerContainer& Coverage; cmCTest* CTest; diff --git a/Source/CTest/cmParseMumpsCoverage.cxx b/Source/CTest/cmParseMumpsCoverage.cxx index af01496..ab8be76 100644 --- a/Source/CTest/cmParseMumpsCoverage.cxx +++ b/Source/CTest/cmParseMumpsCoverage.cxx @@ -1,11 +1,16 @@ -#include "cmParseGTMCoverage.h" +#include "cmParseMumpsCoverage.h" +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" -#include + +#include #include #include -#include -#include +#include +#include +#include +#include cmParseMumpsCoverage::cmParseMumpsCoverage( cmCTestCoverageHandlerContainer& cont, cmCTest* ctest) diff --git a/Source/CTest/cmParseMumpsCoverage.h b/Source/CTest/cmParseMumpsCoverage.h index 3761ba6..8b33bd7 100644 --- a/Source/CTest/cmParseMumpsCoverage.h +++ b/Source/CTest/cmParseMumpsCoverage.h @@ -13,7 +13,13 @@ #ifndef cmParseMumpsCoverage_h #define cmParseMumpsCoverage_h -#include "cmCTestCoverageHandler.h" +#include // IWYU pragma: keep + +#include +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; /** \class cmParseMumpsCoverage * \brief Parse Mumps coverage information diff --git a/Source/CTest/cmParsePHPCoverage.cxx b/Source/CTest/cmParsePHPCoverage.cxx index 5ec2718..d8bb31b 100644 --- a/Source/CTest/cmParsePHPCoverage.cxx +++ b/Source/CTest/cmParsePHPCoverage.cxx @@ -1,8 +1,13 @@ #include "cmParsePHPCoverage.h" +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" + #include #include +#include +#include /* To setup coverage for php. diff --git a/Source/CTest/cmParsePHPCoverage.h b/Source/CTest/cmParsePHPCoverage.h index 72f9129..b261a8d 100644 --- a/Source/CTest/cmParsePHPCoverage.h +++ b/Source/CTest/cmParsePHPCoverage.h @@ -13,7 +13,13 @@ #ifndef cmParsePHPCoverage_h #define cmParsePHPCoverage_h -#include "cmCTestCoverageHandler.h" +#include // IWYU pragma: keep + +#include +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; /** \class cmParsePHPCoverage * \brief Parse xdebug PHP coverage information diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 30cd102..51aed79 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -9,10 +9,11 @@ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more information. ============================================================================*/ +#include "cmProcess.h" -#include - +#include #include +#include cmProcess::cmProcess() { diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h index d5e2721..2a6fa7c 100644 --- a/Source/CTest/cmProcess.h +++ b/Source/CTest/cmProcess.h @@ -12,9 +12,11 @@ #ifndef cmProcess_h #define cmProcess_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include +#include +#include /** \class cmProcess * \brief run a process with c++ ----------------------------------------------------------------------- Summary of changes: Source/CTest/cmCTestBZR.cxx | 10 +++- Source/CTest/cmCTestBZR.h | 14 ++++-- Source/CTest/cmCTestBatchTestHandler.cxx | 8 ++- Source/CTest/cmCTestBatchTestHandler.h | 5 +- Source/CTest/cmCTestBuildAndTestHandler.cxx | 2 + Source/CTest/cmCTestBuildAndTestHandler.h | 9 +++- Source/CTest/cmCTestBuildCommand.cxx | 7 +++ Source/CTest/cmCTestBuildCommand.h | 11 ++++- Source/CTest/cmCTestBuildHandler.cxx | 15 ++---- Source/CTest/cmCTestBuildHandler.h | 11 +++-- Source/CTest/cmCTestCVS.cxx | 2 + Source/CTest/cmCTestCVS.h | 12 ++++- Source/CTest/cmCTestConfigureCommand.cxx | 7 +++ Source/CTest/cmCTestConfigureCommand.h | 8 +++ Source/CTest/cmCTestConfigureHandler.cxx | 6 ++- Source/CTest/cmCTestConfigureHandler.h | 5 +- Source/CTest/cmCTestCoverageCommand.cxx | 2 + Source/CTest/cmCTestCoverageCommand.h | 9 ++++ Source/CTest/cmCTestCoverageHandler.cxx | 12 +++-- Source/CTest/cmCTestCoverageHandler.h | 12 ++++- Source/CTest/cmCTestCurl.cxx | 4 ++ Source/CTest/cmCTestCurl.h | 6 ++- .../CTest/cmCTestEmptyBinaryDirectoryCommand.cxx | 4 ++ Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h | 9 ++++ Source/CTest/cmCTestGIT.cxx | 8 +-- Source/CTest/cmCTestGIT.h | 16 ++++-- Source/CTest/cmCTestGenericHandler.cxx | 4 +- Source/CTest/cmCTestGenericHandler.h | 12 +++-- Source/CTest/cmCTestGlobalVC.cxx | 3 +- Source/CTest/cmCTestGlobalVC.h | 7 +++ Source/CTest/cmCTestHG.cxx | 4 ++ Source/CTest/cmCTestHG.h | 12 ++++- Source/CTest/cmCTestHandlerCommand.cxx | 8 +++ Source/CTest/cmCTestHandlerCommand.h | 8 +++ Source/CTest/cmCTestLaunch.cxx | 13 +++-- Source/CTest/cmCTestLaunch.h | 5 +- Source/CTest/cmCTestMemCheckCommand.h | 6 +++ Source/CTest/cmCTestMemCheckHandler.cxx | 14 ++---- Source/CTest/cmCTestMemCheckHandler.h | 4 +- Source/CTest/cmCTestMultiProcessHandler.cxx | 11 +++-- Source/CTest/cmCTestMultiProcessHandler.h | 12 ++++- Source/CTest/cmCTestP4.cxx | 9 ++-- Source/CTest/cmCTestP4.h | 13 +++-- Source/CTest/cmCTestReadCustomFilesCommand.cxx | 2 + Source/CTest/cmCTestReadCustomFilesCommand.h | 9 ++++ Source/CTest/cmCTestRunScriptCommand.cxx | 5 ++ Source/CTest/cmCTestRunScriptCommand.h | 9 ++++ Source/CTest/cmCTestRunTest.cxx | 12 ++++- Source/CTest/cmCTestRunTest.h | 8 ++- Source/CTest/cmCTestSVN.cxx | 6 +++ Source/CTest/cmCTestSVN.h | 12 ++++- Source/CTest/cmCTestScriptHandler.cxx | 51 ++++++++++---------- Source/CTest/cmCTestScriptHandler.h | 11 +++-- Source/CTest/cmCTestSleepCommand.cxx | 5 +- Source/CTest/cmCTestSleepCommand.h | 9 ++++ Source/CTest/cmCTestStartCommand.cxx | 8 ++- Source/CTest/cmCTestStartCommand.h | 10 ++++ Source/CTest/cmCTestSubmitCommand.cxx | 7 +++ Source/CTest/cmCTestSubmitCommand.h | 12 ++++- Source/CTest/cmCTestSubmitHandler.cxx | 20 +++----- Source/CTest/cmCTestSubmitHandler.h | 10 ++++ Source/CTest/cmCTestTestCommand.cxx | 6 +++ Source/CTest/cmCTestTestCommand.h | 8 +++ Source/CTest/cmCTestTestHandler.cxx | 18 ++++--- Source/CTest/cmCTestTestHandler.h | 13 ++++- Source/CTest/cmCTestUpdateCommand.cxx | 4 ++ Source/CTest/cmCTestUpdateCommand.h | 8 +++ Source/CTest/cmCTestUpdateHandler.cxx | 25 ++-------- Source/CTest/cmCTestUpdateHandler.h | 7 ++- Source/CTest/cmCTestUploadCommand.cxx | 5 ++ Source/CTest/cmCTestUploadCommand.h | 9 +++- Source/CTest/cmCTestUploadHandler.cxx | 4 ++ Source/CTest/cmCTestUploadHandler.h | 4 ++ Source/CTest/cmCTestVC.cxx | 4 ++ Source/CTest/cmCTestVC.h | 6 ++- Source/CTest/cmParseBlanketJSCoverage.cxx | 5 +- Source/CTest/cmParseBlanketJSCoverage.h | 9 +++- Source/CTest/cmParseCacheCoverage.cxx | 6 ++- Source/CTest/cmParseCacheCoverage.h | 8 +++ Source/CTest/cmParseCoberturaCoverage.cxx | 7 ++- Source/CTest/cmParseCoberturaCoverage.h | 9 +++- Source/CTest/cmParseDelphiCoverage.cxx | 5 +- Source/CTest/cmParseDelphiCoverage.h | 9 +++- Source/CTest/cmParseGTMCoverage.cxx | 6 ++- Source/CTest/cmParseGTMCoverage.h | 7 +++ Source/CTest/cmParseJacocoCoverage.cxx | 7 ++- Source/CTest/cmParseJacocoCoverage.h | 10 +++- Source/CTest/cmParseMumpsCoverage.cxx | 13 +++-- Source/CTest/cmParseMumpsCoverage.h | 8 ++- Source/CTest/cmParsePHPCoverage.cxx | 5 ++ Source/CTest/cmParsePHPCoverage.h | 8 ++- Source/CTest/cmProcess.cxx | 5 +- Source/CTest/cmProcess.h | 4 +- 93 files changed, 638 insertions(+), 179 deletions(-) hooks/post-receive -- CMake From steveire at gmail.com Wed Aug 24 16:11:18 2016 From: steveire at gmail.com (Stephen Kelly) Date: Wed, 24 Aug 2016 16:11:18 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1417-gd644883 Message-ID: <20160824201118.7F762F2F80@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via d64488359696c8ad9519daff699ac9f1d93b2b4f (commit) via d0c8e915ef09b5596befa7b7b05e2b1ae189141d (commit) from a03507820e8b11bc65bd678433c173b92b3549f6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d64488359696c8ad9519daff699ac9f1d93b2b4f commit d64488359696c8ad9519daff699ac9f1d93b2b4f Merge: a035078 d0c8e91 Author: Stephen Kelly AuthorDate: Wed Aug 24 16:11:17 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 16:11:17 2016 -0400 Merge topic 'extract-cmMessenger' into next d0c8e915 fixup! cmMessenger: Extract from cmake class https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d0c8e915ef09b5596befa7b7b05e2b1ae189141d commit d0c8e915ef09b5596befa7b7b05e2b1ae189141d Author: Stephen Kelly AuthorDate: Wed Aug 24 22:07:44 2016 +0200 Commit: Stephen Kelly CommitDate: Wed Aug 24 22:07:44 2016 +0200 fixup! cmMessenger: Extract from cmake class diff --git a/bootstrap b/bootstrap index 742fa2b..6c6713e 100755 --- a/bootstrap +++ b/bootstrap @@ -266,6 +266,7 @@ CMAKE_CXX_SOURCES="\ cmPropertyDefinition \ cmPropertyDefinitionMap \ cmMakefile \ + cmMessenger \ cmExportBuildFileGenerator \ cmExportFileGenerator \ cmExportInstallFileGenerator \ ----------------------------------------------------------------------- Summary of changes: bootstrap | 1 + 1 file changed, 1 insertion(+) hooks/post-receive -- CMake From daniel at pfeifer-mail.de Wed Aug 24 16:25:13 2016 From: daniel at pfeifer-mail.de (Daniel Pfeifer) Date: Wed, 24 Aug 2016 16:25:13 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1419-g9619967 Message-ID: <20160824202514.3EAF4F551A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 96199676e0d3a8d14480b781b5e0534b2d342006 (commit) via f1e447467da748ba794f001c72cb0df5aea175d7 (commit) from d64488359696c8ad9519daff699ac9f1d93b2b4f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=96199676e0d3a8d14480b781b5e0534b2d342006 commit 96199676e0d3a8d14480b781b5e0534b2d342006 Merge: d644883 f1e4474 Author: Daniel Pfeifer AuthorDate: Wed Aug 24 16:25:11 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 24 16:25:11 2016 -0400 Merge topic 'include-what-you-use' into next f1e44746 fixup! CTest: fix include-what-you-use violations https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f1e447467da748ba794f001c72cb0df5aea175d7 commit f1e447467da748ba794f001c72cb0df5aea175d7 Author: Daniel Pfeifer AuthorDate: Wed Aug 24 22:24:57 2016 +0200 Commit: Daniel Pfeifer CommitDate: Wed Aug 24 22:24:57 2016 +0200 fixup! CTest: fix include-what-you-use violations diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 7c42fd0..67f7c89 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -29,6 +29,12 @@ #include #include +#if defined(CTEST_USE_XMLRPC) +#include "cmVersion.h" +#include +#include +#endif + #define SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT 120 typedef std::vector cmCTestSubmitHandlerVectorOfChar; ----------------------------------------------------------------------- Summary of changes: Source/CTest/cmCTestSubmitHandler.cxx | 6 ++++++ 1 file changed, 6 insertions(+) hooks/post-receive -- CMake From kwrobot at kitware.com Thu Aug 25 00:01:09 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Thu, 25 Aug 2016 00:01:09 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-717-gd6734ee Message-ID: <20160825040110.DA885F5ADB@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via d6734eeb875ceca5d810e829ca90541918dca2b4 (commit) from 81c3e637ccc135068a06fa3dc72f23733f003db5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d6734eeb875ceca5d810e829ca90541918dca2b4 commit d6734eeb875ceca5d810e829ca90541918dca2b4 Author: Kitware Robot AuthorDate: Thu Aug 25 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Thu Aug 25 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index aabc839..d26debc 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160824) +set(CMake_VERSION_PATCH 20160825) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 09:13:39 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 09:13:39 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1421-gbf1c52e Message-ID: <20160825131339.B1FE0F4FF3@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via bf1c52ecfbd2d5abd1ca6e761c284aa9fdd3cc48 (commit) via 9e0ce22cee97be5f6aa2a62f5b46284d3c4b1148 (commit) from 96199676e0d3a8d14480b781b5e0534b2d342006 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bf1c52ecfbd2d5abd1ca6e761c284aa9fdd3cc48 commit bf1c52ecfbd2d5abd1ca6e761c284aa9fdd3cc48 Merge: 9619967 9e0ce22 Author: Brad King AuthorDate: Thu Aug 25 09:13:38 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 09:13:38 2016 -0400 Merge topic 'vs-resource-pri-dir' into next 9e0ce22c Revert "VS: Use target-specific intermediate directory for `resources.pri`" https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9e0ce22cee97be5f6aa2a62f5b46284d3c4b1148 commit 9e0ce22cee97be5f6aa2a62f5b46284d3c4b1148 Author: Brad King AuthorDate: Thu Aug 25 09:13:07 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 09:13:07 2016 -0400 Revert "VS: Use target-specific intermediate directory for `resources.pri`" This reverts commit d8fbb7d2d33ddbfa69f13e86c9da293591bf8d5f. It causes the Store/Phone tests to fail. diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index ffad095..c33a291 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2742,7 +2742,7 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile() (*this->BuildFileStream) << cmVS10EscapeXML(artifactDir) << "\\\n"; this->WriteString("" - "$(IntDir)resources.pri\n", + "$(TargetDir)resources.pri\n", 2); // If we are missing files and we don't have a certificate and ----------------------------------------------------------------------- Summary of changes: Source/cmVisualStudio10TargetGenerator.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 09:35:07 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 09:35:07 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1423-ge1f3f61 Message-ID: <20160825133507.EE2E3F5A1D@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via e1f3f613573bc2a000ea94485be12dcfed588761 (commit) via 38491644540a203ee6465dd0bf179afb426aa835 (commit) from bf1c52ecfbd2d5abd1ca6e761c284aa9fdd3cc48 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e1f3f613573bc2a000ea94485be12dcfed588761 commit e1f3f613573bc2a000ea94485be12dcfed588761 Merge: bf1c52e 3849164 Author: Brad King AuthorDate: Thu Aug 25 09:35:05 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 09:35:05 2016 -0400 Merge topic 'include-what-you-use' into next 38491644 CTest: fix include-what-you-use violations https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=38491644540a203ee6465dd0bf179afb426aa835 commit 38491644540a203ee6465dd0bf179afb426aa835 Author: Daniel Pfeifer AuthorDate: Wed Aug 24 22:01:40 2016 +0200 Commit: Brad King CommitDate: Thu Aug 25 09:34:37 2016 -0400 CTest: fix include-what-you-use violations diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx index 7baf7a3..413cada 100644 --- a/Source/CTest/cmCTestBZR.cxx +++ b/Source/CTest/cmCTestBZR.cxx @@ -12,12 +12,18 @@ #include "cmCTestBZR.h" #include "cmCTest.h" +#include "cmCTestVC.h" +#include "cmProcessTools.h" #include "cmSystemTools.h" #include "cmXMLParser.h" -#include - #include +#include +#include +#include +#include +#include +#include extern "C" int cmBZRXMLParserUnknownEncodingHandler(void* /*unused*/, const XML_Char* name, diff --git a/Source/CTest/cmCTestBZR.h b/Source/CTest/cmCTestBZR.h index 0f05d38..e2ee8b7 100644 --- a/Source/CTest/cmCTestBZR.h +++ b/Source/CTest/cmCTestBZR.h @@ -12,8 +12,15 @@ #ifndef cmCTestBZR_h #define cmCTestBZR_h +#include + #include "cmCTestGlobalVC.h" +#include +#include + +class cmCTest; + /** \class cmCTestBZR * \brief Interaction with bzr command-line tool * @@ -41,13 +48,14 @@ private: // Parsing helper classes. class InfoParser; - class RevnoParser; class LogParser; - class UpdateParser; + class RevnoParser; class StatusParser; + class UpdateParser; + friend class InfoParser; - friend class RevnoParser; friend class LogParser; + friend class RevnoParser; friend class UpdateParser; friend class StatusParser; }; diff --git a/Source/CTest/cmCTestBatchTestHandler.cxx b/Source/CTest/cmCTestBatchTestHandler.cxx index 70f84cb..bf4ead4 100644 --- a/Source/CTest/cmCTestBatchTestHandler.cxx +++ b/Source/CTest/cmCTestBatchTestHandler.cxx @@ -13,10 +13,14 @@ #include "cmCTestBatchTestHandler.h" #include "cmCTest.h" +#include "cmCTestMultiProcessHandler.h" +#include "cmCTestTestHandler.h" #include "cmProcess.h" -#include "cmStandardIncludes.h" #include "cmSystemTools.h" -#include + +#include +#include +#include cmCTestBatchTestHandler::~cmCTestBatchTestHandler() { diff --git a/Source/CTest/cmCTestBatchTestHandler.h b/Source/CTest/cmCTestBatchTestHandler.h index 17cc234..da10824 100644 --- a/Source/CTest/cmCTestBatchTestHandler.h +++ b/Source/CTest/cmCTestBatchTestHandler.h @@ -13,12 +13,11 @@ #ifndef cmCTestBatchTestHandler_h #define cmCTestBatchTestHandler_h -#include +#include #include -#include -#include #include +#include /** \class cmCTestBatchTestHandler * \brief run parallel ctest diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index 9dab98a..9da2848 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -17,7 +17,9 @@ #include "cmGlobalGenerator.h" #include "cmSystemTools.h" #include "cmake.h" + #include +#include cmCTestBuildAndTestHandler::cmCTestBuildAndTestHandler() { diff --git a/Source/CTest/cmCTestBuildAndTestHandler.h b/Source/CTest/cmCTestBuildAndTestHandler.h index 2aa90a4..f917fb0 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.h +++ b/Source/CTest/cmCTestBuildAndTestHandler.h @@ -13,8 +13,15 @@ #ifndef cmCTestBuildAndTestHandler_h #define cmCTestBuildAndTestHandler_h +#include + #include "cmCTestGenericHandler.h" -#include "cmListFileCache.h" +#include "cmTypeMacro.h" + +#include +#include +#include +#include class cmake; diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx index 408a1a8..91603d7 100644 --- a/Source/CTest/cmCTestBuildCommand.cxx +++ b/Source/CTest/cmCTestBuildCommand.cxx @@ -15,8 +15,15 @@ #include "cmCTestBuildHandler.h" #include "cmCTestGenericHandler.h" #include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" #include "cmake.h" +#include +#include + +class cmExecutionStatus; + cmCTestBuildCommand::cmCTestBuildCommand() { this->GlobalGenerator = CM_NULLPTR; diff --git a/Source/CTest/cmCTestBuildCommand.h b/Source/CTest/cmCTestBuildCommand.h index 92ae216..393c66e 100644 --- a/Source/CTest/cmCTestBuildCommand.h +++ b/Source/CTest/cmCTestBuildCommand.h @@ -12,10 +12,19 @@ #ifndef cmCTestBuildCommand_h #define cmCTestBuildCommand_h +#include + #include "cmCTestHandlerCommand.h" +#include "cmTypeMacro.h" + +#include +#include -class cmGlobalGenerator; class cmCTestBuildHandler; +class cmCTestGenericHandler; +class cmCommand; +class cmExecutionStatus; +class cmGlobalGenerator; /** \class cmCTestBuild * \brief Run a ctest script diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index 230e8c5..cdf292c 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -16,25 +16,16 @@ #include "cmCTest.h" #include "cmFileTimeComparison.h" #include "cmGeneratedFileStream.h" -#include "cmGlobalGenerator.h" #include "cmMakefile.h" +#include "cmSystemTools.h" #include "cmXMLWriter.h" -#include "cmake.h" -//#include #include #include #include - -// used for sleep -#ifdef _WIN32 -#include "windows.h" -#endif - -#include -#include +#include #include -#include +#include static const char* cmCTestErrorMatches[] = { "^[Bb]us [Ee]rror", diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h index 8cc5f01..764dfed 100644 --- a/Source/CTest/cmCTestBuildHandler.h +++ b/Source/CTest/cmCTestBuildHandler.h @@ -13,13 +13,17 @@ #ifndef cmCTestBuildHandler_h #define cmCTestBuildHandler_h -#include "cmCTestGenericHandler.h" +#include -#include "cmListFileCache.h" +#include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" #include - #include +#include +#include +#include +#include class cmMakefile; class cmXMLWriter; @@ -148,6 +152,7 @@ private: bool UseCTestLaunch; std::string CTestLaunchDir; class LaunchHelper; + friend class LaunchHelper; class FragmentCompare; }; diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx index fb96308..64054d3 100644 --- a/Source/CTest/cmCTestCVS.cxx +++ b/Source/CTest/cmCTestCVS.cxx @@ -12,11 +12,13 @@ #include "cmCTestCVS.h" #include "cmCTest.h" +#include "cmProcessTools.h" #include "cmSystemTools.h" #include "cmXMLWriter.h" #include #include +#include cmCTestCVS::cmCTestCVS(cmCTest* ct, std::ostream& log) : cmCTestVC(ct, log) diff --git a/Source/CTest/cmCTestCVS.h b/Source/CTest/cmCTestCVS.h index 67d162d..c1450b1 100644 --- a/Source/CTest/cmCTestCVS.h +++ b/Source/CTest/cmCTestCVS.h @@ -12,11 +12,18 @@ #ifndef cmCTestCVS_h #define cmCTestCVS_h +#include + #include "cmCTestVC.h" +#include #include +#include #include +class cmCTest; +class cmXMLWriter; + /** \class cmCTestCVS * \brief Interaction with cvs command-line tool * @@ -47,10 +54,11 @@ private: Directory const& dir); // Parsing helper classes. - class UpdateParser; class LogParser; - friend class UpdateParser; + class UpdateParser; + friend class LogParser; + friend class UpdateParser; }; #endif diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx index a823704..98e38d3 100644 --- a/Source/CTest/cmCTestConfigureCommand.cxx +++ b/Source/CTest/cmCTestConfigureCommand.cxx @@ -14,6 +14,13 @@ #include "cmCTest.h" #include "cmCTestGenericHandler.h" #include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" +#include "cmake.h" + +#include +#include +#include cmCTestConfigureCommand::cmCTestConfigureCommand() { diff --git a/Source/CTest/cmCTestConfigureCommand.h b/Source/CTest/cmCTestConfigureCommand.h index a97f9f0..9027b6b 100644 --- a/Source/CTest/cmCTestConfigureCommand.h +++ b/Source/CTest/cmCTestConfigureCommand.h @@ -12,7 +12,15 @@ #ifndef cmCTestConfigureCommand_h #define cmCTestConfigureCommand_h +#include + #include "cmCTestHandlerCommand.h" +#include "cmTypeMacro.h" + +#include + +class cmCTestGenericHandler; +class cmCommand; /** \class cmCTestConfigure * \brief Run a ctest script diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx index b99455f..78fa910 100644 --- a/Source/CTest/cmCTestConfigureHandler.cxx +++ b/Source/CTest/cmCTestConfigureHandler.cxx @@ -14,9 +14,11 @@ #include "cmCTest.h" #include "cmGeneratedFileStream.h" +#include "cmSystemTools.h" #include "cmXMLWriter.h" -#include "cmake.h" -#include + +#include +#include cmCTestConfigureHandler::cmCTestConfigureHandler() { diff --git a/Source/CTest/cmCTestConfigureHandler.h b/Source/CTest/cmCTestConfigureHandler.h index a7de939..a7d2167 100644 --- a/Source/CTest/cmCTestConfigureHandler.h +++ b/Source/CTest/cmCTestConfigureHandler.h @@ -13,9 +13,10 @@ #ifndef cmCTestConfigureHandler_h #define cmCTestConfigureHandler_h -#include "cmCTestGenericHandler.h" +#include -#include "cmListFileCache.h" +#include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" /** \class cmCTestConfigureHandler * \brief A class that handles ctest -S invocations diff --git a/Source/CTest/cmCTestCoverageCommand.cxx b/Source/CTest/cmCTestCoverageCommand.cxx index 86e3ce4..7a4271e 100644 --- a/Source/CTest/cmCTestCoverageCommand.cxx +++ b/Source/CTest/cmCTestCoverageCommand.cxx @@ -14,6 +14,8 @@ #include "cmCTest.h" #include "cmCTestCoverageHandler.h" +class cmCTestGenericHandler; + cmCTestCoverageCommand::cmCTestCoverageCommand() { this->LabelsMentioned = false; diff --git a/Source/CTest/cmCTestCoverageCommand.h b/Source/CTest/cmCTestCoverageCommand.h index ffd5fec..b9ef53d 100644 --- a/Source/CTest/cmCTestCoverageCommand.h +++ b/Source/CTest/cmCTestCoverageCommand.h @@ -12,7 +12,16 @@ #ifndef cmCTestCoverageCommand_h #define cmCTestCoverageCommand_h +#include + #include "cmCTestHandlerCommand.h" +#include "cmTypeMacro.h" + +#include +#include + +class cmCTestGenericHandler; +class cmCommand; /** \class cmCTestCoverage * \brief Run a ctest script diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index dd6eb3a..2eb64bf 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -13,7 +13,6 @@ #include "cmCTest.h" #include "cmGeneratedFileStream.h" -#include "cmMakefile.h" #include "cmParseBlanketJSCoverage.h" #include "cmParseCacheCoverage.h" #include "cmParseCoberturaCoverage.h" @@ -25,14 +24,19 @@ #include "cmXMLWriter.h" #include "cmake.h" +#include #include #include #include #include - -#include -#include +#include +#include +#include +#include #include +#include + +class cmMakefile; #define SAFEDIV(x, y) (((y) != 0) ? ((x) / (y)) : (0)) diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h index 60fea48..12a7e19 100644 --- a/Source/CTest/cmCTestCoverageHandler.h +++ b/Source/CTest/cmCTestCoverageHandler.h @@ -13,14 +13,22 @@ #ifndef cmCTestCoverageHandler_h #define cmCTestCoverageHandler_h -#include "cmCTestGenericHandler.h" +#include -#include "cmListFileCache.h" +#include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" #include +#include +#include +#include +#include +#include class cmGeneratedFileStream; +class cmMakefile; class cmXMLWriter; + class cmCTestCoverageHandlerContainer { public: diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx index 6910f6f..941df29 100644 --- a/Source/CTest/cmCTestCurl.cxx +++ b/Source/CTest/cmCTestCurl.cxx @@ -14,6 +14,10 @@ #include "cmCTest.h" #include "cmSystemTools.h" +#include +#include +#include + cmCTestCurl::cmCTestCurl(cmCTest* ctest) { this->CTest = ctest; diff --git a/Source/CTest/cmCTestCurl.h b/Source/CTest/cmCTestCurl.h index 82601e3..c91c88c 100644 --- a/Source/CTest/cmCTestCurl.h +++ b/Source/CTest/cmCTestCurl.h @@ -12,9 +12,11 @@ #ifndef cmCTestCurl_h #define cmCTestCurl_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep -#include "cm_curl.h" +#include +#include +#include class cmCTest; diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx index 09ae1fc..cc0b013 100644 --- a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx +++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx @@ -13,6 +13,10 @@ #include "cmCTestScriptHandler.h" +#include + +class cmExecutionStatus; + bool cmCTestEmptyBinaryDirectoryCommand::InitialPass( std::vector const& args, cmExecutionStatus& /*unused*/) { diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h index acacbcb..a64e55a 100644 --- a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h +++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h @@ -12,7 +12,16 @@ #ifndef cmCTestEmptyBinaryDirectoryCommand_h #define cmCTestEmptyBinaryDirectoryCommand_h +#include + #include "cmCTestCommand.h" +#include "cmTypeMacro.h" + +#include +#include + +class cmCommand; +class cmExecutionStatus; /** \class cmCTestEmptyBinaryDirectory * \brief Run a ctest script diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx index 61dbe33..cec871f 100644 --- a/Source/CTest/cmCTestGIT.cxx +++ b/Source/CTest/cmCTestGIT.cxx @@ -13,15 +13,17 @@ #include "cmAlgorithms.h" #include "cmCTest.h" +#include "cmCTestVC.h" +#include "cmProcessTools.h" #include "cmSystemTools.h" #include #include -#include - #include -#include +#include +#include #include +#include static unsigned int cmCTestGITVersion(unsigned int epic, unsigned int major, unsigned int minor, unsigned int fix) diff --git a/Source/CTest/cmCTestGIT.h b/Source/CTest/cmCTestGIT.h index 85298cb..d61d155 100644 --- a/Source/CTest/cmCTestGIT.h +++ b/Source/CTest/cmCTestGIT.h @@ -12,8 +12,15 @@ #ifndef cmCTestGIT_h #define cmCTestGIT_h +#include + #include "cmCTestGlobalVC.h" +#include +#include + +class cmCTest; + /** \class cmCTestGIT * \brief Interaction with git command-line tool * @@ -47,12 +54,13 @@ private: // "public" needed by older Sun compilers public: // Parsing helper classes. - class OneLineParser; - class DiffParser; class CommitParser; - friend class OneLineParser; - friend class DiffParser; + class DiffParser; + class OneLineParser; + friend class CommitParser; + friend class DiffParser; + friend class OneLineParser; }; #endif diff --git a/Source/CTest/cmCTestGenericHandler.cxx b/Source/CTest/cmCTestGenericHandler.cxx index 7755ee9..aab1781 100644 --- a/Source/CTest/cmCTestGenericHandler.cxx +++ b/Source/CTest/cmCTestGenericHandler.cxx @@ -12,9 +12,11 @@ #include "cmCTestGenericHandler.h" +#include "cmCTest.h" #include "cmSystemTools.h" -#include "cmCTest.h" +#include +#include cmCTestGenericHandler::cmCTestGenericHandler() { diff --git a/Source/CTest/cmCTestGenericHandler.h b/Source/CTest/cmCTestGenericHandler.h index 9949c3a..88905ed 100644 --- a/Source/CTest/cmCTestGenericHandler.h +++ b/Source/CTest/cmCTestGenericHandler.h @@ -13,14 +13,20 @@ #ifndef cmCTestGenericHandler_h #define cmCTestGenericHandler_h -#include "cmObject.h" +#include #include "cmCTest.h" -#include "cmSystemTools.h" //OutputOption +#include "cmObject.h" +#include "cmSystemTools.h" + +#include +#include +#include +#include -class cmMakefile; class cmCTestCommand; class cmGeneratedFileStream; +class cmMakefile; /** \class cmCTestGenericHandler * \brief A superclass of all CTest Handlers diff --git a/Source/CTest/cmCTestGlobalVC.cxx b/Source/CTest/cmCTestGlobalVC.cxx index 0c7ca4d..c575853 100644 --- a/Source/CTest/cmCTestGlobalVC.cxx +++ b/Source/CTest/cmCTestGlobalVC.cxx @@ -15,7 +15,8 @@ #include "cmSystemTools.h" #include "cmXMLWriter.h" -#include +#include +#include cmCTestGlobalVC::cmCTestGlobalVC(cmCTest* ct, std::ostream& log) : cmCTestVC(ct, log) diff --git a/Source/CTest/cmCTestGlobalVC.h b/Source/CTest/cmCTestGlobalVC.h index d42d2f2..b48b835 100644 --- a/Source/CTest/cmCTestGlobalVC.h +++ b/Source/CTest/cmCTestGlobalVC.h @@ -12,12 +12,19 @@ #ifndef cmCTestGlobalVC_h #define cmCTestGlobalVC_h +#include + #include "cmCTestVC.h" +#include #include #include +#include #include +class cmCTest; +class cmXMLWriter; + /** \class cmCTestGlobalVC * \brief Base class for handling globally-versioned trees * diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx index 3e62a1a..c576cf0 100644 --- a/Source/CTest/cmCTestHG.cxx +++ b/Source/CTest/cmCTestHG.cxx @@ -12,10 +12,14 @@ #include "cmCTestHG.h" #include "cmCTest.h" +#include "cmCTestVC.h" +#include "cmProcessTools.h" #include "cmSystemTools.h" #include "cmXMLParser.h" #include +#include +#include cmCTestHG::cmCTestHG(cmCTest* ct, std::ostream& log) : cmCTestGlobalVC(ct, log) diff --git a/Source/CTest/cmCTestHG.h b/Source/CTest/cmCTestHG.h index c4ce08c..08b479c 100644 --- a/Source/CTest/cmCTestHG.h +++ b/Source/CTest/cmCTestHG.h @@ -12,8 +12,15 @@ #ifndef cmCTestHG_h #define cmCTestHG_h +#include + #include "cmCTestGlobalVC.h" +#include +#include + +class cmCTest; + /** \class cmCTestHG * \brief Interaction with Mercurial command-line tool * @@ -37,11 +44,12 @@ private: // Parsing helper classes. class IdentifyParser; - class StatusParser; class LogParser; + class StatusParser; + friend class IdentifyParser; - friend class StatusParser; friend class LogParser; + friend class StatusParser; }; #endif diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index 325f8a3..e8e2956 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -13,6 +13,14 @@ #include "cmCTest.h" #include "cmCTestGenericHandler.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" +#include "cmake.h" + +#include +#include + +class cmExecutionStatus; cmCTestHandlerCommand::cmCTestHandlerCommand() { diff --git a/Source/CTest/cmCTestHandlerCommand.h b/Source/CTest/cmCTestHandlerCommand.h index 0468bbc..7c9fd50 100644 --- a/Source/CTest/cmCTestHandlerCommand.h +++ b/Source/CTest/cmCTestHandlerCommand.h @@ -12,9 +12,17 @@ #ifndef cmCTestHandlerCommand_h #define cmCTestHandlerCommand_h +#include + #include "cmCTestCommand.h" +#include "cmTypeMacro.h" + +#include +#include +#include class cmCTestGenericHandler; +class cmExecutionStatus; /** \class cmCTestHandler * \brief Run a ctest script diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx index fedcb1f..333f4a0 100644 --- a/Source/CTest/cmCTestLaunch.cxx +++ b/Source/CTest/cmCTestLaunch.cxx @@ -11,15 +11,24 @@ ============================================================================*/ #include "cmCTestLaunch.h" +#include + #include "cmGeneratedFileStream.h" +#include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmState.h" #include "cmSystemTools.h" #include "cmXMLWriter.h" #include "cmake.h" +#include #include #include #include #include +#include +#include +#include #ifdef _WIN32 #include // for _O_BINARY @@ -608,10 +617,6 @@ int cmCTestLaunch::Main(int argc, const char* const argv[]) return self.Run(); } -#include "cmGlobalGenerator.h" -#include "cmMakefile.h" -#include "cmake.h" -#include void cmCTestLaunch::LoadConfig() { cmake cm; diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h index cbcc9ec..5f465ac 100644 --- a/Source/CTest/cmCTestLaunch.h +++ b/Source/CTest/cmCTestLaunch.h @@ -12,9 +12,12 @@ #ifndef cmCTestLaunch_h #define cmCTestLaunch_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include +#include +#include +#include class cmXMLWriter; diff --git a/Source/CTest/cmCTestMemCheckCommand.h b/Source/CTest/cmCTestMemCheckCommand.h index 2ba33ae..69f77af 100644 --- a/Source/CTest/cmCTestMemCheckCommand.h +++ b/Source/CTest/cmCTestMemCheckCommand.h @@ -12,9 +12,15 @@ #ifndef cmCTestMemCheckCommand_h #define cmCTestMemCheckCommand_h +#include + #include "cmCTestTestCommand.h" +#include "cmTypeMacro.h" + +#include class cmCTestGenericHandler; +class cmCommand; /** \class cmCTestMemCheck * \brief Run a ctest script diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index 7d0715f..7a975dd 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -13,20 +13,16 @@ #include "cmCTestMemCheckHandler.h" #include "cmCTest.h" -#include "cmGeneratedFileStream.h" -#include "cmMakefile.h" +#include "cmSystemTools.h" #include "cmXMLParser.h" #include "cmXMLWriter.h" -#include "cmake.h" -#include + #include #include -#include #include - -#include -#include -#include +#include +#include +#include struct CatToErrorType { diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h index a005d54..a4ff684 100644 --- a/Source/CTest/cmCTestMemCheckHandler.h +++ b/Source/CTest/cmCTestMemCheckHandler.h @@ -13,9 +13,11 @@ #ifndef cmCTestMemCheckHandler_h #define cmCTestMemCheckHandler_h +#include + #include "cmCTestTestHandler.h" +#include "cmTypeMacro.h" -#include "cmListFileCache.h" #include #include diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 2632870..d65c915 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -12,17 +12,22 @@ #include "cmCTestMultiProcessHandler.h" #include "cmCTest.h" +#include "cmCTestRunTest.h" #include "cmCTestScriptHandler.h" -#include "cmProcess.h" -#include "cmStandardIncludes.h" +#include "cmCTestTestHandler.h" #include "cmSystemTools.h" + +#include #include +#include #include -#include +#include #include #include +#include #include #include +#include class TestComparator { diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h index 9ec1528..08068c5 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.h +++ b/Source/CTest/cmCTestMultiProcessHandler.h @@ -12,9 +12,17 @@ #ifndef cmCTestMultiProcessHandler_h #define cmCTestMultiProcessHandler_h -#include +#include // IWYU pragma: keep -#include +#include +#include +#include +#include +#include +#include + +class cmCTest; +class cmCTestRunTest; /** \class cmCTestMultiProcessHandler * \brief run parallel ctest diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx index 82422a3..cf7b2ca 100644 --- a/Source/CTest/cmCTestP4.cxx +++ b/Source/CTest/cmCTestP4.cxx @@ -12,14 +12,15 @@ #include "cmCTestP4.h" #include "cmCTest.h" +#include "cmCTestVC.h" +#include "cmProcessTools.h" #include "cmSystemTools.h" -#include +#include #include - -#include -#include +#include #include +#include cmCTestP4::cmCTestP4(cmCTest* ct, std::ostream& log) : cmCTestGlobalVC(ct, log) diff --git a/Source/CTest/cmCTestP4.h b/Source/CTest/cmCTestP4.h index 84e4f96..549936b 100644 --- a/Source/CTest/cmCTestP4.h +++ b/Source/CTest/cmCTestP4.h @@ -12,11 +12,17 @@ #ifndef cmCTestP4_h #define cmCTestP4_h +#include + #include "cmCTestGlobalVC.h" +#include #include +#include #include +class cmCTest; + /** \class cmCTestP4 * \brief Interaction with the Perforce command-line tool * @@ -62,12 +68,13 @@ private: void LoadRevisions() CM_OVERRIDE; void LoadModifications() CM_OVERRIDE; - // Parsing helper classes. - class IdentifyParser; class ChangesParser; - class UserParser; class DescribeParser; class DiffParser; + // Parsing helper classes. + class IdentifyParser; + class UserParser; + friend class IdentifyParser; friend class ChangesParser; friend class UserParser; diff --git a/Source/CTest/cmCTestReadCustomFilesCommand.cxx b/Source/CTest/cmCTestReadCustomFilesCommand.cxx index 24e985d..50a00f6 100644 --- a/Source/CTest/cmCTestReadCustomFilesCommand.cxx +++ b/Source/CTest/cmCTestReadCustomFilesCommand.cxx @@ -13,6 +13,8 @@ #include "cmCTest.h" +class cmExecutionStatus; + bool cmCTestReadCustomFilesCommand::InitialPass( std::vector const& args, cmExecutionStatus& /*unused*/) { diff --git a/Source/CTest/cmCTestReadCustomFilesCommand.h b/Source/CTest/cmCTestReadCustomFilesCommand.h index 6cce7c8..4dcde62 100644 --- a/Source/CTest/cmCTestReadCustomFilesCommand.h +++ b/Source/CTest/cmCTestReadCustomFilesCommand.h @@ -12,7 +12,16 @@ #ifndef cmCTestReadCustomFilesCommand_h #define cmCTestReadCustomFilesCommand_h +#include + #include "cmCTestCommand.h" +#include "cmTypeMacro.h" + +#include +#include + +class cmCommand; +class cmExecutionStatus; /** \class cmCTestReadCustomFiles * \brief Run a ctest script diff --git a/Source/CTest/cmCTestRunScriptCommand.cxx b/Source/CTest/cmCTestRunScriptCommand.cxx index 32bf28f..29aa279 100644 --- a/Source/CTest/cmCTestRunScriptCommand.cxx +++ b/Source/CTest/cmCTestRunScriptCommand.cxx @@ -12,6 +12,11 @@ #include "cmCTestRunScriptCommand.h" #include "cmCTestScriptHandler.h" +#include "cmMakefile.h" + +#include + +class cmExecutionStatus; bool cmCTestRunScriptCommand::InitialPass(std::vector const& args, cmExecutionStatus& /*unused*/) diff --git a/Source/CTest/cmCTestRunScriptCommand.h b/Source/CTest/cmCTestRunScriptCommand.h index 9ea0999..9705f57 100644 --- a/Source/CTest/cmCTestRunScriptCommand.h +++ b/Source/CTest/cmCTestRunScriptCommand.h @@ -12,7 +12,16 @@ #ifndef cmCTestRunScriptCommand_h #define cmCTestRunScriptCommand_h +#include + #include "cmCTestCommand.h" +#include "cmTypeMacro.h" + +#include +#include + +class cmCommand; +class cmExecutionStatus; /** \class cmCTestRunScript * \brief Run a ctest script diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 49acbbf..e7e51d5 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -14,11 +14,21 @@ #include "cmCTest.h" #include "cmCTestMemCheckHandler.h" +#include "cmCTestTestHandler.h" +#include "cmProcess.h" #include "cmSystemTools.h" -#include "cm_curl.h" +#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler) { diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index 3dcc026..0ca434d 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -12,9 +12,15 @@ #ifndef cmCTestRunTest_h #define cmCTestRunTest_h +#include // IWYU pragma: keep + #include +#include +#include +#include -#include +class cmCTest; +class cmProcess; /** \class cmRunTest * \brief represents a single test to be run diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx index bee8296..f680612 100644 --- a/Source/CTest/cmCTestSVN.cxx +++ b/Source/CTest/cmCTestSVN.cxx @@ -12,11 +12,17 @@ #include "cmCTestSVN.h" #include "cmCTest.h" +#include "cmCTestVC.h" +#include "cmProcessTools.h" #include "cmSystemTools.h" #include "cmXMLParser.h" #include "cmXMLWriter.h" #include +#include +#include +#include +#include struct cmCTestSVN::Revision : public cmCTestVC::Revision { diff --git a/Source/CTest/cmCTestSVN.h b/Source/CTest/cmCTestSVN.h index 4f3eb88..6f2374d 100644 --- a/Source/CTest/cmCTestSVN.h +++ b/Source/CTest/cmCTestSVN.h @@ -12,9 +12,17 @@ #ifndef cmCTestSVN_h #define cmCTestSVN_h +#include + #include "cmCTestGlobalVC.h" +#include #include +#include +#include + +class cmCTest; +class cmXMLWriter; /** \class cmCTestSVN * \brief Interaction with subversion command-line tool @@ -68,6 +76,7 @@ private: // Extended revision structure to include info about external it refers to. struct Revision; + friend struct Revision; // Info of all the repositories (root, externals and nested ones). @@ -89,12 +98,13 @@ private: void WriteXMLGlobal(cmXMLWriter& xml) CM_OVERRIDE; + class ExternalParser; // Parsing helper classes. class InfoParser; class LogParser; class StatusParser; class UpdateParser; - class ExternalParser; + friend class InfoParser; friend class LogParser; friend class StatusParser; diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index 44427b0..a31d789 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -13,32 +13,8 @@ #include "cmCTestScriptHandler.h" #include "cmCTest.h" -#include "cmFunctionBlocker.h" -#include "cmGeneratedFileStream.h" -#include "cmGlobalGenerator.h" -#include "cmMakefile.h" -#include "cmake.h" - -//#include -#include -#include - -// used for sleep -#ifdef _WIN32 -#include "windows.h" -#endif - -#include -#include -#include -#include - -// needed for sleep -#if !defined(_WIN32) -#include -#endif - #include "cmCTestBuildCommand.h" +#include "cmCTestCommand.h" #include "cmCTestConfigureCommand.h" #include "cmCTestCoverageCommand.h" #include "cmCTestEmptyBinaryDirectoryCommand.h" @@ -51,6 +27,31 @@ #include "cmCTestTestCommand.h" #include "cmCTestUpdateCommand.h" #include "cmCTestUploadCommand.h" +#include "cmFunctionBlocker.h" +#include "cmGeneratedFileStream.h" +#include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmState.h" +#include "cmSystemTools.h" +#include "cmake.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +class cmExecutionStatus; +struct cmListFileFunction; #define CTEST_INITIAL_CMAKE_OUTPUT_FILE_NAME "CTestInitialCMakeOutput.log" diff --git a/Source/CTest/cmCTestScriptHandler.h b/Source/CTest/cmCTestScriptHandler.h index 4403030..17d7aef 100644 --- a/Source/CTest/cmCTestScriptHandler.h +++ b/Source/CTest/cmCTestScriptHandler.h @@ -13,14 +13,19 @@ #ifndef cmCTestScriptHandler_h #define cmCTestScriptHandler_h +#include + #include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" -#include "cmListFileCache.h" +#include +#include -class cmMakefile; +class cmCTest; +class cmCTestCommand; class cmGlobalGenerator; +class cmMakefile; class cmake; -class cmCTestCommand; /** \class cmCTestScriptHandler * \brief A class that handles ctest -S invocations diff --git a/Source/CTest/cmCTestSleepCommand.cxx b/Source/CTest/cmCTestSleepCommand.cxx index 464f025..0954a7e 100644 --- a/Source/CTest/cmCTestSleepCommand.cxx +++ b/Source/CTest/cmCTestSleepCommand.cxx @@ -12,7 +12,10 @@ #include "cmCTestSleepCommand.h" #include "cmCTestScriptHandler.h" -#include // required for atoi + +#include + +class cmExecutionStatus; bool cmCTestSleepCommand::InitialPass(std::vector const& args, cmExecutionStatus& /*unused*/) diff --git a/Source/CTest/cmCTestSleepCommand.h b/Source/CTest/cmCTestSleepCommand.h index 7981fa2..2a3fa00 100644 --- a/Source/CTest/cmCTestSleepCommand.h +++ b/Source/CTest/cmCTestSleepCommand.h @@ -12,7 +12,16 @@ #ifndef cmCTestSleepCommand_h #define cmCTestSleepCommand_h +#include + #include "cmCTestCommand.h" +#include "cmTypeMacro.h" + +#include +#include + +class cmCommand; +class cmExecutionStatus; /** \class cmCTestSleep * \brief Run a ctest script diff --git a/Source/CTest/cmCTestStartCommand.cxx b/Source/CTest/cmCTestStartCommand.cxx index 04d2f03..803e01c 100644 --- a/Source/CTest/cmCTestStartCommand.cxx +++ b/Source/CTest/cmCTestStartCommand.cxx @@ -14,7 +14,13 @@ #include "cmCTest.h" #include "cmCTestVC.h" #include "cmGeneratedFileStream.h" -#include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" + +#include +#include + +class cmExecutionStatus; cmCTestStartCommand::cmCTestStartCommand() { diff --git a/Source/CTest/cmCTestStartCommand.h b/Source/CTest/cmCTestStartCommand.h index e3f8f8b..22035fa 100644 --- a/Source/CTest/cmCTestStartCommand.h +++ b/Source/CTest/cmCTestStartCommand.h @@ -12,7 +12,17 @@ #ifndef cmCTestStartCommand_h #define cmCTestStartCommand_h +#include + #include "cmCTestCommand.h" +#include "cmTypeMacro.h" + +#include +#include +#include + +class cmCommand; +class cmExecutionStatus; /** \class cmCTestStart * \brief Run a ctest script diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx index 54da383..c7c3584 100644 --- a/Source/CTest/cmCTestSubmitCommand.cxx +++ b/Source/CTest/cmCTestSubmitCommand.cxx @@ -14,6 +14,13 @@ #include "cmCTest.h" #include "cmCTestGenericHandler.h" #include "cmCTestSubmitHandler.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" +#include "cmake.h" + +#include + +class cmExecutionStatus; cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler() { diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h index 7c3d6cd..03165bf 100644 --- a/Source/CTest/cmCTestSubmitCommand.h +++ b/Source/CTest/cmCTestSubmitCommand.h @@ -12,9 +12,19 @@ #ifndef cmCTestSubmitCommand_h #define cmCTestSubmitCommand_h -#include "cmCTestHandlerCommand.h" +#include #include "cmCTest.h" +#include "cmCTestHandlerCommand.h" +#include "cmTypeMacro.h" + +#include +#include +#include + +class cmCTestGenericHandler; +class cmCommand; +class cmExecutionStatus; /** \class cmCTestSubmit * \brief Run a ctest script diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 42727d0..67f7c89 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -12,26 +12,28 @@ #include "cmCTestSubmitHandler.h" #include "cmCTest.h" +#include "cmCTestCurl.h" #include "cmCTestScriptHandler.h" +#include "cmCurl.h" #include "cmGeneratedFileStream.h" #include "cmState.h" #include "cmSystemTools.h" -#include "cmVersion.h" #include "cmXMLParser.h" #include "cmake.h" -#include -#include - -// For XML-RPC submission -#include "cm_xmlrpc.h" - +#include #include -// For curl submission -#include "cmCTestCurl.h" -#include "cmCurl.h" +#include +#include +#include +#include +#include +#if defined(CTEST_USE_XMLRPC) +#include "cmVersion.h" +#include #include +#endif #define SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT 120 diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h index 4cca6eb..0e5aea6 100644 --- a/Source/CTest/cmCTestSubmitHandler.h +++ b/Source/CTest/cmCTestSubmitHandler.h @@ -12,7 +12,16 @@ #ifndef cmCTestSubmitHandler_h #define cmCTestSubmitHandler_h +#include + +#include "cmCTest.h" #include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" + +#include +#include +#include +#include /** \class cmCTestSubmitHandler * \brief Helper class for CTest @@ -84,6 +93,7 @@ private: std::string GetSubmitResultsPrefix(); class ResponseParser; + std::string HTTPProxy; int HTTPProxyType; std::string HTTPProxyAuth; diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx index 1d064db..8ac4c69 100644 --- a/Source/CTest/cmCTestTestCommand.cxx +++ b/Source/CTest/cmCTestTestCommand.cxx @@ -13,6 +13,12 @@ #include "cmCTest.h" #include "cmCTestGenericHandler.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" + +#include +#include +#include cmCTestTestCommand::cmCTestTestCommand() { diff --git a/Source/CTest/cmCTestTestCommand.h b/Source/CTest/cmCTestTestCommand.h index f652971..89e37b9 100644 --- a/Source/CTest/cmCTestTestCommand.h +++ b/Source/CTest/cmCTestTestCommand.h @@ -12,7 +12,15 @@ #ifndef cmCTestTestCommand_h #define cmCTestTestCommand_h +#include + #include "cmCTestHandlerCommand.h" +#include "cmTypeMacro.h" + +#include + +class cmCTestGenericHandler; +class cmCommand; /** \class cmCTestTest * \brief Run a ctest script diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 3ce0317..479c516 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -15,26 +15,32 @@ #include "cmCTest.h" #include "cmCTestBatchTestHandler.h" #include "cmCTestMultiProcessHandler.h" -#include "cmCTestRunTest.h" #include "cmCommand.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" +#include "cmState.h" #include "cmSystemTools.h" #include "cmXMLWriter.h" +#include "cm_auto_ptr.hxx" #include "cm_utf8.h" #include "cmake.h" + +#include #include #include #include -#include #include - -#include -#include +#include +#include +#include +#include +#include #include +#include +#include -#include +class cmExecutionStatus; class cmCTestSubdirCommand : public cmCommand { diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index a085a82..a5e62dc 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -13,10 +13,21 @@ #ifndef cmCTestTestHandler_h #define cmCTestTestHandler_h +#include + #include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" #include - +#include +#include +#include +#include +#include +#include +#include + +class cmCTest; class cmMakefile; class cmXMLWriter; diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx index bc06da6..53382c9 100644 --- a/Source/CTest/cmCTestUpdateCommand.cxx +++ b/Source/CTest/cmCTestUpdateCommand.cxx @@ -13,6 +13,10 @@ #include "cmCTest.h" #include "cmCTestGenericHandler.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" + +#include cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler() { diff --git a/Source/CTest/cmCTestUpdateCommand.h b/Source/CTest/cmCTestUpdateCommand.h index 6b5bbab..89470e1 100644 --- a/Source/CTest/cmCTestUpdateCommand.h +++ b/Source/CTest/cmCTestUpdateCommand.h @@ -12,7 +12,15 @@ #ifndef cmCTestUpdateCommand_h #define cmCTestUpdateCommand_h +#include + #include "cmCTestHandlerCommand.h" +#include "cmTypeMacro.h" + +#include + +class cmCTestGenericHandler; +class cmCommand; /** \class cmCTestUpdate * \brief Run a ctest script diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx index ac7eb05..bbb9430 100644 --- a/Source/CTest/cmCTestUpdateHandler.cxx +++ b/Source/CTest/cmCTestUpdateHandler.cxx @@ -14,14 +14,6 @@ #include "cmCLocaleEnvironmentScope.h" #include "cmCTest.h" -#include "cmGeneratedFileStream.h" -#include "cmGlobalGenerator.h" -#include "cmMakefile.h" -#include "cmVersion.h" -#include "cmXMLParser.h" -#include "cmXMLWriter.h" -#include "cmake.h" - #include "cmCTestBZR.h" #include "cmCTestCVS.h" #include "cmCTestGIT.h" @@ -29,20 +21,13 @@ #include "cmCTestP4.h" #include "cmCTestSVN.h" #include "cmCTestVC.h" +#include "cmGeneratedFileStream.h" +#include "cmSystemTools.h" +#include "cmVersion.h" +#include "cmXMLWriter.h" #include - -//#include -#include - -// used for sleep -#ifdef _WIN32 -#include "windows.h" -#endif - -#include -#include -#include +#include static const char* cmCTestUpdateHandlerUpdateStrings[] = { "Unknown", "CVS", "SVN", "BZR", "GIT", "HG", "P4" diff --git a/Source/CTest/cmCTestUpdateHandler.h b/Source/CTest/cmCTestUpdateHandler.h index 6733c8c..838ef0e 100644 --- a/Source/CTest/cmCTestUpdateHandler.h +++ b/Source/CTest/cmCTestUpdateHandler.h @@ -13,9 +13,14 @@ #ifndef cmCTestUpdateHandler_h #define cmCTestUpdateHandler_h +#include + #include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" -#include "cmListFileCache.h" +#include +#include +#include /** \class cmCTestUpdateHandler * \brief A class that handles ctest -S invocations diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx index 016b32b..5ea637e 100644 --- a/Source/CTest/cmCTestUploadCommand.cxx +++ b/Source/CTest/cmCTestUploadCommand.cxx @@ -14,6 +14,11 @@ #include "cmCTest.h" #include "cmCTestGenericHandler.h" #include "cmCTestUploadHandler.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" +#include "cmake.h" + +#include cmCTestGenericHandler* cmCTestUploadCommand::InitializeHandler() { diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h index 923995d..da291f3 100644 --- a/Source/CTest/cmCTestUploadCommand.h +++ b/Source/CTest/cmCTestUploadCommand.h @@ -12,9 +12,16 @@ #ifndef cmCTestUploadCommand_h #define cmCTestUploadCommand_h -#include "cmCTestHandlerCommand.h" +#include #include "cmCTest.h" +#include "cmCTestHandlerCommand.h" +#include "cmTypeMacro.h" + +#include + +class cmCTestGenericHandler; +class cmCommand; /** \class cmCTestUpload * \brief Run a ctest script diff --git a/Source/CTest/cmCTestUploadHandler.cxx b/Source/CTest/cmCTestUploadHandler.cxx index 6a3b830..07d3ad7 100644 --- a/Source/CTest/cmCTestUploadHandler.cxx +++ b/Source/CTest/cmCTestUploadHandler.cxx @@ -15,6 +15,10 @@ #include "cmVersion.h" #include "cmXMLWriter.h" +#include +#include +#include + cmCTestUploadHandler::cmCTestUploadHandler() { this->Initialize(); diff --git a/Source/CTest/cmCTestUploadHandler.h b/Source/CTest/cmCTestUploadHandler.h index 8b824d6..6503d08 100644 --- a/Source/CTest/cmCTestUploadHandler.h +++ b/Source/CTest/cmCTestUploadHandler.h @@ -12,7 +12,11 @@ #ifndef cmCTestUploadHandler_h #define cmCTestUploadHandler_h +#include + +#include "cmCTest.h" #include "cmCTestGenericHandler.h" +#include "cmTypeMacro.h" /** \class cmCTestUploadHandler * \brief Helper class for CTest diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx index 24557aa..182364b 100644 --- a/Source/CTest/cmCTestVC.cxx +++ b/Source/CTest/cmCTestVC.cxx @@ -16,6 +16,10 @@ #include "cmXMLWriter.h" #include +#include +#include +#include +#include cmCTestVC::cmCTestVC(cmCTest* ct, std::ostream& log) : CTest(ct) diff --git a/Source/CTest/cmCTestVC.h b/Source/CTest/cmCTestVC.h index eb85a23..8063e40 100644 --- a/Source/CTest/cmCTestVC.h +++ b/Source/CTest/cmCTestVC.h @@ -12,8 +12,13 @@ #ifndef cmCTestVC_h #define cmCTestVC_h +#include + #include "cmProcessTools.h" +#include +#include + class cmCTest; class cmXMLWriter; @@ -93,7 +98,6 @@ public: }; protected: - struct File; friend struct File; /** Represent change to one file. */ diff --git a/Source/CTest/cmParseBlanketJSCoverage.cxx b/Source/CTest/cmParseBlanketJSCoverage.cxx index 976a92d..28077ff 100644 --- a/Source/CTest/cmParseBlanketJSCoverage.cxx +++ b/Source/CTest/cmParseBlanketJSCoverage.cxx @@ -11,10 +11,11 @@ ============================================================================*/ #include "cmParseBlanketJSCoverage.h" +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" -#include + #include -#include #include #include diff --git a/Source/CTest/cmParseBlanketJSCoverage.h b/Source/CTest/cmParseBlanketJSCoverage.h index a4f6670..ece1efa 100644 --- a/Source/CTest/cmParseBlanketJSCoverage.h +++ b/Source/CTest/cmParseBlanketJSCoverage.h @@ -13,7 +13,13 @@ #ifndef cmParseBlanketJSCoverage_h #define cmParseBlanketJSCoverage_h -#include "cmCTestCoverageHandler.h" +#include // IWYU pragma: keep + +#include +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; /** \class cmParseBlanketJSCoverage * \brief Parse BlanketJS coverage information @@ -39,6 +45,7 @@ public: protected: class JSONParser; + cmCTestCoverageHandlerContainer& Coverage; cmCTest* CTest; }; diff --git a/Source/CTest/cmParseCacheCoverage.cxx b/Source/CTest/cmParseCacheCoverage.cxx index 0916da2..23176b5 100644 --- a/Source/CTest/cmParseCacheCoverage.cxx +++ b/Source/CTest/cmParseCacheCoverage.cxx @@ -1,11 +1,15 @@ #include "cmParseCacheCoverage.h" +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" + #include #include -#include +#include #include #include +#include cmParseCacheCoverage::cmParseCacheCoverage( cmCTestCoverageHandlerContainer& cont, cmCTest* ctest) diff --git a/Source/CTest/cmParseCacheCoverage.h b/Source/CTest/cmParseCacheCoverage.h index 65b1d10..4fa6c26 100644 --- a/Source/CTest/cmParseCacheCoverage.h +++ b/Source/CTest/cmParseCacheCoverage.h @@ -13,8 +13,16 @@ #ifndef cmParseCacheCoverage_h #define cmParseCacheCoverage_h +#include + #include "cmParseMumpsCoverage.h" +#include +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; + /** \class cmParseCacheCoverage * \brief Parse Cache coverage information * diff --git a/Source/CTest/cmParseCoberturaCoverage.cxx b/Source/CTest/cmParseCoberturaCoverage.cxx index 1a3fe3c..0b6d3ce 100644 --- a/Source/CTest/cmParseCoberturaCoverage.cxx +++ b/Source/CTest/cmParseCoberturaCoverage.cxx @@ -1,9 +1,14 @@ #include "cmParseCoberturaCoverage.h" +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" #include "cmXMLParser.h" -#include + +#include #include +#include +#include class cmParseCoberturaCoverage::XMLParser : public cmXMLParser { diff --git a/Source/CTest/cmParseCoberturaCoverage.h b/Source/CTest/cmParseCoberturaCoverage.h index 4fa6d10..f45ec95 100644 --- a/Source/CTest/cmParseCoberturaCoverage.h +++ b/Source/CTest/cmParseCoberturaCoverage.h @@ -13,7 +13,13 @@ #ifndef cmParseCoberturaCoverage_h #define cmParseCoberturaCoverage_h -#include "cmCTestCoverageHandler.h" +#include // IWYU pragma: keep + +#include +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; /** \class cmParsePythonCoverage * \brief Parse coverage.py Python coverage information @@ -40,6 +46,7 @@ public: private: class XMLParser; + cmCTestCoverageHandlerContainer& Coverage; cmCTest* CTest; std::string CurFileName; diff --git a/Source/CTest/cmParseDelphiCoverage.cxx b/Source/CTest/cmParseDelphiCoverage.cxx index 9d86ce9..7fe91f4 100644 --- a/Source/CTest/cmParseDelphiCoverage.cxx +++ b/Source/CTest/cmParseDelphiCoverage.cxx @@ -1,8 +1,9 @@ #include "cmParseDelphiCoverage.h" +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" -#include "cmXMLParser.h" -#include + #include #include #include diff --git a/Source/CTest/cmParseDelphiCoverage.h b/Source/CTest/cmParseDelphiCoverage.h index c1c495c..82557d9 100644 --- a/Source/CTest/cmParseDelphiCoverage.h +++ b/Source/CTest/cmParseDelphiCoverage.h @@ -13,7 +13,13 @@ #ifndef cmParseDelphiCoverage_h #define cmParseDelphiCoverage_h -#include "cmCTestCoverageHandler.h" +#include // IWYU pragma: keep + +#include +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; /** \class cmParseDelphiCoverage * \brief Parse Delphi coverage information @@ -35,6 +41,7 @@ public: protected: class HTMLParser; + cmCTestCoverageHandlerContainer& Coverage; cmCTest* CTest; }; diff --git a/Source/CTest/cmParseGTMCoverage.cxx b/Source/CTest/cmParseGTMCoverage.cxx index 33ad839..214ce5a 100644 --- a/Source/CTest/cmParseGTMCoverage.cxx +++ b/Source/CTest/cmParseGTMCoverage.cxx @@ -1,11 +1,15 @@ #include "cmParseGTMCoverage.h" +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" + #include #include -#include +#include #include #include +#include cmParseGTMCoverage::cmParseGTMCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest) diff --git a/Source/CTest/cmParseGTMCoverage.h b/Source/CTest/cmParseGTMCoverage.h index 4188689..623cd5a 100644 --- a/Source/CTest/cmParseGTMCoverage.h +++ b/Source/CTest/cmParseGTMCoverage.h @@ -13,8 +13,15 @@ #ifndef cmParseGTMCoverage_h #define cmParseGTMCoverage_h +#include + #include "cmParseMumpsCoverage.h" +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; + /** \class cmParseGTMCoverage * \brief Parse GTM coverage information * diff --git a/Source/CTest/cmParseJacocoCoverage.cxx b/Source/CTest/cmParseJacocoCoverage.cxx index bc05666..0e36c01 100644 --- a/Source/CTest/cmParseJacocoCoverage.cxx +++ b/Source/CTest/cmParseJacocoCoverage.cxx @@ -1,12 +1,17 @@ #include "cmParseJacocoCoverage.h" +#include + +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" #include "cmXMLParser.h" + #include #include #include -#include #include +#include class cmParseJacocoCoverage::XMLParser : public cmXMLParser { diff --git a/Source/CTest/cmParseJacocoCoverage.h b/Source/CTest/cmParseJacocoCoverage.h index bcd472e..4b94725 100644 --- a/Source/CTest/cmParseJacocoCoverage.h +++ b/Source/CTest/cmParseJacocoCoverage.h @@ -13,7 +13,14 @@ #ifndef cmParseJacocoCoverage_h #define cmParseJacocoCoverage_h -#include "cmCTestCoverageHandler.h" +#include // IWYU pragma: keep + +#include +#include +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; /** \class cmParseJacocoCoverage * \brief Parse JaCoCO coverage information @@ -47,6 +54,7 @@ private: bool LoadSource(std::string d); class XMLParser; + std::map RoutineToDirectory; cmCTestCoverageHandlerContainer& Coverage; cmCTest* CTest; diff --git a/Source/CTest/cmParseMumpsCoverage.cxx b/Source/CTest/cmParseMumpsCoverage.cxx index af01496..ab8be76 100644 --- a/Source/CTest/cmParseMumpsCoverage.cxx +++ b/Source/CTest/cmParseMumpsCoverage.cxx @@ -1,11 +1,16 @@ -#include "cmParseGTMCoverage.h" +#include "cmParseMumpsCoverage.h" +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" -#include + +#include #include #include -#include -#include +#include +#include +#include +#include cmParseMumpsCoverage::cmParseMumpsCoverage( cmCTestCoverageHandlerContainer& cont, cmCTest* ctest) diff --git a/Source/CTest/cmParseMumpsCoverage.h b/Source/CTest/cmParseMumpsCoverage.h index 3761ba6..8b33bd7 100644 --- a/Source/CTest/cmParseMumpsCoverage.h +++ b/Source/CTest/cmParseMumpsCoverage.h @@ -13,7 +13,13 @@ #ifndef cmParseMumpsCoverage_h #define cmParseMumpsCoverage_h -#include "cmCTestCoverageHandler.h" +#include // IWYU pragma: keep + +#include +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; /** \class cmParseMumpsCoverage * \brief Parse Mumps coverage information diff --git a/Source/CTest/cmParsePHPCoverage.cxx b/Source/CTest/cmParsePHPCoverage.cxx index 5ec2718..d8bb31b 100644 --- a/Source/CTest/cmParsePHPCoverage.cxx +++ b/Source/CTest/cmParsePHPCoverage.cxx @@ -1,8 +1,13 @@ #include "cmParsePHPCoverage.h" +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" + #include #include +#include +#include /* To setup coverage for php. diff --git a/Source/CTest/cmParsePHPCoverage.h b/Source/CTest/cmParsePHPCoverage.h index 72f9129..b261a8d 100644 --- a/Source/CTest/cmParsePHPCoverage.h +++ b/Source/CTest/cmParsePHPCoverage.h @@ -13,7 +13,13 @@ #ifndef cmParsePHPCoverage_h #define cmParsePHPCoverage_h -#include "cmCTestCoverageHandler.h" +#include // IWYU pragma: keep + +#include +#include + +class cmCTest; +class cmCTestCoverageHandlerContainer; /** \class cmParsePHPCoverage * \brief Parse xdebug PHP coverage information diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 30cd102..51aed79 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -9,10 +9,11 @@ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more information. ============================================================================*/ +#include "cmProcess.h" -#include - +#include #include +#include cmProcess::cmProcess() { diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h index d5e2721..2a6fa7c 100644 --- a/Source/CTest/cmProcess.h +++ b/Source/CTest/cmProcess.h @@ -12,9 +12,11 @@ #ifndef cmProcess_h #define cmProcess_h -#include "cmStandardIncludes.h" +#include // IWYU pragma: keep #include +#include +#include /** \class cmProcess * \brief run a process with c++ ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 09:48:10 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 09:48:10 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1429-ga668268 Message-ID: <20160825134810.A7F09F46C4@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via a668268d9bc890b5ec0bcc6670e399a33670674e (commit) via 1462576bcba68310395a7185e4b77da38e1e6b33 (commit) via 421012a330989a64b24a3289379bb4938e6ed3ea (commit) via 14a8d61fd49a9b990cbef7e1495e4763f31c55f2 (commit) via 2af853deb5225a9c8cb3d1e6311680c3fb7d86aa (commit) via 33bb9cfa365f494bb76ff9c2c78ad625e77152ec (commit) from e1f3f613573bc2a000ea94485be12dcfed588761 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a668268d9bc890b5ec0bcc6670e399a33670674e commit a668268d9bc890b5ec0bcc6670e399a33670674e Merge: e1f3f61 1462576 Author: Brad King AuthorDate: Thu Aug 25 09:48:09 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 09:48:09 2016 -0400 Merge topic 'extract-cmMessenger' into next 1462576b Parser: Port away from cmMakefile 421012a3 cmMessenger: Extract from cmake class 14a8d61f cmMakefile: Port nested error logic away from cmExecutionStatus 2af853de cmMakefile: Simplify IssueMessage implementation 33bb9cfa Parser: Issue messages through cmake, not cmSystemTools https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1462576bcba68310395a7185e4b77da38e1e6b33 commit 1462576bcba68310395a7185e4b77da38e1e6b33 Author: Stephen Kelly AuthorDate: Thu Jan 28 22:10:28 2016 +0100 Commit: Brad King CommitDate: Thu Aug 25 09:47:27 2016 -0400 Parser: Port away from cmMakefile It is an unneeded dependency. diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 9204d14..39d9e97 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -12,7 +12,7 @@ #include "cmListFileCache.h" #include "cmListFileLexer.h" -#include "cmMakefile.h" +#include "cmMessenger.h" #include "cmOutputConverter.h" #include "cmSystemTools.h" #include "cmVersion.h" @@ -21,7 +21,8 @@ struct cmListFileParser { - cmListFileParser(cmListFile* lf, cmMakefile* mf, const char* filename); + cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt, + cmMessenger* messenger, const char* filename); ~cmListFileParser(); void IssueFileOpenError(std::string const& text) const; void IssueError(std::string const& text) const; @@ -30,8 +31,8 @@ struct cmListFileParser bool AddArgument(cmListFileLexer_Token* token, cmListFileArgument::Delimiter delim); cmListFile* ListFile; - cmMakefile* Makefile; cmListFileBacktrace Backtrace; + cmMessenger* Messenger; const char* FileName; cmListFileLexer* Lexer; cmListFileFunction Function; @@ -43,11 +44,12 @@ struct cmListFileParser } Separation; }; -cmListFileParser::cmListFileParser(cmListFile* lf, cmMakefile* mf, +cmListFileParser::cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt, + cmMessenger* messenger, const char* filename) : ListFile(lf) - , Makefile(mf) - , Backtrace(mf->GetBacktrace()) + , Backtrace(lfbt) + , Messenger(messenger) , FileName(filename) , Lexer(cmListFileLexer_New()) { @@ -60,7 +62,7 @@ cmListFileParser::~cmListFileParser() void cmListFileParser::IssueFileOpenError(const std::string& text) const { - this->Makefile->IssueMessage(cmake::FATAL_ERROR, text); + this->Messenger->IssueMessage(cmake::FATAL_ERROR, text, this->Backtrace); } void cmListFileParser::IssueError(const std::string& text) const @@ -70,8 +72,7 @@ void cmListFileParser::IssueError(const std::string& text) const lfc.Line = cmListFileLexer_GetCurrentLine(this->Lexer); cmListFileBacktrace lfbt = this->Backtrace; lfbt = lfbt.Push(lfc); - this->Makefile->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, text, - lfbt); + this->Messenger->IssueMessage(cmake::FATAL_ERROR, text, lfbt); cmSystemTools::SetFatalErrorOccured(); } @@ -129,7 +130,8 @@ bool cmListFileParser::ParseFile() return true; } -bool cmListFile::ParseFile(const char* filename, cmMakefile* mf) +bool cmListFile::ParseFile(const char* filename, cmMessenger* messenger, + cmListFileBacktrace const& lfbt) { if (!cmSystemTools::FileExists(filename) || cmSystemTools::FileIsDirectory(filename)) { @@ -139,7 +141,7 @@ bool cmListFile::ParseFile(const char* filename, cmMakefile* mf) bool parseError = false; { - cmListFileParser parser(this, mf, filename); + cmListFileParser parser(this, lfbt, messenger, filename); parseError = !parser.ParseFile(); } @@ -242,8 +244,7 @@ bool cmListFileParser::ParseFunction(const char* name, long line) lfbt = lfbt.Push(lfc); error << "Parse error. Function missing ending \")\". " << "End of file reached."; - this->Makefile->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, - error.str(), lfbt); + this->Messenger->IssueMessage(cmake::FATAL_ERROR, error.str(), lfbt); return false; } @@ -269,10 +270,10 @@ bool cmListFileParser::AddArgument(cmListFileLexer_Token* token, << "Argument not separated from preceding token by whitespace."; /* clang-format on */ if (isError) { - this->Makefile->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, m.str(), lfbt); + this->Messenger->IssueMessage(cmake::FATAL_ERROR, m.str(), lfbt); return false; } - this->Makefile->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING, m.str(), lfbt); + this->Messenger->IssueMessage(cmake::AUTHOR_WARNING, m.str(), lfbt); return true; } diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index f3e6f70..cd44536 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -23,7 +23,7 @@ * cmake list files. */ -class cmMakefile; +class cmMessenger; struct cmCommandContext { @@ -158,7 +158,8 @@ private: struct cmListFile { - bool ParseFile(const char* path, cmMakefile* mf); + bool ParseFile(const char* path, cmMessenger* messenger, + cmListFileBacktrace const& lfbt); std::vector Functions; }; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 6c83b06..6e47797 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -25,6 +25,7 @@ #include "cmGlobalGenerator.h" #include "cmInstallGenerator.h" #include "cmListFileCache.h" +#include "cmMessenger.h" #include "cmSourceFile.h" #include "cmSourceFileLocation.h" #include "cmState.h" @@ -457,7 +458,8 @@ bool cmMakefile::ReadDependentFile(const char* filename, bool noPolicyScope) IncludeScope incScope(this, filenametoread, noPolicyScope); cmListFile listFile; - if (!listFile.ParseFile(filenametoread.c_str(), this)) { + if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(), + this->Backtrace)) { return false; } @@ -506,7 +508,8 @@ bool cmMakefile::ReadListFile(const char* filename) ListFileScope scope(this, filenametoread); cmListFile listFile; - if (!listFile.ParseFile(filenametoread.c_str(), this)) { + if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(), + this->Backtrace)) { return false; } @@ -1452,7 +1455,8 @@ void cmMakefile::Configure() this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentStart.c_str()); cmListFile listFile; - if (!listFile.ParseFile(currentStart.c_str(), this)) { + if (!listFile.ParseFile(currentStart.c_str(), this->GetMessenger(), + this->Backtrace)) { return; } if (this->IsRootMakefile()) { @@ -3274,6 +3278,11 @@ cmake* cmMakefile::GetCMakeInstance() const return this->GlobalGenerator->GetCMakeInstance(); } +cmMessenger* cmMakefile::GetMessenger() const +{ + return this->GetCMakeInstance()->GetMessenger(); +} + cmGlobalGenerator* cmMakefile::GetGlobalGenerator() const { return this->GlobalGenerator; diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index d082964..b3587c5 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -607,6 +607,7 @@ public: * Get the instance */ cmake* GetCMakeInstance() const; + cmMessenger* GetMessenger() const; cmGlobalGenerator* GetGlobalGenerator() const; /** https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=421012a330989a64b24a3289379bb4938e6ed3ea commit 421012a330989a64b24a3289379bb4938e6ed3ea Author: Stephen Kelly AuthorDate: Thu Jan 28 22:10:27 2016 +0100 Commit: Brad King CommitDate: Thu Aug 25 09:47:27 2016 -0400 cmMessenger: Extract from cmake class This way messages can be issued independent of the cmake instance. It is now possible to make DisplayMessage a virtual interface and override it to handle messages in the cmake-gui or future IDE interaction interfaces. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index e63bf5a..3b94df7 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -319,6 +319,8 @@ set(SRCS cmMakefileExecutableTargetGenerator.cxx cmMakefileLibraryTargetGenerator.cxx cmMakefileUtilityTargetGenerator.cxx + cmMessenger.cxx + cmMessenger.h cmOSXBundleGenerator.cxx cmOSXBundleGenerator.h cmOutputConverter.cxx diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx index 080880b..c48910e 100644 --- a/Source/cmMessageCommand.cxx +++ b/Source/cmMessageCommand.cxx @@ -11,6 +11,8 @@ ============================================================================*/ #include "cmMessageCommand.h" +#include "cmMessenger.h" + // cmLibraryCommand bool cmMessageCommand::InitialPass(std::vector const& args, cmExecutionStatus&) @@ -65,8 +67,8 @@ bool cmMessageCommand::InitialPass(std::vector const& args, if (type != cmake::MESSAGE) { // we've overriden the message type, above, so display it directly - cmake* cm = this->Makefile->GetCMakeInstance(); - cm->DisplayMessage(type, message, this->Makefile->GetBacktrace()); + cmMessenger* m = this->Makefile->GetMessenger(); + m->DisplayMessage(type, message, this->Makefile->GetBacktrace()); } else { if (status) { this->Makefile->DisplayStatus(message.c_str(), -1); diff --git a/Source/cmMessenger.cxx b/Source/cmMessenger.cxx new file mode 100644 index 0000000..43fa150 --- /dev/null +++ b/Source/cmMessenger.cxx @@ -0,0 +1,209 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmMessenger.h" +#include "cmDocumentationFormatter.h" +#include "cmMessenger.h" +#include "cmOutputConverter.h" + +#if defined(CMAKE_BUILD_WITH_CMAKE) +#include +#endif + +cmake::MessageType cmMessenger::ConvertMessageType(cmake::MessageType t) const +{ + bool warningsAsErrors; + + if (t == cmake::AUTHOR_WARNING || t == cmake::AUTHOR_ERROR) { + warningsAsErrors = this->GetDevWarningsAsErrors(); + if (warningsAsErrors && t == cmake::AUTHOR_WARNING) { + t = cmake::AUTHOR_ERROR; + } else if (!warningsAsErrors && t == cmake::AUTHOR_ERROR) { + t = cmake::AUTHOR_WARNING; + } + } else if (t == cmake::DEPRECATION_WARNING || + t == cmake::DEPRECATION_ERROR) { + warningsAsErrors = this->GetDeprecatedWarningsAsErrors(); + if (warningsAsErrors && t == cmake::DEPRECATION_WARNING) { + t = cmake::DEPRECATION_ERROR; + } else if (!warningsAsErrors && t == cmake::DEPRECATION_ERROR) { + t = cmake::DEPRECATION_WARNING; + } + } + + return t; +} + +bool cmMessenger::IsMessageTypeVisible(cmake::MessageType t) const +{ + bool isVisible = true; + + if (t == cmake::DEPRECATION_ERROR) { + if (!this->GetDeprecatedWarningsAsErrors()) { + isVisible = false; + } + } else if (t == cmake::DEPRECATION_WARNING) { + if (this->GetSuppressDeprecatedWarnings()) { + isVisible = false; + } + } else if (t == cmake::AUTHOR_ERROR) { + if (!this->GetDevWarningsAsErrors()) { + isVisible = false; + } + } else if (t == cmake::AUTHOR_WARNING) { + if (this->GetSuppressDevWarnings()) { + isVisible = false; + } + } + + return isVisible; +} + +static bool printMessagePreamble(cmake::MessageType t, std::ostream& msg) +{ + // Construct the message header. + if (t == cmake::FATAL_ERROR) { + msg << "CMake Error"; + } else if (t == cmake::INTERNAL_ERROR) { + msg << "CMake Internal Error (please report a bug)"; + } else if (t == cmake::LOG) { + msg << "CMake Debug Log"; + } else if (t == cmake::DEPRECATION_ERROR) { + msg << "CMake Deprecation Error"; + } else if (t == cmake::DEPRECATION_WARNING) { + msg << "CMake Deprecation Warning"; + } else if (t == cmake::AUTHOR_WARNING) { + msg << "CMake Warning (dev)"; + } else if (t == cmake::AUTHOR_ERROR) { + msg << "CMake Error (dev)"; + } else { + msg << "CMake Warning"; + } + return true; +} + +void printMessageText(std::ostream& msg, std::string const& text) +{ + msg << ":\n"; + cmDocumentationFormatter formatter; + formatter.SetIndent(" "); + formatter.PrintFormatted(msg, text.c_str()); +} + +void displayMessage(cmake::MessageType t, std::ostringstream& msg) +{ + // Add a note about warning suppression. + if (t == cmake::AUTHOR_WARNING) { + msg << "This warning is for project developers. Use -Wno-dev to suppress " + "it."; + } else if (t == cmake::AUTHOR_ERROR) { + msg << "This error is for project developers. Use -Wno-error=dev to " + "suppress " + "it."; + } + + // Add a terminating blank line. + msg << "\n"; + +#if defined(CMAKE_BUILD_WITH_CMAKE) + // Add a C++ stack trace to internal errors. + if (t == cmake::INTERNAL_ERROR) { + std::string stack = cmsys::SystemInformation::GetProgramStack(0, 0); + if (!stack.empty()) { + if (cmHasLiteralPrefix(stack, "WARNING:")) { + stack = "Note:" + stack.substr(8); + } + msg << stack << "\n"; + } + } +#endif + + // Output the message. + if (t == cmake::FATAL_ERROR || t == cmake::INTERNAL_ERROR || + t == cmake::DEPRECATION_ERROR || t == cmake::AUTHOR_ERROR) { + cmSystemTools::SetErrorOccured(); + cmSystemTools::Message(msg.str().c_str(), "Error"); + } else { + cmSystemTools::Message(msg.str().c_str(), "Warning"); + } +} + +cmMessenger::cmMessenger(cmState* state) + : State(state) +{ +} + +void cmMessenger::IssueMessage(cmake::MessageType t, const std::string& text, + const cmListFileBacktrace& backtrace) const +{ + bool force = false; + if (!force) { + // override the message type, if needed, for warnings and errors + cmake::MessageType override = this->ConvertMessageType(t); + if (override != t) { + t = override; + force = true; + } + } + + if (!force && !this->IsMessageTypeVisible(t)) { + return; + } + this->DisplayMessage(t, text, backtrace); +} + +void cmMessenger::DisplayMessage(cmake::MessageType t, const std::string& text, + const cmListFileBacktrace& backtrace) const +{ + std::ostringstream msg; + if (!printMessagePreamble(t, msg)) { + return; + } + + // Add the immediate context. + backtrace.PrintTitle(msg); + + printMessageText(msg, text); + + // Add the rest of the context. + backtrace.PrintCallStack(msg); + + displayMessage(t, msg); +} + +bool cmMessenger::GetSuppressDevWarnings() const +{ + const char* cacheEntryValue = + this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_WARNINGS"); + return cmSystemTools::IsOn(cacheEntryValue); +} + +bool cmMessenger::GetSuppressDeprecatedWarnings() const +{ + const char* cacheEntryValue = + this->State->GetCacheEntryValue("CMAKE_WARN_DEPRECATED"); + return cacheEntryValue && cmSystemTools::IsOff(cacheEntryValue); +} + +bool cmMessenger::GetDevWarningsAsErrors() const +{ + const char* cacheEntryValue = + this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_ERRORS"); + return cacheEntryValue && cmSystemTools::IsOff(cacheEntryValue); +} + +bool cmMessenger::GetDeprecatedWarningsAsErrors() const +{ + const char* cacheEntryValue = + this->State->GetCacheEntryValue("CMAKE_ERROR_DEPRECATED"); + return cmSystemTools::IsOn(cacheEntryValue); +} diff --git a/Source/cmMessenger.h b/Source/cmMessenger.h new file mode 100644 index 0000000..f15bf13 --- /dev/null +++ b/Source/cmMessenger.h @@ -0,0 +1,44 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmMessenger_h +#define cmMessenger_h + +#include "cmListFileCache.h" +#include "cmState.h" +#include "cmake.h" + +class cmMessenger +{ +public: + cmMessenger(cmState* state); + + void IssueMessage( + cmake::MessageType t, std::string const& text, + cmListFileBacktrace const& backtrace = cmListFileBacktrace()) const; + + void DisplayMessage(cmake::MessageType t, std::string const& text, + cmListFileBacktrace const& backtrace) const; + + bool GetSuppressDevWarnings() const; + bool GetSuppressDeprecatedWarnings() const; + bool GetDevWarningsAsErrors() const; + bool GetDeprecatedWarningsAsErrors() const; + +private: + bool IsMessageTypeVisible(cmake::MessageType t) const; + cmake::MessageType ConvertMessageType(cmake::MessageType t) const; + + cmState* State; +}; + +#endif diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 74c3f71..701a5e5 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -19,6 +19,7 @@ #include "cmFileTimeComparison.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmMessenger.h" #include "cmSourceFile.h" #include "cmState.h" #include "cmTest.h" @@ -152,6 +153,7 @@ cmake::cmake() this->State = new cmState; this->CurrentSnapshot = this->State->CreateBaseSnapshot(); + this->Messenger = new cmMessenger(this->State); #ifdef __APPLE__ struct rlimit rlp; @@ -207,6 +209,7 @@ cmake::cmake() cmake::~cmake() { delete this->State; + delete this->Messenger; if (this->GlobalGenerator) { delete this->GlobalGenerator; this->GlobalGenerator = CM_NULLPTR; @@ -2281,160 +2284,10 @@ static bool cmakeCheckStampList(const char* stampList) return true; } -cmake::MessageType cmake::ConvertMessageType(cmake::MessageType t) const -{ - bool warningsAsErrors; - - if (t == cmake::AUTHOR_WARNING || t == cmake::AUTHOR_ERROR) { - warningsAsErrors = this->GetDevWarningsAsErrors(); - if (warningsAsErrors && t == cmake::AUTHOR_WARNING) { - t = cmake::AUTHOR_ERROR; - } else if (!warningsAsErrors && t == cmake::AUTHOR_ERROR) { - t = cmake::AUTHOR_WARNING; - } - } else if (t == cmake::DEPRECATION_WARNING || - t == cmake::DEPRECATION_ERROR) { - warningsAsErrors = this->GetDeprecatedWarningsAsErrors(); - if (warningsAsErrors && t == cmake::DEPRECATION_WARNING) { - t = cmake::DEPRECATION_ERROR; - } else if (!warningsAsErrors && t == cmake::DEPRECATION_ERROR) { - t = cmake::DEPRECATION_WARNING; - } - } - - return t; -} - -bool cmake::IsMessageTypeVisible(cmake::MessageType t) const -{ - bool isVisible = true; - - if (t == cmake::DEPRECATION_ERROR) { - if (!this->GetDeprecatedWarningsAsErrors()) { - isVisible = false; - } - } else if (t == cmake::DEPRECATION_WARNING) { - if (this->GetSuppressDeprecatedWarnings()) { - isVisible = false; - } - } else if (t == cmake::AUTHOR_ERROR) { - if (!this->GetDevWarningsAsErrors()) { - isVisible = false; - } - } else if (t == cmake::AUTHOR_WARNING) { - if (this->GetSuppressDevWarnings()) { - isVisible = false; - } - } - - return isVisible; -} - -static bool printMessagePreamble(cmake::MessageType t, std::ostream& msg) -{ - // Construct the message header. - if (t == cmake::FATAL_ERROR) { - msg << "CMake Error"; - } else if (t == cmake::INTERNAL_ERROR) { - msg << "CMake Internal Error (please report a bug)"; - } else if (t == cmake::LOG) { - msg << "CMake Debug Log"; - } else if (t == cmake::DEPRECATION_ERROR) { - msg << "CMake Deprecation Error"; - } else if (t == cmake::DEPRECATION_WARNING) { - msg << "CMake Deprecation Warning"; - } else if (t == cmake::AUTHOR_WARNING) { - msg << "CMake Warning (dev)"; - } else if (t == cmake::AUTHOR_ERROR) { - msg << "CMake Error (dev)"; - } else { - msg << "CMake Warning"; - } - return true; -} - -void printMessageText(std::ostream& msg, std::string const& text) -{ - msg << ":\n"; - cmDocumentationFormatter formatter; - formatter.SetIndent(" "); - formatter.PrintFormatted(msg, text.c_str()); -} - -void displayMessage(cmake::MessageType t, std::ostringstream& msg) -{ - - // Add a note about warning suppression. - if (t == cmake::AUTHOR_WARNING) { - msg << "This warning is for project developers. Use -Wno-dev to suppress " - "it."; - } else if (t == cmake::AUTHOR_ERROR) { - msg << "This error is for project developers. Use -Wno-error=dev to " - "suppress " - "it."; - } - - // Add a terminating blank line. - msg << "\n"; - -#if defined(CMAKE_BUILD_WITH_CMAKE) - // Add a C++ stack trace to internal errors. - if (t == cmake::INTERNAL_ERROR) { - std::string stack = cmsys::SystemInformation::GetProgramStack(0, 0); - if (!stack.empty()) { - if (cmHasLiteralPrefix(stack, "WARNING:")) { - stack = "Note:" + stack.substr(8); - } - msg << stack << "\n"; - } - } -#endif - - // Output the message. - if (t == cmake::FATAL_ERROR || t == cmake::INTERNAL_ERROR || - t == cmake::DEPRECATION_ERROR || t == cmake::AUTHOR_ERROR) { - cmSystemTools::SetErrorOccured(); - cmSystemTools::Message(msg.str().c_str(), "Error"); - } else { - cmSystemTools::Message(msg.str().c_str(), "Warning"); - } -} - void cmake::IssueMessage(cmake::MessageType t, std::string const& text, cmListFileBacktrace const& backtrace) const { - bool force = false; - // override the message type, if needed, for warnings and errors - cmake::MessageType override = this->ConvertMessageType(t); - if (override != t) { - t = override; - force = true; - } - - if (!force && !this->IsMessageTypeVisible(t)) { - return; - } - - this->DisplayMessage(t, text, backtrace); -} - -void cmake::DisplayMessage(cmake::MessageType t, std::string const& text, - cmListFileBacktrace const& backtrace) const -{ - std::ostringstream msg; - if (!printMessagePreamble(t, msg)) { - return; - } - - // Add the immediate context. - backtrace.PrintTitle(msg); - - printMessageText(msg, text); - - // Add the rest of the context. - backtrace.PrintCallStack(msg); - - displayMessage(t, msg); + this->Messenger->IssueMessage(t, text, backtrace); } std::vector cmake::GetDebugConfigs() @@ -2454,6 +2307,11 @@ std::vector cmake::GetDebugConfigs() return configs; } +cmMessenger* cmake::GetMessenger() const +{ + return this->Messenger; +} + int cmake::Build(const std::string& dir, const std::string& target, const std::string& config, const std::vector& nativeOptions, bool clean) @@ -2560,9 +2418,7 @@ void cmake::RunCheckForUnusedVariables() bool cmake::GetSuppressDevWarnings() const { - const char* cacheEntryValue = - this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_WARNINGS"); - return cmSystemTools::IsOn(cacheEntryValue); + return this->Messenger->GetSuppressDevWarnings(); } void cmake::SetSuppressDevWarnings(bool b) @@ -2586,9 +2442,7 @@ void cmake::SetSuppressDevWarnings(bool b) bool cmake::GetSuppressDeprecatedWarnings() const { - const char* cacheEntryValue = - this->State->GetCacheEntryValue("CMAKE_WARN_DEPRECATED"); - return cacheEntryValue && cmSystemTools::IsOff(cacheEntryValue); + return this->Messenger->GetSuppressDeprecatedWarnings(); } void cmake::SetSuppressDeprecatedWarnings(bool b) @@ -2612,9 +2466,7 @@ void cmake::SetSuppressDeprecatedWarnings(bool b) bool cmake::GetDevWarningsAsErrors() const { - const char* cacheEntryValue = - this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_ERRORS"); - return cacheEntryValue && cmSystemTools::IsOff(cacheEntryValue); + return this->Messenger->GetDevWarningsAsErrors(); } void cmake::SetDevWarningsAsErrors(bool b) @@ -2638,9 +2490,7 @@ void cmake::SetDevWarningsAsErrors(bool b) bool cmake::GetDeprecatedWarningsAsErrors() const { - const char* cacheEntryValue = - this->State->GetCacheEntryValue("CMAKE_ERROR_DEPRECATED"); - return cmSystemTools::IsOn(cacheEntryValue); + return this->Messenger->GetDeprecatedWarningsAsErrors(); } void cmake::SetDeprecatedWarningsAsErrors(bool b) diff --git a/Source/cmake.h b/Source/cmake.h index 343d371..dbe936b 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -25,6 +25,7 @@ class cmGlobalGeneratorFactory; class cmGlobalGenerator; class cmLocalGenerator; class cmMakefile; +class cmMessenger; class cmVariableWatch; class cmFileTimeComparison; class cmExternalMakefileProjectGeneratorFactory; @@ -346,6 +347,8 @@ public: return this->CMakeEditCommand; } + cmMessenger* GetMessenger() const; + /* * Get the state of the suppression of developer (author) warnings. * Returns false, by default, if developer warnings should be shown, true @@ -395,9 +398,6 @@ public: cmake::MessageType t, std::string const& text, cmListFileBacktrace const& backtrace = cmListFileBacktrace()) const; - void DisplayMessage(cmake::MessageType t, std::string const& text, - cmListFileBacktrace const& backtrace) const; - ///! run the --build option int Build(const std::string& dir, const std::string& target, const std::string& config, @@ -491,6 +491,7 @@ private: cmState* State; cmState::Snapshot CurrentSnapshot; + cmMessenger* Messenger; std::vector TraceOnlyThisSources; diff --git a/bootstrap b/bootstrap index 742fa2b..6c6713e 100755 --- a/bootstrap +++ b/bootstrap @@ -266,6 +266,7 @@ CMAKE_CXX_SOURCES="\ cmPropertyDefinition \ cmPropertyDefinitionMap \ cmMakefile \ + cmMessenger \ cmExportBuildFileGenerator \ cmExportFileGenerator \ cmExportInstallFileGenerator \ https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=14a8d61fd49a9b990cbef7e1495e4763f31c55f2 commit 14a8d61fd49a9b990cbef7e1495e4763f31c55f2 Author: Stephen Kelly AuthorDate: Thu Jan 28 22:10:29 2016 +0100 Commit: Brad King CommitDate: Thu Aug 25 09:47:26 2016 -0400 cmMakefile: Port nested error logic away from cmExecutionStatus It is no longer needed. diff --git a/Source/cmExecutionStatus.h b/Source/cmExecutionStatus.h index 508c6bd..8006514 100644 --- a/Source/cmExecutionStatus.h +++ b/Source/cmExecutionStatus.h @@ -38,16 +38,12 @@ public: this->ReturnInvoked = false; this->BreakInvoked = false; this->ContinueInvoked = false; - this->NestedError = false; } - void SetNestedError(bool val) { this->NestedError = val; } - bool GetNestedError() { return this->NestedError; } private: bool ReturnInvoked; bool BreakInvoked; bool ContinueInvoked; - bool NestedError; }; #endif diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index 40c54db..f0e4854 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -76,7 +76,7 @@ public: }; bool cmFunctionHelperCommand::InvokeInitialPass( - const std::vector& args, cmExecutionStatus& inStatus) + const std::vector& args, cmExecutionStatus&) { // Expand the argument list to the function. std::vector expandedArgs; @@ -129,11 +129,11 @@ bool cmFunctionHelperCommand::InvokeInitialPass( for (unsigned int c = 0; c < this->Functions.size(); ++c) { cmExecutionStatus status; if (!this->Makefile->ExecuteCommand(this->Functions[c], status) || - status.GetNestedError()) { + (cmSystemTools::GetErrorOccuredFlag() && + !cmSystemTools::GetFatalErrorOccured())) { // The error message should have already included the call stack // so we do not need to report an error here. functionScope.Quiet(); - inStatus.SetNestedError(true); return false; } if (status.GetReturnInvoked()) { diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index ee9dc8a..9d312ee 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -159,11 +159,11 @@ bool cmMacroHelperCommand::InvokeInitialPass( } cmExecutionStatus status; if (!this->Makefile->ExecuteCommand(newLFF, status) || - status.GetNestedError()) { + (cmSystemTools::GetErrorOccuredFlag() && + !cmSystemTools::GetFatalErrorOccured())) { // The error message should have already included the call stack // so we do not need to report an error here. macroScope.Quiet(); - inStatus.SetNestedError(true); return false; } if (status.GetReturnInvoked()) { diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index d299b8b..6c83b06 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -115,10 +115,6 @@ cmMakefile::~cmMakefile() void cmMakefile::IssueMessage(cmake::MessageType t, std::string const& text) const { - assert(!this->ExecutionStatusStack.empty()); - if ((t == cmake::FATAL_ERROR) || (t == cmake::INTERNAL_ERROR)) { - this->ExecutionStatusStack.back()->SetNestedError(true); - } this->GetCMakeInstance()->IssueMessage(t, text, this->GetBacktrace()); } @@ -279,11 +275,19 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, if (this->GetCMakeInstance()->GetTrace()) { this->PrintCommandTrace(lff); } - // Try invoking the command. + + bool hadPreviousNonFatalError = cmSystemTools::GetErrorOccuredFlag() && + !cmSystemTools::GetFatalErrorOccured(); + cmSystemTools::ResetErrorOccuredFlag(); + bool invokeSucceeded = pcmd->InvokeInitialPass(lff.Arguments, status); - bool hadNestedError = status.GetNestedError(); + bool hadNestedError = cmSystemTools::GetErrorOccuredFlag() && + !cmSystemTools::GetFatalErrorOccured(); + if (hadPreviousNonFatalError) { + cmSystemTools::SetErrorOccured(); + } if (!invokeSucceeded || hadNestedError) { - if (!hadNestedError) { + if (!hadNestedError && !cmSystemTools::GetFatalErrorOccured()) { // The command invocation requested that we report an error. this->IssueMessage(cmake::FATAL_ERROR, pcmd->GetError()); } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2af853deb5225a9c8cb3d1e6311680c3fb7d86aa commit 2af853deb5225a9c8cb3d1e6311680c3fb7d86aa Author: Stephen Kelly AuthorDate: Thu Jan 28 22:10:28 2016 +0100 Commit: Brad King CommitDate: Thu Aug 25 09:47:26 2016 -0400 cmMakefile: Simplify IssueMessage implementation It is only called during configure time when the execution stack is non-empty. diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index b9d71ec..d299b8b 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -115,11 +115,9 @@ cmMakefile::~cmMakefile() void cmMakefile::IssueMessage(cmake::MessageType t, std::string const& text) const { - // Collect context information. - if (!this->ExecutionStatusStack.empty()) { - if ((t == cmake::FATAL_ERROR) || (t == cmake::INTERNAL_ERROR)) { - this->ExecutionStatusStack.back()->SetNestedError(true); - } + assert(!this->ExecutionStatusStack.empty()); + if ((t == cmake::FATAL_ERROR) || (t == cmake::INTERNAL_ERROR)) { + this->ExecutionStatusStack.back()->SetNestedError(true); } this->GetCMakeInstance()->IssueMessage(t, text, this->GetBacktrace()); } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=33bb9cfa365f494bb76ff9c2c78ad625e77152ec commit 33bb9cfa365f494bb76ff9c2c78ad625e77152ec Author: Stephen Kelly AuthorDate: Thu Jan 28 22:10:23 2016 +0100 Commit: Brad King CommitDate: Thu Aug 25 09:47:26 2016 -0400 Parser: Issue messages through cmake, not cmSystemTools Make these messages uniform with regard to other messages issued by cmake. diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 1a2ddaf..9204d14 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -24,6 +24,7 @@ struct cmListFileParser cmListFileParser(cmListFile* lf, cmMakefile* mf, const char* filename); ~cmListFileParser(); void IssueFileOpenError(std::string const& text) const; + void IssueError(std::string const& text) const; bool ParseFile(); bool ParseFunction(const char* name, long line); bool AddArgument(cmListFileLexer_Token* token, @@ -62,6 +63,18 @@ void cmListFileParser::IssueFileOpenError(const std::string& text) const this->Makefile->IssueMessage(cmake::FATAL_ERROR, text); } +void cmListFileParser::IssueError(const std::string& text) const +{ + cmListFileContext lfc; + lfc.FilePath = this->FileName; + lfc.Line = cmListFileLexer_GetCurrentLine(this->Lexer); + cmListFileBacktrace lfbt = this->Backtrace; + lfbt = lfbt.Push(lfc); + this->Makefile->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, text, + lfbt); + cmSystemTools::SetFatalErrorOccured(); +} + bool cmListFileParser::ParseFile() { // Open the file. @@ -98,22 +111,18 @@ bool cmListFileParser::ParseFile() } } else { std::ostringstream error; - error << "Error in cmake code at\n" - << this->FileName << ":" << token->line << ":\n" - << "Parse error. Expected a newline, got " + error << "Parse error. Expected a newline, got " << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) << " with text \"" << token->text << "\"."; - cmSystemTools::Error(error.str().c_str()); + this->IssueError(error.str()); return false; } } else { std::ostringstream error; - error << "Error in cmake code at\n" - << this->FileName << ":" << token->line << ":\n" - << "Parse error. Expected a command name, got " + error << "Parse error. Expected a command name, got " << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) << " with text \"" << token->text << "\"."; - cmSystemTools::Error(error.str().c_str()); + this->IssueError(error.str()); return false; } } @@ -156,18 +165,15 @@ bool cmListFileParser::ParseFunction(const char* name, long line) << cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n" << "Parse error. Function missing opening \"(\"."; /* clang-format on */ - cmSystemTools::Error(error.str().c_str()); + this->IssueError(error.str()); return false; } if (token->type != cmListFileLexer_Token_ParenLeft) { std::ostringstream error; - error << "Error in cmake code at\n" - << this->FileName << ":" - << cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n" - << "Parse error. Expected \"(\", got " + error << "Parse error. Expected \"(\", got " << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) << " with text \"" << token->text << "\"."; - cmSystemTools::Error(error.str().c_str()); + this->IssueError(error.str()); return false; } @@ -219,25 +225,25 @@ bool cmListFileParser::ParseFunction(const char* name, long line) } else { // Error. std::ostringstream error; - error << "Error in cmake code at\n" - << this->FileName << ":" - << cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n" - << "Parse error. Function missing ending \")\". " + error << "Parse error. Function missing ending \")\". " << "Instead found " << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) << " with text \"" << token->text << "\"."; - cmSystemTools::Error(error.str().c_str()); + this->IssueError(error.str()); return false; } } std::ostringstream error; - error << "Error in cmake code at\n" - << this->FileName << ":" << lastLine << ":\n" - << "Parse error. Function missing ending \")\". " + cmListFileContext lfc; + lfc.FilePath = this->FileName; + lfc.Line = lastLine; + cmListFileBacktrace lfbt = this->Backtrace; + lfbt = lfbt.Push(lfc); + error << "Parse error. Function missing ending \")\". " << "End of file reached."; - cmSystemTools::Error(error.str().c_str()); - + this->Makefile->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, + error.str(), lfbt); return false; } @@ -252,17 +258,21 @@ bool cmListFileParser::AddArgument(cmListFileLexer_Token* token, bool isError = (this->Separation == SeparationError || delim == cmListFileArgument::Bracket); std::ostringstream m; - /* clang-format off */ - m << "Syntax " << (isError? "Error":"Warning") << " in cmake code at\n" - << " " << this->FileName << ":" << token->line << ":" - << token->column << "\n" + cmListFileContext lfc; + lfc.FilePath = this->FileName; + lfc.Line = token->line; + cmListFileBacktrace lfbt = this->Backtrace; + lfbt = lfbt.Push(lfc); + + m << "Syntax " << (isError ? "Error" : "Warning") << " in cmake code at " + << "column " << token->column << "\n" << "Argument not separated from preceding token by whitespace."; /* clang-format on */ if (isError) { - this->Makefile->IssueMessage(cmake::FATAL_ERROR, m.str()); + this->Makefile->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, m.str(), lfbt); return false; } - this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, m.str()); + this->Makefile->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING, m.str(), lfbt); return true; } diff --git a/Tests/RunCMake/Syntax/BracketComment4-stderr.txt b/Tests/RunCMake/Syntax/BracketComment4-stderr.txt index 8ba32c2..6bbb980 100644 --- a/Tests/RunCMake/Syntax/BracketComment4-stderr.txt +++ b/Tests/RunCMake/Syntax/BracketComment4-stderr.txt @@ -1,7 +1,4 @@ -CMake Error: Error in cmake code at -.*/Tests/RunCMake/Syntax/BracketComment4.cmake:3: -Parse error. Expected a newline, got identifier with text "message". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: - - BracketComment4.cmake +CMake Error at BracketComment4.cmake:3: + Parse error. Expected a newline, got identifier with text "message". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/BracketNoSpace0-stderr.txt b/Tests/RunCMake/Syntax/BracketNoSpace0-stderr.txt index a288280..0a52022 100644 --- a/Tests/RunCMake/Syntax/BracketNoSpace0-stderr.txt +++ b/Tests/RunCMake/Syntax/BracketNoSpace0-stderr.txt @@ -1,7 +1,5 @@ -CMake Error in BracketNoSpace0.cmake: - Syntax Error in cmake code at - - .*/Tests/RunCMake/Syntax/BracketNoSpace0.cmake:1:27 +CMake Error at BracketNoSpace0.cmake:1: + Syntax Error in cmake code at column 27 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/BracketNoSpace1-stderr.txt b/Tests/RunCMake/Syntax/BracketNoSpace1-stderr.txt index 391e11b..43bf995 100644 --- a/Tests/RunCMake/Syntax/BracketNoSpace1-stderr.txt +++ b/Tests/RunCMake/Syntax/BracketNoSpace1-stderr.txt @@ -1,7 +1,5 @@ -CMake Error in BracketNoSpace1.cmake: - Syntax Error in cmake code at - - .*/Tests/RunCMake/Syntax/BracketNoSpace1.cmake:1:24 +CMake Error at BracketNoSpace1.cmake:1: + Syntax Error in cmake code at column 24 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/BracketNoSpace2-stderr.txt b/Tests/RunCMake/Syntax/BracketNoSpace2-stderr.txt index acaf7fe..f78b4bd 100644 --- a/Tests/RunCMake/Syntax/BracketNoSpace2-stderr.txt +++ b/Tests/RunCMake/Syntax/BracketNoSpace2-stderr.txt @@ -1,7 +1,5 @@ -CMake Error in BracketNoSpace2.cmake: - Syntax Error in cmake code at - - .*/Tests/RunCMake/Syntax/BracketNoSpace2.cmake:1:44 +CMake Error at BracketNoSpace2.cmake:1: + Syntax Error in cmake code at column 44 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/BracketNoSpace3-stderr.txt b/Tests/RunCMake/Syntax/BracketNoSpace3-stderr.txt index f12b2e5..63ca600 100644 --- a/Tests/RunCMake/Syntax/BracketNoSpace3-stderr.txt +++ b/Tests/RunCMake/Syntax/BracketNoSpace3-stderr.txt @@ -1,7 +1,5 @@ -CMake Error in BracketNoSpace3.cmake: - Syntax Error in cmake code at - - .*/Tests/RunCMake/Syntax/BracketNoSpace3.cmake:1:45 +CMake Error at BracketNoSpace3.cmake:1: + Syntax Error in cmake code at column 45 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/BracketNoSpace4-stderr.txt b/Tests/RunCMake/Syntax/BracketNoSpace4-stderr.txt index 7157763..318b0e3 100644 --- a/Tests/RunCMake/Syntax/BracketNoSpace4-stderr.txt +++ b/Tests/RunCMake/Syntax/BracketNoSpace4-stderr.txt @@ -1,7 +1,5 @@ -CMake Error in BracketNoSpace4.cmake: - Syntax Error in cmake code at - - .*/Tests/RunCMake/Syntax/BracketNoSpace4.cmake:1:44 +CMake Error at BracketNoSpace4.cmake:1: + Syntax Error in cmake code at column 44 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/BracketNoSpace5-stderr.txt b/Tests/RunCMake/Syntax/BracketNoSpace5-stderr.txt index c13969d..a68478a 100644 --- a/Tests/RunCMake/Syntax/BracketNoSpace5-stderr.txt +++ b/Tests/RunCMake/Syntax/BracketNoSpace5-stderr.txt @@ -1,7 +1,5 @@ -CMake Error in BracketNoSpace5.cmake: - Syntax Error in cmake code at - - .*/Tests/RunCMake/Syntax/BracketNoSpace5.cmake:1:45 +CMake Error at BracketNoSpace5.cmake:1: + Syntax Error in cmake code at column 45 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/CommandError0-stderr.txt b/Tests/RunCMake/Syntax/CommandError0-stderr.txt index 24d7997..e584fb0 100644 --- a/Tests/RunCMake/Syntax/CommandError0-stderr.txt +++ b/Tests/RunCMake/Syntax/CommandError0-stderr.txt @@ -1,8 +1,6 @@ -CMake Error: Error in cmake code at -.*/Tests/RunCMake/Syntax/CommandError0.cmake:2: -Parse error. Expected "\(", got newline with text " -". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: +CMake Error at CommandError0.cmake:2: + Parse error. Expected "\(", got newline with text " - CommandError0.cmake + ". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/CommandError1-stderr.txt b/Tests/RunCMake/Syntax/CommandError1-stderr.txt index 599f600..c3bf93c 100644 --- a/Tests/RunCMake/Syntax/CommandError1-stderr.txt +++ b/Tests/RunCMake/Syntax/CommandError1-stderr.txt @@ -1,7 +1,4 @@ -CMake Error: Error in cmake code at -.*/Tests/RunCMake/Syntax/CommandError1.cmake:1: -Parse error. Expected a newline, got identifier with text "message". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: - - CommandError1.cmake +CMake Error at CommandError1.cmake:1: + Parse error. Expected a newline, got identifier with text "message". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/CommandError2-stderr.txt b/Tests/RunCMake/Syntax/CommandError2-stderr.txt index f4dfc77..4fe28a9 100644 --- a/Tests/RunCMake/Syntax/CommandError2-stderr.txt +++ b/Tests/RunCMake/Syntax/CommandError2-stderr.txt @@ -1,7 +1,5 @@ -CMake Error: Error in cmake code at -.*/Tests/RunCMake/Syntax/CommandError2.cmake:1: -Parse error. Expected a command name, got bracket argument with text "oops-not-a-comment". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: - - CommandError2.cmake +CMake Error at CommandError2.cmake:1: + Parse error. Expected a command name, got bracket argument with text + "oops-not-a-comment". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/ParenInENV-stderr.txt b/Tests/RunCMake/Syntax/ParenInENV-stderr.txt index 37c5d6e..d7861e2 100644 --- a/Tests/RunCMake/Syntax/ParenInENV-stderr.txt +++ b/Tests/RunCMake/Syntax/ParenInENV-stderr.txt @@ -1,7 +1,5 @@ -CMake Warning \(dev\) in ParenInENV.cmake: - Syntax Warning in cmake code at - - .*/Tests/RunCMake/Syntax/ParenInENV.cmake:2:21 +CMake Warning \(dev\) at ParenInENV.cmake:2: + Syntax Warning in cmake code at column 21 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): @@ -11,7 +9,7 @@ This warning is for project developers. Use -Wno-dev to suppress it. CMake Error at ParenInENV.cmake:2 \(message\): Syntax error in cmake code at - .*/Tests/RunCMake/Syntax/ParenInENV.cmake:2 + .*Tests/RunCMake/Syntax/ParenInENV.cmake:2 when parsing string diff --git a/Tests/RunCMake/Syntax/ParenNoSpace1-stderr.txt b/Tests/RunCMake/Syntax/ParenNoSpace1-stderr.txt index 45b2e6a..7958249 100644 --- a/Tests/RunCMake/Syntax/ParenNoSpace1-stderr.txt +++ b/Tests/RunCMake/Syntax/ParenNoSpace1-stderr.txt @@ -1,27 +1,21 @@ -CMake Warning \(dev\) in ParenNoSpace1.cmake: - Syntax Warning in cmake code at - - .*/Tests/RunCMake/Syntax/ParenNoSpace1.cmake:1:26 +CMake Warning \(dev\) at ParenNoSpace1.cmake:1: + Syntax Warning in cmake code at column 26 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) This warning is for project developers. Use -Wno-dev to suppress it. -CMake Warning \(dev\) in ParenNoSpace1.cmake: - Syntax Warning in cmake code at - - .*/Tests/RunCMake/Syntax/ParenNoSpace1.cmake:2:26 +CMake Warning \(dev\) at ParenNoSpace1.cmake:2: + Syntax Warning in cmake code at column 26 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) This warning is for project developers. Use -Wno-dev to suppress it. -CMake Error in ParenNoSpace1.cmake: - Syntax Error in cmake code at - - .*/Tests/RunCMake/Syntax/ParenNoSpace1.cmake:3:29 +CMake Error at ParenNoSpace1.cmake:3: + Syntax Error in cmake code at column 29 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/StringNoSpace-stderr.txt b/Tests/RunCMake/Syntax/StringNoSpace-stderr.txt index a4ec6e7..817fcfa 100644 --- a/Tests/RunCMake/Syntax/StringNoSpace-stderr.txt +++ b/Tests/RunCMake/Syntax/StringNoSpace-stderr.txt @@ -1,17 +1,13 @@ -CMake Warning \(dev\) in StringNoSpace.cmake: - Syntax Warning in cmake code at - - .*/Tests/RunCMake/Syntax/StringNoSpace.cmake:2:28 +CMake Warning \(dev\) at StringNoSpace.cmake:2: + Syntax Warning in cmake code at column 28 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) This warning is for project developers. Use -Wno-dev to suppress it. -CMake Warning \(dev\) in StringNoSpace.cmake: - Syntax Warning in cmake code at - - .*/Tests/RunCMake/Syntax/StringNoSpace.cmake:2:31 +CMake Warning \(dev\) at StringNoSpace.cmake:2: + Syntax Warning in cmake code at column 31 Argument not separated from preceding token by whitespace. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/Syntax/UnterminatedBracket0-stderr.txt b/Tests/RunCMake/Syntax/UnterminatedBracket0-stderr.txt index 3559c18..de33f7d 100644 --- a/Tests/RunCMake/Syntax/UnterminatedBracket0-stderr.txt +++ b/Tests/RunCMake/Syntax/UnterminatedBracket0-stderr.txt @@ -1,8 +1,7 @@ -CMake Error: Error in cmake code at -.*/Syntax/UnterminatedBracket0.cmake:2: -Parse error. Function missing ending "\)". Instead found unterminated bracket with text "\) -". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: +CMake Error at UnterminatedBracket0.cmake:2: + Parse error. Function missing ending "\)". Instead found unterminated + bracket with text "\) - UnterminatedBracket0.cmake$ + ". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/UnterminatedBracket1-stderr.txt b/Tests/RunCMake/Syntax/UnterminatedBracket1-stderr.txt index 55d458b..86bfa2a 100644 --- a/Tests/RunCMake/Syntax/UnterminatedBracket1-stderr.txt +++ b/Tests/RunCMake/Syntax/UnterminatedBracket1-stderr.txt @@ -1,8 +1,7 @@ -CMake Error: Error in cmake code at -.*/Syntax/UnterminatedBracket1.cmake:2: -Parse error. Function missing ending "\)". Instead found unterminated bracket with text "\]\]\) -". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: +CMake Error at UnterminatedBracket1.cmake:2: + Parse error. Function missing ending "\)". Instead found unterminated + bracket with text "]]\) - UnterminatedBracket1.cmake$ + ". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/UnterminatedBracketComment-stderr.txt b/Tests/RunCMake/Syntax/UnterminatedBracketComment-stderr.txt index 0a799eb..4ec78a1 100644 --- a/Tests/RunCMake/Syntax/UnterminatedBracketComment-stderr.txt +++ b/Tests/RunCMake/Syntax/UnterminatedBracketComment-stderr.txt @@ -1,8 +1,7 @@ -CMake Error: Error in cmake code at -.*/Syntax/UnterminatedBracketComment.cmake:1: -Parse error. Expected a command name, got unterminated bracket with text "#\]\] -". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: +CMake Error at UnterminatedBracketComment.cmake:3: + Parse error. Expected a command name, got unterminated bracket with text + "#]] - UnterminatedBracketComment.cmake + ". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt b/Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt index 281ce0d..3f52244 100644 --- a/Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt +++ b/Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt @@ -1,7 +1,4 @@ -CMake Error: Error in cmake code at -.*/Syntax/UnterminatedCall1.cmake:2: -Parse error. Function missing ending "\)". End of file reached. -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: - - UnterminatedCall1.cmake +CMake Error at UnterminatedCall1.cmake:2: + Parse error. Function missing ending "\)". End of file reached. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt b/Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt index 065de30..18656f7 100644 --- a/Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt +++ b/Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt @@ -1,7 +1,4 @@ -CMake Error: Error in cmake code at -.*/Syntax/UnterminatedCall2.cmake:4: -Parse error. Function missing ending "\)". End of file reached. -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: - - UnterminatedCall2.cmake +CMake Error at UnterminatedCall2.cmake:4: + Parse error. Function missing ending "\)". End of file reached. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/UnterminatedString-stderr.txt b/Tests/RunCMake/Syntax/UnterminatedString-stderr.txt index d925032..79c3fd2 100644 --- a/Tests/RunCMake/Syntax/UnterminatedString-stderr.txt +++ b/Tests/RunCMake/Syntax/UnterminatedString-stderr.txt @@ -1,8 +1,7 @@ -CMake Error: Error in cmake code at -.*/Syntax/UnterminatedString.cmake:2: -Parse error. Function missing ending "\)". Instead found unterminated string with text "\) -". -CMake Error at CMakeLists.txt:3 \(include\): - include could not find load file: +CMake Error at UnterminatedString.cmake:2: + Parse error. Function missing ending "\)". Instead found unterminated + string with text "\) - UnterminatedString.cmake$ + ". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 09:50:22 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 09:50:22 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-720-gd8b70f6 Message-ID: <20160825135022.CB195F49F7@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via d8b70f62cb1a5ea7231c4236bed57206068a946c (commit) via 7bc6dccc0a993ddb3681100e28405189be09ff72 (commit) via fcc532470aa56e7a2e345f7f2396774787feb2ce (commit) from d6734eeb875ceca5d810e829ca90541918dca2b4 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d8b70f62cb1a5ea7231c4236bed57206068a946c commit d8b70f62cb1a5ea7231c4236bed57206068a946c Merge: d6734ee 7bc6dcc Author: Brad King AuthorDate: Thu Aug 25 09:50:19 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 09:50:19 2016 -0400 Merge topic 'update-kwsys' 7bc6dccc Merge branch 'upstream-KWSys' into update-kwsys fcc53247 KWSys 2016-08-24 (8e643b9b) ----------------------------------------------------------------------- Summary of changes: Source/kwsys/SystemTools.cxx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 09:50:25 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 09:50:25 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-722-gd1ee1cb Message-ID: <20160825135026.0DC40F4AA8@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via d1ee1cb81351cc9bd84cd7c3b755d0c4a5e45f6f (commit) via 828e763260c257920d91037395c7f88e59243367 (commit) from d8b70f62cb1a5ea7231c4236bed57206068a946c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d1ee1cb81351cc9bd84cd7c3b755d0c4a5e45f6f commit d1ee1cb81351cc9bd84cd7c3b755d0c4a5e45f6f Merge: d8b70f6 828e763 Author: Brad King AuthorDate: Thu Aug 25 09:50:23 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 09:50:23 2016 -0400 Merge topic 'test-RunCMake.CMP0040-fix' 828e7632 Tests: Fix RunCMake.CMP0040 custom command syntax ----------------------------------------------------------------------- Summary of changes: Tests/RunCMake/CMP0040/CMP0040-NEW-existing-target.cmake | 2 +- Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target.cmake | 2 +- Tests/RunCMake/CMP0040/CMP0040-OLD-existing-target.cmake | 2 +- Tests/RunCMake/CMP0040/CMP0040-OLD-missing-target.cmake | 2 +- Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target.cmake | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 09:50:37 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 09:50:37 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-724-gce8fadc Message-ID: <20160825135037.F0388F4AD6@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via ce8fadc717b001b39b3208f8069cb0048073f975 (commit) via f699323ade84bb672ed0998de73c6f0333981bc1 (commit) from d1ee1cb81351cc9bd84cd7c3b755d0c4a5e45f6f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ce8fadc717b001b39b3208f8069cb0048073f975 commit ce8fadc717b001b39b3208f8069cb0048073f975 Merge: d1ee1cb f699323 Author: Brad King AuthorDate: Thu Aug 25 09:50:35 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 09:50:35 2016 -0400 Merge topic 'intel-fortran-mod-diff' f699323a Fortran: Fix .mod file comparison for Intel 16 format ----------------------------------------------------------------------- Summary of changes: Source/cmDependsFortran.cxx | 6 ++++++ 1 file changed, 6 insertions(+) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 09:50:45 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 09:50:45 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-731-ga79abb8 Message-ID: <20160825135045.185B9F4AA8@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via a79abb82fe1c90b65f124a8dd31e4a0227583ce4 (commit) via 1462576bcba68310395a7185e4b77da38e1e6b33 (commit) via 421012a330989a64b24a3289379bb4938e6ed3ea (commit) via 14a8d61fd49a9b990cbef7e1495e4763f31c55f2 (commit) via 2af853deb5225a9c8cb3d1e6311680c3fb7d86aa (commit) via 33bb9cfa365f494bb76ff9c2c78ad625e77152ec (commit) via db7de303c2a1e35b672016833db4bf85148c98c2 (commit) from ce8fadc717b001b39b3208f8069cb0048073f975 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a79abb82fe1c90b65f124a8dd31e4a0227583ce4 commit a79abb82fe1c90b65f124a8dd31e4a0227583ce4 Merge: ce8fadc 1462576 Author: Brad King AuthorDate: Thu Aug 25 09:50:39 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 09:50:39 2016 -0400 Merge topic 'extract-cmMessenger' 1462576b Parser: Port away from cmMakefile 421012a3 cmMessenger: Extract from cmake class 14a8d61f cmMakefile: Port nested error logic away from cmExecutionStatus 2af853de cmMakefile: Simplify IssueMessage implementation 33bb9cfa Parser: Issue messages through cmake, not cmSystemTools db7de303 Parser: Store the Backtrace for use in issuing messages ----------------------------------------------------------------------- Summary of changes: Source/CMakeLists.txt | 2 + Source/cmExecutionStatus.h | 4 - Source/cmFunctionCommand.cxx | 6 +- Source/cmListFileCache.cxx | 89 +++++---- Source/cmListFileCache.h | 5 +- Source/cmMacroCommand.cxx | 4 +- Source/cmMakefile.cxx | 35 ++-- Source/cmMakefile.h | 1 + Source/cmMessageCommand.cxx | 6 +- Source/cmMessenger.cxx | 209 ++++++++++++++++++++ Source/cmMessenger.h | 44 +++++ Source/cmake.cxx | 176 ++--------------- Source/cmake.h | 7 +- Tests/RunCMake/Syntax/BracketComment4-stderr.txt | 11 +- Tests/RunCMake/Syntax/BracketNoSpace0-stderr.txt | 6 +- Tests/RunCMake/Syntax/BracketNoSpace1-stderr.txt | 6 +- Tests/RunCMake/Syntax/BracketNoSpace2-stderr.txt | 6 +- Tests/RunCMake/Syntax/BracketNoSpace3-stderr.txt | 6 +- Tests/RunCMake/Syntax/BracketNoSpace4-stderr.txt | 6 +- Tests/RunCMake/Syntax/BracketNoSpace5-stderr.txt | 6 +- Tests/RunCMake/Syntax/CommandError0-stderr.txt | 12 +- Tests/RunCMake/Syntax/CommandError1-stderr.txt | 11 +- Tests/RunCMake/Syntax/CommandError2-stderr.txt | 12 +- Tests/RunCMake/Syntax/ParenInENV-stderr.txt | 8 +- Tests/RunCMake/Syntax/ParenNoSpace1-stderr.txt | 18 +- Tests/RunCMake/Syntax/StringNoSpace-stderr.txt | 12 +- .../Syntax/UnterminatedBracket0-stderr.txt | 13 +- .../Syntax/UnterminatedBracket1-stderr.txt | 13 +- .../Syntax/UnterminatedBracketComment-stderr.txt | 13 +- Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt | 11 +- Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt | 11 +- .../RunCMake/Syntax/UnterminatedString-stderr.txt | 13 +- bootstrap | 1 + 33 files changed, 435 insertions(+), 348 deletions(-) create mode 100644 Source/cmMessenger.cxx create mode 100644 Source/cmMessenger.h hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 09:50:47 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 09:50:47 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-733-g98caa14 Message-ID: <20160825135047.F091EF4AD4@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 98caa14cc84cc659c2c5b51f84c6547b57c89c30 (commit) via 38491644540a203ee6465dd0bf179afb426aa835 (commit) from a79abb82fe1c90b65f124a8dd31e4a0227583ce4 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=98caa14cc84cc659c2c5b51f84c6547b57c89c30 commit 98caa14cc84cc659c2c5b51f84c6547b57c89c30 Merge: a79abb8 3849164 Author: Brad King AuthorDate: Thu Aug 25 09:50:45 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 09:50:45 2016 -0400 Merge topic 'include-what-you-use' 38491644 CTest: fix include-what-you-use violations ----------------------------------------------------------------------- Summary of changes: Source/CTest/cmCTestBZR.cxx | 10 +++- Source/CTest/cmCTestBZR.h | 14 ++++-- Source/CTest/cmCTestBatchTestHandler.cxx | 8 ++- Source/CTest/cmCTestBatchTestHandler.h | 5 +- Source/CTest/cmCTestBuildAndTestHandler.cxx | 2 + Source/CTest/cmCTestBuildAndTestHandler.h | 9 +++- Source/CTest/cmCTestBuildCommand.cxx | 7 +++ Source/CTest/cmCTestBuildCommand.h | 11 ++++- Source/CTest/cmCTestBuildHandler.cxx | 15 ++---- Source/CTest/cmCTestBuildHandler.h | 11 +++-- Source/CTest/cmCTestCVS.cxx | 2 + Source/CTest/cmCTestCVS.h | 12 ++++- Source/CTest/cmCTestConfigureCommand.cxx | 7 +++ Source/CTest/cmCTestConfigureCommand.h | 8 +++ Source/CTest/cmCTestConfigureHandler.cxx | 6 ++- Source/CTest/cmCTestConfigureHandler.h | 5 +- Source/CTest/cmCTestCoverageCommand.cxx | 2 + Source/CTest/cmCTestCoverageCommand.h | 9 ++++ Source/CTest/cmCTestCoverageHandler.cxx | 12 +++-- Source/CTest/cmCTestCoverageHandler.h | 12 ++++- Source/CTest/cmCTestCurl.cxx | 4 ++ Source/CTest/cmCTestCurl.h | 6 ++- .../CTest/cmCTestEmptyBinaryDirectoryCommand.cxx | 4 ++ Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h | 9 ++++ Source/CTest/cmCTestGIT.cxx | 8 +-- Source/CTest/cmCTestGIT.h | 16 ++++-- Source/CTest/cmCTestGenericHandler.cxx | 4 +- Source/CTest/cmCTestGenericHandler.h | 12 +++-- Source/CTest/cmCTestGlobalVC.cxx | 3 +- Source/CTest/cmCTestGlobalVC.h | 7 +++ Source/CTest/cmCTestHG.cxx | 4 ++ Source/CTest/cmCTestHG.h | 12 ++++- Source/CTest/cmCTestHandlerCommand.cxx | 8 +++ Source/CTest/cmCTestHandlerCommand.h | 8 +++ Source/CTest/cmCTestLaunch.cxx | 13 +++-- Source/CTest/cmCTestLaunch.h | 5 +- Source/CTest/cmCTestMemCheckCommand.h | 6 +++ Source/CTest/cmCTestMemCheckHandler.cxx | 14 ++---- Source/CTest/cmCTestMemCheckHandler.h | 4 +- Source/CTest/cmCTestMultiProcessHandler.cxx | 11 +++-- Source/CTest/cmCTestMultiProcessHandler.h | 12 ++++- Source/CTest/cmCTestP4.cxx | 9 ++-- Source/CTest/cmCTestP4.h | 13 +++-- Source/CTest/cmCTestReadCustomFilesCommand.cxx | 2 + Source/CTest/cmCTestReadCustomFilesCommand.h | 9 ++++ Source/CTest/cmCTestRunScriptCommand.cxx | 5 ++ Source/CTest/cmCTestRunScriptCommand.h | 9 ++++ Source/CTest/cmCTestRunTest.cxx | 12 ++++- Source/CTest/cmCTestRunTest.h | 8 ++- Source/CTest/cmCTestSVN.cxx | 6 +++ Source/CTest/cmCTestSVN.h | 12 ++++- Source/CTest/cmCTestScriptHandler.cxx | 51 ++++++++++---------- Source/CTest/cmCTestScriptHandler.h | 11 +++-- Source/CTest/cmCTestSleepCommand.cxx | 5 +- Source/CTest/cmCTestSleepCommand.h | 9 ++++ Source/CTest/cmCTestStartCommand.cxx | 8 ++- Source/CTest/cmCTestStartCommand.h | 10 ++++ Source/CTest/cmCTestSubmitCommand.cxx | 7 +++ Source/CTest/cmCTestSubmitCommand.h | 12 ++++- Source/CTest/cmCTestSubmitHandler.cxx | 22 +++++---- Source/CTest/cmCTestSubmitHandler.h | 10 ++++ Source/CTest/cmCTestTestCommand.cxx | 6 +++ Source/CTest/cmCTestTestCommand.h | 8 +++ Source/CTest/cmCTestTestHandler.cxx | 18 ++++--- Source/CTest/cmCTestTestHandler.h | 13 ++++- Source/CTest/cmCTestUpdateCommand.cxx | 4 ++ Source/CTest/cmCTestUpdateCommand.h | 8 +++ Source/CTest/cmCTestUpdateHandler.cxx | 25 ++-------- Source/CTest/cmCTestUpdateHandler.h | 7 ++- Source/CTest/cmCTestUploadCommand.cxx | 5 ++ Source/CTest/cmCTestUploadCommand.h | 9 +++- Source/CTest/cmCTestUploadHandler.cxx | 4 ++ Source/CTest/cmCTestUploadHandler.h | 4 ++ Source/CTest/cmCTestVC.cxx | 4 ++ Source/CTest/cmCTestVC.h | 6 ++- Source/CTest/cmParseBlanketJSCoverage.cxx | 5 +- Source/CTest/cmParseBlanketJSCoverage.h | 9 +++- Source/CTest/cmParseCacheCoverage.cxx | 6 ++- Source/CTest/cmParseCacheCoverage.h | 8 +++ Source/CTest/cmParseCoberturaCoverage.cxx | 7 ++- Source/CTest/cmParseCoberturaCoverage.h | 9 +++- Source/CTest/cmParseDelphiCoverage.cxx | 5 +- Source/CTest/cmParseDelphiCoverage.h | 9 +++- Source/CTest/cmParseGTMCoverage.cxx | 6 ++- Source/CTest/cmParseGTMCoverage.h | 7 +++ Source/CTest/cmParseJacocoCoverage.cxx | 7 ++- Source/CTest/cmParseJacocoCoverage.h | 10 +++- Source/CTest/cmParseMumpsCoverage.cxx | 13 +++-- Source/CTest/cmParseMumpsCoverage.h | 8 ++- Source/CTest/cmParsePHPCoverage.cxx | 5 ++ Source/CTest/cmParsePHPCoverage.h | 8 ++- Source/CTest/cmProcess.cxx | 5 +- Source/CTest/cmProcess.h | 4 +- 93 files changed, 642 insertions(+), 177 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 09:58:59 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 09:58:59 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1436-g61a017f Message-ID: <20160825135859.C4CF0F5776@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 61a017f8810c9478009fe9e24e2968798bd13b59 (commit) via 98caa14cc84cc659c2c5b51f84c6547b57c89c30 (commit) via a79abb82fe1c90b65f124a8dd31e4a0227583ce4 (commit) via ce8fadc717b001b39b3208f8069cb0048073f975 (commit) via d1ee1cb81351cc9bd84cd7c3b755d0c4a5e45f6f (commit) via d8b70f62cb1a5ea7231c4236bed57206068a946c (commit) via d6734eeb875ceca5d810e829ca90541918dca2b4 (commit) from a668268d9bc890b5ec0bcc6670e399a33670674e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=61a017f8810c9478009fe9e24e2968798bd13b59 commit 61a017f8810c9478009fe9e24e2968798bd13b59 Merge: a668268 98caa14 Author: Brad King AuthorDate: Thu Aug 25 09:58:49 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 09:58:49 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 10:08:01 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 10:08:01 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1439-g826dd1e Message-ID: <20160825140801.629B0F5850@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 826dd1ed9908ac29fb375b7af232e7a13eaa647a (commit) via b290832699d3baefa7588fc25fd03513d2af82bc (commit) via 430090e0a6c186291491cdece2bb2e349343a331 (commit) from 61a017f8810c9478009fe9e24e2968798bd13b59 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=826dd1ed9908ac29fb375b7af232e7a13eaa647a commit 826dd1ed9908ac29fb375b7af232e7a13eaa647a Merge: 61a017f b290832 Author: Brad King AuthorDate: Thu Aug 25 10:08:00 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 10:08:00 2016 -0400 Merge topic 'FindwxWidgets-library-path' into next b2908326 FindwxWidgets: Add VS-versioned library directory prefixes 430090e0 FindwxWidgets: Add version 3.1.0 https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b290832699d3baefa7588fc25fd03513d2af82bc commit b290832699d3baefa7588fc25fd03513d2af82bc Author: Hannes Grobler <30o_24ff4snfv2oz at byom.de> AuthorDate: Wed Aug 24 23:09:26 2016 +0200 Commit: Brad King CommitDate: Thu Aug 25 10:05:47 2016 -0400 FindwxWidgets: Add VS-versioned library directory prefixes Add Visual Studio version number (supported: VS2008 to VS2015) to WX_LIB_DIR_PREFIX (old: vc / vc_x64; new: vc120 / vc120_x64). diff --git a/Modules/FindwxWidgets.cmake b/Modules/FindwxWidgets.cmake index 30b8e21..47a70f5 100644 --- a/Modules/FindwxWidgets.cmake +++ b/Modules/FindwxWidgets.cmake @@ -504,10 +504,22 @@ if(wxWidgets_FIND_STYLE STREQUAL "win32") # settings. if(MINGW) set(WX_LIB_DIR_PREFIX gcc) - elseif(CMAKE_CL_64) - set(WX_LIB_DIR_PREFIX vc_x64) - else() + elseif(MSVC) set(WX_LIB_DIR_PREFIX vc) + if(MSVC14) + set(WX_LIB_DIR_PREFIX ${WX_LIB_DIR_PREFIX}140) + elseif(MSVC12) + set(WX_LIB_DIR_PREFIX ${WX_LIB_DIR_PREFIX}120) + elseif(MSVC11) + set(WX_LIB_DIR_PREFIX ${WX_LIB_DIR_PREFIX}110) + elseif(MSVC10) + set(WX_LIB_DIR_PREFIX ${WX_LIB_DIR_PREFIX}100) + elseif(MSVC90) + set(WX_LIB_DIR_PREFIX ${WX_LIB_DIR_PREFIX}90) + endif() + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(WX_LIB_DIR_PREFIX ${WX_LIB_DIR_PREFIX}_x64) + endif() endif() if(BUILD_SHARED_LIBS) find_path(wxWidgets_LIB_DIR https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=430090e0a6c186291491cdece2bb2e349343a331 commit 430090e0a6c186291491cdece2bb2e349343a331 Author: Hannes Grobler <30o_24ff4snfv2oz at byom.de> AuthorDate: Wed Aug 24 23:09:26 2016 +0200 Commit: Brad King CommitDate: Thu Aug 25 10:04:42 2016 -0400 FindwxWidgets: Add version 3.1.0 diff --git a/Modules/FindwxWidgets.cmake b/Modules/FindwxWidgets.cmake index 2974b9e..30b8e21 100644 --- a/Modules/FindwxWidgets.cmake +++ b/Modules/FindwxWidgets.cmake @@ -452,6 +452,7 @@ if(wxWidgets_FIND_STYLE STREQUAL "win32") D:/ ENV ProgramFiles PATH_SUFFIXES + wxWidgets-3.1.0 wxWidgets-3.0.2 wxWidgets-3.0.1 wxWidgets-3.0.0 ----------------------------------------------------------------------- Summary of changes: Modules/FindwxWidgets.cmake | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 10:13:01 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 10:13:01 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1441-gd708b54 Message-ID: <20160825141301.41673F3948@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via d708b54d0dc44340c71b7288a719f846c4b27a39 (commit) via f325ae186d5d235cb90f4fb002a8df56abc050f8 (commit) from 826dd1ed9908ac29fb375b7af232e7a13eaa647a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d708b54d0dc44340c71b7288a719f846c4b27a39 commit d708b54d0dc44340c71b7288a719f846c4b27a39 Merge: 826dd1e f325ae1 Author: Brad King AuthorDate: Thu Aug 25 10:13:00 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 10:13:00 2016 -0400 Merge topic 'vs-resource-pri-dir' into next f325ae18 VS: Use target-specific directory for `resources.pri` https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f325ae186d5d235cb90f4fb002a8df56abc050f8 commit f325ae186d5d235cb90f4fb002a8df56abc050f8 Author: Brad King AuthorDate: Thu Aug 25 09:17:17 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 09:17:17 2016 -0400 VS: Use target-specific directory for `resources.pri` Set the `ProjectPriFullPath` field to a value that is unique to each target and not shared with others in order to avoid collisions. Closes: #16106 diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index c33a291..1b1d04b 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2741,9 +2741,9 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile() this->WriteString("", 2); (*this->BuildFileStream) << cmVS10EscapeXML(artifactDir) << "\\\n"; - this->WriteString("" - "$(TargetDir)resources.pri\n", - 2); + this->WriteString("", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(artifactDir) + << "\\resources.pri\n"; // If we are missing files and we don't have a certificate and // aren't targeting WP8.0, add a default certificate ----------------------------------------------------------------------- Summary of changes: Source/cmVisualStudio10TargetGenerator.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 10:15:48 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 10:15:48 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1443-gcd4b2e9 Message-ID: <20160825141548.C19EFF50B8@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via cd4b2e96fbc1f25f215baec95e10c6b338e7adc9 (commit) via aebd6167111f2fc6247dc173ff16917316bbe660 (commit) from d708b54d0dc44340c71b7288a719f846c4b27a39 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cd4b2e96fbc1f25f215baec95e10c6b338e7adc9 commit cd4b2e96fbc1f25f215baec95e10c6b338e7adc9 Merge: d708b54 aebd616 Author: Brad King AuthorDate: Thu Aug 25 10:15:46 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 10:15:46 2016 -0400 Merge topic '16101-xcode-fix-directory-exclude-from-all' into next aebd6167 Revert "Xcode: Add targets marked as EXCLUDE_FROM_ALL to project (#16101)" https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=aebd6167111f2fc6247dc173ff16917316bbe660 commit aebd6167111f2fc6247dc173ff16917316bbe660 Author: Brad King AuthorDate: Thu Aug 25 10:15:09 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 10:15:09 2016 -0400 Revert "Xcode: Add targets marked as EXCLUDE_FROM_ALL to project (#16101)" This reverts commit a0fbdb8b2c928306848dd19de0ceaf5a90c741a7. It has some compile warnings, test failures, and style violations. diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 7b7c744..780ca90 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -2639,6 +2639,9 @@ bool cmGlobalXCodeGenerator::CreateGroups( { for (std::vector::iterator i = generators.begin(); i != generators.end(); ++i) { + if (this->IsExcluded(root, *i)) { + continue; + } cmMakefile* mf = (*i)->GetMakefile(); std::vector sourceGroups = mf->GetSourceGroups(); std::vector tgts = (*i)->GetGeneratorTargets(); @@ -3038,8 +3041,10 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( std::vector targets; for (std::vector::iterator i = generators.begin(); i != generators.end(); ++i) { - if (!this->CreateXCodeTargets(*i, targets)) { - return false; + if (!this->IsExcluded(root, *i)) { + if (!this->CreateXCodeTargets(*i, targets)) { + return false; + } } } // loop over all targets and add link and depend info diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake b/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake deleted file mode 100644 index f686005..0000000 --- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake +++ /dev/null @@ -1,6 +0,0 @@ -enable_language(CXX) - -add_subdirectory(ExcludeFromAll EXCLUDE_FROM_ALL) - -add_executable(main main.cpp) -target_link_libraries(main PRIVATE foo) diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt deleted file mode 100644 index b1df6b0..0000000 --- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_library(bar STATIC bar.cpp) - -add_library(foo STATIC foo.cpp) -target_include_directories(foo PUBLIC .) diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp deleted file mode 100644 index 7a828bd..0000000 --- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp +++ /dev/null @@ -1 +0,0 @@ -#error This should be excluded from all target diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp deleted file mode 100644 index 2789e61..0000000 --- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "foo.h" - -int foo() { return 42; } diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.h b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.h deleted file mode 100644 index 5d5f8f0..0000000 --- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.h +++ /dev/null @@ -1 +0,0 @@ -int foo(); diff --git a/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake index 6d9418b..9d514e1 100644 --- a/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake +++ b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake @@ -3,15 +3,3 @@ include(RunCMake) run_cmake(DoesNotExist) run_cmake(Missing) run_cmake(Function) - -set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ExcludeFromAll) -set(RunCMake_TEST_NO_CLEAN 1) - -file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") -file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") - -run_cmake(ExcludeFromAll) -run_cmake_command(ExcludeFromAll-build ${CMAKE_COMMAND} --build .) - -unset(RunCMake_TEST_BINARY_DIR) -unset(RunCMake_TEST_NO_CLEAN) diff --git a/Tests/RunCMake/add_subdirectory/main.cpp b/Tests/RunCMake/add_subdirectory/main.cpp deleted file mode 100644 index 1fbb144..0000000 --- a/Tests/RunCMake/add_subdirectory/main.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "foo.h" - -int main(int argc, char* argv[]) -{ - return foo(); -} ----------------------------------------------------------------------- Summary of changes: Source/cmGlobalXCodeGenerator.cxx | 9 +++++++-- Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake | 6 ------ .../add_subdirectory/ExcludeFromAll/CMakeLists.txt | 4 ---- Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp | 1 - Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp | 3 --- Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.h | 1 - Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake | 12 ------------ Tests/RunCMake/add_subdirectory/main.cpp | 6 ------ 8 files changed, 7 insertions(+), 35 deletions(-) delete mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake delete mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt delete mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp delete mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp delete mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.h delete mode 100644 Tests/RunCMake/add_subdirectory/main.cpp hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 10:53:56 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 10:53:56 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1445-g7ea8c85 Message-ID: <20160825145356.913E8F4C4E@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 7ea8c85db1c15f2fec85203a6807c6f06555716e (commit) via 5eb9be54067af197934fa74a2686d152904fed77 (commit) from cd4b2e96fbc1f25f215baec95e10c6b338e7adc9 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7ea8c85db1c15f2fec85203a6807c6f06555716e commit 7ea8c85db1c15f2fec85203a6807c6f06555716e Merge: cd4b2e9 5eb9be5 Author: Brad King AuthorDate: Thu Aug 25 10:53:55 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 10:53:55 2016 -0400 Merge topic 'ninja-add_custom_command-depfile' into next 5eb9be54 add_custom_command: Add DEPFILE option for Ninja https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5eb9be54067af197934fa74a2686d152904fed77 commit 5eb9be54067af197934fa74a2686d152904fed77 Author: Kulla Christoph AuthorDate: Fri Aug 5 14:39:31 2016 +0200 Commit: Brad King CommitDate: Thu Aug 25 10:48:26 2016 -0400 add_custom_command: Add DEPFILE option for Ninja Provide a way for custom commands to inform the ninja build tool about their implicit dependencies. For now simply make use of the option an error on other generators. Closes: #15479 diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst index d421364..4ab4298 100644 --- a/Help/command/add_custom_command.rst +++ b/Help/command/add_custom_command.rst @@ -20,6 +20,7 @@ The first signature is for adding a custom command to produce an output:: [ depend2] ...] [WORKING_DIRECTORY dir] [COMMENT comment] + [DEPFILE depfile] [VERBATIM] [APPEND] [USES_TERMINAL]) This defines a command to generate specified ``OUTPUT`` file(s). @@ -170,6 +171,12 @@ The options are: If it is a relative path it will be interpreted relative to the build tree directory corresponding to the current source directory. +``DEPFILE`` + Specify a ``.d`` depfile for the :generator:`Ninja` generator. + A ``.d`` file holds dependencies usually emitted by the custom + command itself. + Using ``DEPFILE`` with other generators than Ninja is an error. + Build Events ^^^^^^^^^^^^ diff --git a/Help/release/dev/ninja-add_custom_command-depfile.rst b/Help/release/dev/ninja-add_custom_command-depfile.rst new file mode 100644 index 0000000..c8099fe --- /dev/null +++ b/Help/release/dev/ninja-add_custom_command-depfile.rst @@ -0,0 +1,6 @@ +ninja-add_custom_command-depfile +-------------------------------- + +* The :command:`add_custom_command` command gained a new ``DEPFILE`` + option that works with the :generator:`Ninja` generator to provide + implicit dependency information to the build tool. diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx index 400be77..2c4a4ca 100644 --- a/Source/cmAddCustomCommandCommand.cxx +++ b/Source/cmAddCustomCommandCommand.cxx @@ -15,6 +15,8 @@ #include "cmSourceFile.h" +#include "cmGlobalGenerator.h" + // cmAddCustomCommandCommand bool cmAddCustomCommandCommand::InitialPass( std::vector const& args, cmExecutionStatus&) @@ -28,7 +30,7 @@ bool cmAddCustomCommandCommand::InitialPass( return false; } - std::string source, target, main_dependency, working; + std::string source, target, main_dependency, working, depfile; std::string comment_buffer; const char* comment = CM_NULLPTR; std::vector depends, outputs, output, byproducts; @@ -60,6 +62,7 @@ bool cmAddCustomCommandCommand::InitialPass( doing_byproducts, doing_comment, doing_working_directory, + doing_depfile, doing_nothing }; @@ -110,6 +113,13 @@ bool cmAddCustomCommandCommand::InitialPass( doing = doing_implicit_depends_lang; } else if (copy == "COMMENT") { doing = doing_comment; + } else if (copy == "DEPFILE") { + doing = doing_depfile; + if (this->Makefile->GetGlobalGenerator()->GetName() != "Ninja") { + this->SetError("Option DEPFILE not supported by " + + this->Makefile->GetGlobalGenerator()->GetName()); + return false; + } } else { std::string filename; switch (doing) { @@ -147,6 +157,9 @@ bool cmAddCustomCommandCommand::InitialPass( filename = cmSystemTools::CollapseFullPath(filename); } switch (doing) { + case doing_depfile: + depfile = copy; + break; case doing_working_directory: working = copy; break; @@ -269,12 +282,12 @@ bool cmAddCustomCommandCommand::InitialPass( std::vector no_depends; this->Makefile->AddCustomCommandToTarget( target, byproducts, no_depends, commandLines, cctype, comment, - working.c_str(), escapeOldStyle, uses_terminal); + working.c_str(), escapeOldStyle, uses_terminal, depfile); } else if (target.empty()) { // Target is empty, use the output. this->Makefile->AddCustomCommandToOutput( output, byproducts, depends, main_dependency, commandLines, comment, - working.c_str(), false, escapeOldStyle, uses_terminal); + working.c_str(), false, escapeOldStyle, uses_terminal, depfile); // Add implicit dependency scanning requests if any were given. if (!implicit_depends.empty()) { diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx index 7533369..eaa49b0 100644 --- a/Source/cmCustomCommand.cxx +++ b/Source/cmCustomCommand.cxx @@ -135,3 +135,13 @@ void cmCustomCommand::SetUsesTerminal(bool b) { this->UsesTerminal = b; } + +const std::string& cmCustomCommand::GetDepfile() const +{ + return this->Depfile; +} + +void cmCustomCommand::SetDepfile(const std::string& depfile) +{ + this->Depfile = depfile; +} diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h index c2b9738..34753f4 100644 --- a/Source/cmCustomCommand.h +++ b/Source/cmCustomCommand.h @@ -88,6 +88,10 @@ public: bool GetUsesTerminal() const; void SetUsesTerminal(bool b); + /** Set/Get the depfile (used by the Ninja generator) */ + const std::string& GetDepfile() const; + void SetDepfile(const std::string& depfile); + private: std::vector Outputs; std::vector Byproducts; @@ -97,6 +101,7 @@ private: ImplicitDependsList ImplicitDepends; std::string Comment; std::string WorkingDirectory; + std::string Depfile; bool HaveComment; bool EscapeAllowMakeVars; bool EscapeOldStyle; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 2b83479..9bc8246 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -251,8 +251,8 @@ void cmGlobalNinjaGenerator::AddCustomCommandRule() void cmGlobalNinjaGenerator::WriteCustomCommandBuild( const std::string& command, const std::string& description, - const std::string& comment, bool uses_terminal, bool restat, - const cmNinjaDeps& outputs, const cmNinjaDeps& deps, + const std::string& comment, const std::string& depfile, bool uses_terminal, + bool restat, const cmNinjaDeps& outputs, const cmNinjaDeps& deps, const cmNinjaDeps& orderOnly) { std::string cmd = command; @@ -273,7 +273,9 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild( if (uses_terminal && SupportsConsolePool()) { vars["pool"] = "console"; } - + if (!depfile.empty()) { + vars["depfile"] = depfile; + } this->WriteBuild(*this->BuildFileStream, comment, "CUSTOM_COMMAND", outputs, deps, cmNinjaDeps(), orderOnly, vars); @@ -839,7 +841,7 @@ void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies() std::copy(i->second.begin(), i->second.end(), std::back_inserter(deps)); WriteCustomCommandBuild(/*command=*/"", /*description=*/"", "Assume dependencies for generated source file.", - /*uses_terminal*/ false, + /*depfile*/ "", /*uses_terminal*/ false, /*restat*/ true, cmNinjaDeps(1, i->first), deps); } } diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 52fa5c9..082ee3a 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -113,7 +113,8 @@ public: void WriteCustomCommandBuild(const std::string& command, const std::string& description, - const std::string& comment, bool uses_terminal, + const std::string& comment, + const std::string& depfile, bool uses_terminal, bool restat, const cmNinjaDeps& outputs, const cmNinjaDeps& deps = cmNinjaDeps(), const cmNinjaDeps& orderOnly = cmNinjaDeps()); diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 46d7e18..4200e5d 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -412,7 +412,8 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( } else { this->GetGlobalNinjaGenerator()->WriteCustomCommandBuild( this->BuildCommandLine(cmdLines), this->ConstructComment(ccg), - "Custom command for " + ninjaOutputs[0], cc->GetUsesTerminal(), + "Custom command for " + ninjaOutputs[0], cc->GetDepfile(), + cc->GetUsesTerminal(), /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, ninjaDeps, orderOnlyDeps); } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 6e47797..d1fddca 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -701,7 +701,7 @@ void cmMakefile::AddCustomCommandToTarget( const std::vector& depends, const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type, const char* comment, const char* workingDir, bool escapeOldStyle, - bool uses_terminal) + bool uses_terminal, const std::string& depfile) { // Find the target to which to add the custom command. cmTargets::iterator ti = this->Targets.find(target); @@ -773,6 +773,7 @@ void cmMakefile::AddCustomCommandToTarget( cc.SetEscapeOldStyle(escapeOldStyle); cc.SetEscapeAllowMakeVars(true); cc.SetUsesTerminal(uses_terminal); + cc.SetDepfile(depfile); switch (type) { case cmTarget::PRE_BUILD: ti->second.AddPreBuildCommand(cc); @@ -792,7 +793,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput( const std::vector& depends, const std::string& main_dependency, const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace, bool escapeOldStyle, - bool uses_terminal) + bool uses_terminal, const std::string& depfile) { // Make sure there is at least one output. if (outputs.empty()) { @@ -886,6 +887,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput( cc->SetEscapeOldStyle(escapeOldStyle); cc->SetEscapeAllowMakeVars(true); cc->SetUsesTerminal(uses_terminal); + cc->SetDepfile(depfile); file->SetCustomCommand(cc); this->UpdateOutputToSourceMap(outputs, file); } @@ -923,14 +925,14 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput( const std::string& output, const std::vector& depends, const std::string& main_dependency, const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace, - bool escapeOldStyle, bool uses_terminal) + bool escapeOldStyle, bool uses_terminal, const std::string& depfile) { std::vector outputs; outputs.push_back(output); std::vector no_byproducts; return this->AddCustomCommandToOutput( outputs, no_byproducts, depends, main_dependency, commandLines, comment, - workingDir, replace, escapeOldStyle, uses_terminal); + workingDir, replace, escapeOldStyle, uses_terminal, depfile); } void cmMakefile::AddCustomCommandOldStyle( diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index b3587c5..4d137db 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -135,14 +135,12 @@ public: void FinalPass(); /** Add a custom command to the build. */ - void AddCustomCommandToTarget(const std::string& target, - const std::vector& byproducts, - const std::vector& depends, - const cmCustomCommandLines& commandLines, - cmTarget::CustomCommandType type, - const char* comment, const char* workingDir, - bool escapeOldStyle = true, - bool uses_terminal = false); + void AddCustomCommandToTarget( + const std::string& target, const std::vector& byproducts, + const std::vector& depends, + const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type, + const char* comment, const char* workingDir, bool escapeOldStyle = true, + bool uses_terminal = false, const std::string& depfile = ""); cmSourceFile* AddCustomCommandToOutput( const std::vector& outputs, const std::vector& byproducts, @@ -150,13 +148,13 @@ public: const std::string& main_dependency, const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace = false, bool escapeOldStyle = true, - bool uses_terminal = false); + bool uses_terminal = false, const std::string& depfile = ""); cmSourceFile* AddCustomCommandToOutput( const std::string& output, const std::vector& depends, const std::string& main_dependency, const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace = false, bool escapeOldStyle = true, - bool uses_terminal = false); + bool uses_terminal = false, const std::string& depfile = ""); void AddCustomCommandOldStyle(const std::string& target, const std::vector& outputs, const std::vector& depends, diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx index 49836f2..0664104 100644 --- a/Source/cmNinjaUtilityTargetGenerator.cxx +++ b/Source/cmNinjaUtilityTargetGenerator.cxx @@ -150,7 +150,7 @@ void cmNinjaUtilityTargetGenerator::Generate() this->GetGlobalGenerator()->WriteCustomCommandBuild( command, desc, "Utility command for " + this->GetTargetName(), - uses_terminal, + /*depfile*/ "", uses_terminal, /*restat*/ true, util_outputs, deps); this->GetGlobalGenerator()->WritePhonyBuild( diff --git a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-result.txt b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt new file mode 100644 index 0000000..733c950 --- /dev/null +++ b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error at CustomCommandDepfile-ERROR.cmake:1 \(add_custom_command\): + add_custom_command Option DEPFILE not supported by Unix Makefiles diff --git a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR.cmake b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR.cmake new file mode 100644 index 0000000..bad7955 --- /dev/null +++ b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR.cmake @@ -0,0 +1,8 @@ +add_custom_command( + OUTPUT hello.copy.c + COMMAND "${CMAKE_COMMAND}" -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/hello.c" + hello.copy.c + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + DEPFILE "test.d" + ) diff --git a/Tests/RunCMake/Make/RunCMakeTest.cmake b/Tests/RunCMake/Make/RunCMakeTest.cmake index c6bbd03..869d11e 100644 --- a/Tests/RunCMake/Make/RunCMakeTest.cmake +++ b/Tests/RunCMake/Make/RunCMakeTest.cmake @@ -15,3 +15,5 @@ run_TargetMessages(OFF) run_TargetMessages(VAR-ON -DCMAKE_TARGET_MESSAGES=ON) run_TargetMessages(VAR-OFF -DCMAKE_TARGET_MESSAGES=OFF) + +run_cmake(CustomCommandDepfile-ERROR) diff --git a/Tests/RunCMake/Ninja/CustomCommandDepfile-check.cmake b/Tests/RunCMake/Ninja/CustomCommandDepfile-check.cmake new file mode 100644 index 0000000..189de64 --- /dev/null +++ b/Tests/RunCMake/Ninja/CustomCommandDepfile-check.cmake @@ -0,0 +1,5 @@ +set(log "${RunCMake_BINARY_DIR}/CustomCommandDepfile-build/build.ninja") +file(READ "${log}" build_file) +if(NOT "${build_file}" MATCHES "depfile = test\\.d") + set(RunCMake_TEST_FAILED "Log file:\n ${log}\ndoes not have expected line: depfile = test.d") +endif() diff --git a/Tests/RunCMake/Ninja/CustomCommandDepfile.cmake b/Tests/RunCMake/Ninja/CustomCommandDepfile.cmake new file mode 100644 index 0000000..dbef2a5 --- /dev/null +++ b/Tests/RunCMake/Ninja/CustomCommandDepfile.cmake @@ -0,0 +1,11 @@ +add_custom_command( + OUTPUT hello.copy.c + COMMAND "${CMAKE_COMMAND}" -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/hello.c" + hello.copy.c + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + DEPFILE "test.d" + ) +add_custom_target(copy ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/hello.copy.c") + +include(CheckNoPrefixSubDir.cmake) diff --git a/Tests/RunCMake/Ninja/RunCMakeTest.cmake b/Tests/RunCMake/Ninja/RunCMakeTest.cmake index 622c327..778f2c1 100644 --- a/Tests/RunCMake/Ninja/RunCMakeTest.cmake +++ b/Tests/RunCMake/Ninja/RunCMakeTest.cmake @@ -32,6 +32,8 @@ run_CMP0058(WARN-by) run_CMP0058(NEW-no) run_CMP0058(NEW-by) +run_cmake(CustomCommandDepfile) + function(run_SubDir) # Use a single build tree for a few tests without cleaning. set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SubDir-build) ----------------------------------------------------------------------- Summary of changes: Help/command/add_custom_command.rst | 7 +++++++ .../dev/ninja-add_custom_command-depfile.rst | 6 ++++++ Source/cmAddCustomCommandCommand.cxx | 19 ++++++++++++++++--- Source/cmCustomCommand.cxx | 10 ++++++++++ Source/cmCustomCommand.h | 5 +++++ Source/cmGlobalNinjaGenerator.cxx | 10 ++++++---- Source/cmGlobalNinjaGenerator.h | 3 ++- Source/cmLocalNinjaGenerator.cxx | 3 ++- Source/cmMakefile.cxx | 10 ++++++---- Source/cmMakefile.h | 18 ++++++++---------- Source/cmNinjaUtilityTargetGenerator.cxx | 2 +- .../CustomCommandDepfile-ERROR-result.txt} | 0 .../Make/CustomCommandDepfile-ERROR-stderr.txt | 2 ++ .../CustomCommandDepfile-ERROR.cmake} | 7 +------ Tests/RunCMake/Make/RunCMakeTest.cmake | 2 ++ .../RunCMake/Ninja/CustomCommandDepfile-check.cmake | 5 +++++ ...ngDirectory.cmake => CustomCommandDepfile.cmake} | 4 +--- Tests/RunCMake/Ninja/RunCMakeTest.cmake | 2 ++ 18 files changed, 82 insertions(+), 33 deletions(-) create mode 100644 Help/release/dev/ninja-add_custom_command-depfile.rst copy Tests/RunCMake/{Android/BadSYSROOT-result.txt => Make/CustomCommandDepfile-ERROR-result.txt} (100%) create mode 100644 Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt copy Tests/RunCMake/{Ninja/CustomCommandWorkingDirectory.cmake => Make/CustomCommandDepfile-ERROR.cmake} (54%) create mode 100644 Tests/RunCMake/Ninja/CustomCommandDepfile-check.cmake copy Tests/RunCMake/Ninja/{CustomCommandWorkingDirectory.cmake => CustomCommandDepfile.cmake} (84%) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 10:59:45 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 10:59:45 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1447-gd89838e Message-ID: <20160825145946.1FECAF5202@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via d89838e180cf2d1f6aab2c403135d599c775e9af (commit) via cd344e3a62e3a6728e5b749cb923104c2c09949c (commit) from 7ea8c85db1c15f2fec85203a6807c6f06555716e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d89838e180cf2d1f6aab2c403135d599c775e9af commit d89838e180cf2d1f6aab2c403135d599c775e9af Merge: 7ea8c85 cd344e3 Author: Brad King AuthorDate: Thu Aug 25 10:59:42 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 10:59:42 2016 -0400 Merge topic 'test-driver-clang-tidy' into next cd344e3a create_test_sourcelist: Use safer strncpy instead of strcpy https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cd344e3a62e3a6728e5b749cb923104c2c09949c commit cd344e3a62e3a6728e5b749cb923104c2c09949c Author: Sylvain Joubert AuthorDate: Thu Aug 25 11:54:28 2016 +0200 Commit: Brad King CommitDate: Thu Aug 25 10:56:50 2016 -0400 create_test_sourcelist: Use safer strncpy instead of strcpy Clang-tidy advises to use a safer function in place of strcpy. This should avoid such warnings in user build using clang-tidy. diff --git a/Templates/TestDriver.cxx.in b/Templates/TestDriver.cxx.in index ffa6999..3e0afa5 100644 --- a/Templates/TestDriver.cxx.in +++ b/Templates/TestDriver.cxx.in @@ -33,19 +33,21 @@ static functionMapEntry cmakeGeneratedFunctionMapEntries[] = { static char* lowercase(const char *string) { char *new_string, *p; + size_t stringSize = 0; #ifdef __cplusplus - new_string = static_cast(malloc(sizeof(char) * - static_cast(strlen(string) + 1))); + stringSize = static_cast(strlen(string) + 1); + new_string = static_cast(malloc(sizeof(char) * stringSize)); #else - new_string = (char *)(malloc(sizeof(char) * (size_t)(strlen(string) + 1))); + stringSize = (size_t)(strlen(string) + 1); + new_string = (char *)(malloc(sizeof(char) * stringSize)); #endif if (!new_string) { return 0; } - strcpy(new_string, string); + strncpy(new_string, string, stringSize); p = new_string; while (*p != 0) { ----------------------------------------------------------------------- Summary of changes: Templates/TestDriver.cxx.in | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 11:27:31 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 11:27:31 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1450-gf80a411 Message-ID: <20160825152731.D5C42F55BA@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via f80a4113e66cc5e83367af25c96faeaaa95d7a46 (commit) via 20d7da5276704864569fb08259278a08c5f9e725 (commit) via 4ef8a205edf66b652418aa5491436d26fd806175 (commit) from d89838e180cf2d1f6aab2c403135d599c775e9af (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f80a4113e66cc5e83367af25c96faeaaa95d7a46 commit f80a4113e66cc5e83367af25c96faeaaa95d7a46 Merge: d89838e 20d7da5 Author: Brad King AuthorDate: Thu Aug 25 11:27:31 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 11:27:31 2016 -0400 Merge topic 'FindwxWidgets-library-path' into next 20d7da52 FindwxWidgets: Add VS-versioned library directory prefixes 4ef8a205 FindwxWidgets: Add version 3.1.0 https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=20d7da5276704864569fb08259278a08c5f9e725 commit 20d7da5276704864569fb08259278a08c5f9e725 Author: Brad King AuthorDate: Wed Aug 24 23:09:26 2016 +0200 Commit: Brad King CommitDate: Thu Aug 25 11:26:34 2016 -0400 FindwxWidgets: Add VS-versioned library directory prefixes Add Visual Studio version number (supported: VS2008 to VS2015) to WX_LIB_DIR_PREFIX (old: vc / vc_x64; new: vc120 / vc120_x64). Patch-by: Hannes Grobler (Johnny_xy on gitlab.kitware.com) diff --git a/Modules/FindwxWidgets.cmake b/Modules/FindwxWidgets.cmake index 30b8e21..47a70f5 100644 --- a/Modules/FindwxWidgets.cmake +++ b/Modules/FindwxWidgets.cmake @@ -504,10 +504,22 @@ if(wxWidgets_FIND_STYLE STREQUAL "win32") # settings. if(MINGW) set(WX_LIB_DIR_PREFIX gcc) - elseif(CMAKE_CL_64) - set(WX_LIB_DIR_PREFIX vc_x64) - else() + elseif(MSVC) set(WX_LIB_DIR_PREFIX vc) + if(MSVC14) + set(WX_LIB_DIR_PREFIX ${WX_LIB_DIR_PREFIX}140) + elseif(MSVC12) + set(WX_LIB_DIR_PREFIX ${WX_LIB_DIR_PREFIX}120) + elseif(MSVC11) + set(WX_LIB_DIR_PREFIX ${WX_LIB_DIR_PREFIX}110) + elseif(MSVC10) + set(WX_LIB_DIR_PREFIX ${WX_LIB_DIR_PREFIX}100) + elseif(MSVC90) + set(WX_LIB_DIR_PREFIX ${WX_LIB_DIR_PREFIX}90) + endif() + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(WX_LIB_DIR_PREFIX ${WX_LIB_DIR_PREFIX}_x64) + endif() endif() if(BUILD_SHARED_LIBS) find_path(wxWidgets_LIB_DIR https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4ef8a205edf66b652418aa5491436d26fd806175 commit 4ef8a205edf66b652418aa5491436d26fd806175 Author: Brad King AuthorDate: Wed Aug 24 23:09:26 2016 +0200 Commit: Brad King CommitDate: Thu Aug 25 11:25:38 2016 -0400 FindwxWidgets: Add version 3.1.0 Patch-by: Hannes Grobler (Johnny_xy on gitlab.kitware.com) diff --git a/Modules/FindwxWidgets.cmake b/Modules/FindwxWidgets.cmake index 2974b9e..30b8e21 100644 --- a/Modules/FindwxWidgets.cmake +++ b/Modules/FindwxWidgets.cmake @@ -452,6 +452,7 @@ if(wxWidgets_FIND_STYLE STREQUAL "win32") D:/ ENV ProgramFiles PATH_SUFFIXES + wxWidgets-3.1.0 wxWidgets-3.0.2 wxWidgets-3.0.1 wxWidgets-3.0.0 ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From domen.vrankar at gmail.com Thu Aug 25 13:17:30 2016 From: domen.vrankar at gmail.com (Domen Vrankar) Date: Thu, 25 Aug 2016 13:17:30 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1453-g5a38fe2 Message-ID: <20160825171730.8F145F5705@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 5a38fe2135c8f421e79027ff0f5d6525c6c4449f (commit) via a6d9d783b45dcec84dd16b2fb0f0bef53c0b2487 (commit) via bc8c0add7f799ad5775e4f229256832e17156b68 (commit) from f80a4113e66cc5e83367af25c96faeaaa95d7a46 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5a38fe2135c8f421e79027ff0f5d6525c6c4449f commit 5a38fe2135c8f421e79027ff0f5d6525c6c4449f Merge: f80a411 a6d9d78 Author: Domen Vrankar AuthorDate: Thu Aug 25 13:17:28 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 13:17:28 2016 -0400 Merge topic 'cpack-rpm-debuginfo-pkg' into next a6d9d783 cpack-rpm-debuginfo bc8c0add CPack RPM debuginfo packages generation https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a6d9d783b45dcec84dd16b2fb0f0bef53c0b2487 commit a6d9d783b45dcec84dd16b2fb0f0bef53c0b2487 Author: Domen Vrankar AuthorDate: Thu Aug 25 18:35:42 2016 +0200 Commit: Domen Vrankar CommitDate: Thu Aug 25 18:36:09 2016 +0200 cpack-rpm-debuginfo test and release notes diff --git a/Help/release/dev/cpack-rpm-debuginfo-pkg.rst b/Help/release/dev/cpack-rpm-debuginfo-pkg.rst new file mode 100644 index 0000000..f02a162 --- /dev/null +++ b/Help/release/dev/cpack-rpm-debuginfo-pkg.rst @@ -0,0 +1,6 @@ +cpack-rpm-debuginfo-pkg +------------------ + +* The :module:`CPackRPM` module learned to generate debuginfo + packages on demand. See :variable:`CPACK_RPM_DEBUGINFO_PACKAGE` + and its per component version. diff --git a/Tests/RunCMake/CPack/DEBUGINFO.cmake b/Tests/RunCMake/CPack/DEBUGINFO.cmake new file mode 100644 index 0000000..2a65b7f --- /dev/null +++ b/Tests/RunCMake/CPack/DEBUGINFO.cmake @@ -0,0 +1,26 @@ +set(CMAKE_BUILD_WITH_INSTALL_RPATH 1) + +set(CPACK_RPM_COMPONENT_INSTALL "ON") + +set(CMAKE_BUILD_TYPE Debug) + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.hpp" + "int test_lib();\n") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp" + "#include \"test_lib.hpp\"\nint test_lib() {return 0;}\n") +add_library(test_lib SHARED "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp") + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp" + "#include \"test_lib.hpp\"\nint main() {return test_lib();}\n") +add_executable(test_prog "${CMAKE_CURRENT_BINARY_DIR}/main.cpp") +target_link_libraries(test_prog test_lib) + +install(TARGETS test_prog DESTINATION foo COMPONENT applications) +install(FILES CMakeLists.txt DESTINATION bar COMPONENT headers) +install(TARGETS test_lib DESTINATION bas COMPONENT libs) + +set(CPACK_RPM_APPLICATIONS_FILE_NAME "RPM-DEFAULT") +set(CPACK_RPM_APPLICATIONS_DEBUGINFO_PACKAGE ON) +set(CPACK_RPM_LIBS_DEBUGINFO_PACKAGE ON) + +set(CPACK_PACKAGE_NAME "debuginfo") diff --git a/Tests/RunCMake/CPack/RPM/DEBUGINFO-ExpectedFiles.cmake b/Tests/RunCMake/CPack/RPM/DEBUGINFO-ExpectedFiles.cmake new file mode 100644 index 0000000..265ca92 --- /dev/null +++ b/Tests/RunCMake/CPack/RPM/DEBUGINFO-ExpectedFiles.cmake @@ -0,0 +1,14 @@ +set(whitespaces_ "[\t\n\r ]*") + +set(EXPECTED_FILES_COUNT "5") +set(EXPECTED_FILE_1 "debuginfo-applications-0*.rpm") +set(EXPECTED_FILE_CONTENT_1 "^/usr/foo${whitespaces_}/usr/foo/test_prog$") +set(EXPECTED_FILE_2 "debuginfo*-headers.rpm") +set(EXPECTED_FILE_CONTENT_2 "^/usr/bar${whitespaces_}/usr/bar/CMakeLists.txt$") +set(EXPECTED_FILE_3 "debuginfo*-libs.rpm") +set(EXPECTED_FILE_CONTENT_3 "^/usr/bas${whitespaces_}/usr/bas/libtest_lib.so$") + +set(EXPECTED_FILE_4 "debuginfo-applications-debuginfo*.rpm") +set(EXPECTED_FILE_CONTENT_4 ".*") +set(EXPECTED_FILE_5 "debuginfo-libs-debuginfo*.rpm") +set(EXPECTED_FILE_CONTENT_5 ".*") diff --git a/Tests/RunCMake/CPack/RPM/DEBUGINFO-stderr.txt b/Tests/RunCMake/CPack/RPM/DEBUGINFO-stderr.txt new file mode 100644 index 0000000..557ef3d --- /dev/null +++ b/Tests/RunCMake/CPack/RPM/DEBUGINFO-stderr.txt @@ -0,0 +1,3 @@ +^CPackRPM: Will use GENERATED spec file: .*/Tests/RunCMake/RPM/CPack/DEBUGINFO-build/_CPack_Packages/.*/RPM/SPECS/debuginfo-applications.spec +CPackRPM: Will use GENERATED spec file: .*/Tests/RunCMake/RPM/CPack/DEBUGINFO-build/_CPack_Packages/.*/RPM/SPECS/debuginfo-headers.spec +CPackRPM: Will use GENERATED spec file: .*/Tests/RunCMake/RPM/CPack/DEBUGINFO-build/_CPack_Packages/.*/RPM/SPECS/debuginfo-libs.spec$ diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake index 59c52f8..44586d7 100644 --- a/Tests/RunCMake/CPack/RunCMakeTest.cmake +++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake @@ -16,3 +16,4 @@ run_cpack_test(RPM_DIST "RPM" false) run_cpack_test(INSTALL_SCRIPTS "RPM" false) run_cpack_test(DEB_GENERATE_SHLIBS "DEB" true) run_cpack_test(DEB_GENERATE_SHLIBS_LDCONFIG "DEB" true) +run_cpack_test(DEBUGINFO "RPM" true) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bc8c0add7f799ad5775e4f229256832e17156b68 commit bc8c0add7f799ad5775e4f229256832e17156b68 Author: Istvan Bodnar AuthorDate: Mon Aug 22 23:40:15 2016 +0200 Commit: Domen Vrankar CommitDate: Thu Aug 25 18:36:09 2016 +0200 CPack RPM debuginfo packages generation Added new variable to CPackRPM for debuginfo rpm package generation. Binaries will be checked for debug symbols. diff --git a/Modules/CPackRPM.cmake b/Modules/CPackRPM.cmake index c195746..36caac6 100644 --- a/Modules/CPackRPM.cmake +++ b/Modules/CPackRPM.cmake @@ -60,6 +60,14 @@ # * Mandatory : YES # * Default : :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY` # +# .. variable:: CPACK_RPM_DEBUGINFO_PACKAGE +# CPACK_RPM__DEBUGINFO_PACKAGE +# +# Option to additionally generate debuginfo RPM package(s). +# +# * Mandatory : NO +# * Default : OFF +# # .. variable:: CPACK_RPM_PACKAGE_NAME # CPACK_RPM__PACKAGE_NAME # @@ -1236,6 +1244,30 @@ if(NOT UNIX) message(FATAL_ERROR "CPackRPM.cmake may only be used under UNIX.") endif() +# We need to check if the binaries were compiled with debug symbols +# because without them the package will be useless +function(cpack_rpm_debugsymbol_check INSTALL_FILES WORKING_DIR) + # With objdump we should check the debug symbols + find_program(OBJDUMP_EXECUTABLE objdump) + if(NOT OBJDUMP_EXECUTABLE) + message(WARNING "CPackRPM: objdump binary could not be found!") + endif() + + foreach(F IN LISTS INSTALL_FILES) + execute_process(COMMAND "${OBJDUMP_EXECUTABLE}" -h ${WORKING_DIR}/${F} + WORKING_DIRECTORY "${CPACK_TOPLEVEL_DIRECTORY}" + RESULT_VARIABLE OBJDUMP_EXEC_RESULT + OUTPUT_VARIABLE OBJDUMP_OUT) + # Check that if the given file was executable or not + if(NOT OBJDUMP_EXEC_RESULT) + string(FIND "${OBJDUMP_OUT}" "debug" FIND_RESULT) + if(NOT FIND_RESULT GREATER -1) + message(WARNING "CPackRPM: File: ${F} does not contain debug symbols. They will possibly be missing from debuginfo package!") + endif() + endif() + endforeach() +endfunction() + function(cpack_rpm_variable_fallback OUTPUT_VAR_NAME) set(FALLBACK_VAR_NAMES ${ARGN}) @@ -1804,6 +1836,15 @@ function(cpack_rpm_generate_package) "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_USER_BINARY_SPECFILE") endif() + cpack_rpm_variable_fallback("CPACK_RPM_DEBUGINFO_PACKAGE" + "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_DEBUGINFO_PACKAGE" + "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_DEBUGINFO_PACKAGE" + "CPACK_RPM_DEBUGINFO_PACKAGE") + if(CPACK_RPM_DEBUGINFO_PACKAGE) + cpack_rpm_debugsymbol_check("${CPACK_ABSOLUTE_DESTINATION_FILES}" "${WDIR}") + set(TMP_RPM_DEBUGINFO "%debug_package") + endif() + cpack_rpm_variable_fallback("CPACK_RPM_FILE_NAME" "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_FILE_NAME" "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_FILE_NAME" @@ -1824,7 +1865,9 @@ function(cpack_rpm_generate_package) # else example: #set(CPACK_RPM_FILE_NAME "${CPACK_RPM_PACKAGE_NAME}-${CPACK_RPM_PACKAGE_VERSION}-${CPACK_RPM_PACKAGE_RELEASE}-${CPACK_RPM_PACKAGE_ARCHITECTURE}.rpm") - set(FILE_NAME_DEFINE "%define _rpmfilename ${CPACK_RPM_FILE_NAME}") + if(NOT CPACK_RPM_DEBUGINFO_PACKAGE) + set(FILE_NAME_DEFINE "%define _rpmfilename ${CPACK_RPM_FILE_NAME}") + endif() endif() # We should generate a USER spec file template: @@ -1856,6 +1899,8 @@ Vendor: \@CPACK_RPM_PACKAGE_VENDOR\@ \@TMP_RPM_BUILDARCH\@ \@TMP_RPM_PREFIXES\@ +\@TMP_RPM_DEBUGINFO\@ + %define _rpmdir \@CPACK_RPM_DIRECTORY\@ \@FILE_NAME_DEFINE\@ %define _unpackaged_files_terminate_build 0 @@ -1911,7 +1956,7 @@ mv \"\@CPACK_TOPLEVEL_DIRECTORY\@/tmpBBroot\" $RPM_BUILD_ROOT # The generated file may then be used as a template by user who wants # to customize their own spec file. if(CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE) - message(FATAL_ERROR "CPackRPM: STOP here Generated USER binary spec file templare is: ${CPACK_RPM_BINARY_SPECFILE}.in") + message(FATAL_ERROR "CPackRPM: STOP here Generated USER binary spec file template is: ${CPACK_RPM_BINARY_SPECFILE}.in") endif() endif() @@ -1968,6 +2013,22 @@ mv \"\@CPACK_TOPLEVEL_DIRECTORY\@/tmpBBroot\" $RPM_BUILD_ROOT message(FATAL_ERROR "RPM package was not generated! ${CPACK_RPM_DIRECTORY}") endif() + if(CPACK_RPM_DEBUGINFO_PACKAGE AND NOT CPACK_RPM_FILE_NAME STREQUAL "RPM-DEFAULT") + string(TOLOWER "${CPACK_RPM_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}.*\\.rpm" EXPECTED_FILENAME) + + foreach(F IN LISTS GENERATED_FILES) + if(F MATCHES ".*/${EXPECTED_FILENAME}") + get_filename_component(FILE_PATH "${F}" DIRECTORY) + file(RENAME "${F}" "${FILE_PATH}/${CPACK_RPM_FILE_NAME}") + list(APPEND new_files_list_ "${FILE_PATH}/${CPACK_RPM_FILE_NAME}") + else() + list(APPEND new_files_list_ "${F}") + endif() + endforeach() + + set(GENERATED_FILES "${new_files_list_}") + endif() + set(GEN_CPACK_OUTPUT_FILES "${GENERATED_FILES}" PARENT_SCOPE) if(CPACK_RPM_PACKAGE_DEBUG) ----------------------------------------------------------------------- Summary of changes: Help/release/dev/cpack-rpm-debuginfo-pkg.rst | 6 ++ Modules/CPackRPM.cmake | 65 +++++++++++++++++++- .../CPack/{DEPENDENCIES.cmake => DEBUGINFO.cmake} | 12 +++- .../CPack/RPM/DEBUGINFO-ExpectedFiles.cmake | 14 +++++ Tests/RunCMake/CPack/RPM/DEBUGINFO-stderr.txt | 3 + Tests/RunCMake/CPack/RunCMakeTest.cmake | 1 + 6 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 Help/release/dev/cpack-rpm-debuginfo-pkg.rst copy Tests/RunCMake/CPack/{DEPENDENCIES.cmake => DEBUGINFO.cmake} (74%) create mode 100644 Tests/RunCMake/CPack/RPM/DEBUGINFO-ExpectedFiles.cmake create mode 100644 Tests/RunCMake/CPack/RPM/DEBUGINFO-stderr.txt hooks/post-receive -- CMake From brad.king at kitware.com Thu Aug 25 14:30:35 2016 From: brad.king at kitware.com (Brad King) Date: Thu, 25 Aug 2016 14:30:35 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1469-g33ab8bd Message-ID: <20160825183036.01FB8F5844@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 33ab8bdd0aad3e44e8d85a730daca64c26ad71b1 (commit) via cc4220e76c9a88baa0232b2ff525900e297b3827 (commit) via b2a031f4cb9f1d9180caa990fc13697c04459488 (commit) via bde497f83d311371731b737cfdb9ced75af840c8 (commit) via 9c57ac5ad8f048dfdae7d5e28885ca7bfa70b938 (commit) via 98ca133e64258f812a2359e356b13759775a0af0 (commit) via 33a62bb0e07dbb345fffff0387a34ef2305ab2fc (commit) via 04abc90dfdc88b3759829a27f95fd8bb35727c10 (commit) via b19a5e3ebc1c53fb1c4b7c2881e2ef0ca57ff60f (commit) via 362e42d39e9b451b7e8aef05644bc26ffe964abf (commit) via d08a3b2ea3f9ea4b254a9bd70d66e05e60c82814 (commit) via 98aabffff41aeef2b549c3a4e2cd0962c48d59bf (commit) via 738b10e44733c713961c3c54d35134434ee010cb (commit) via dbc3fb0a90ef09e1b1b31da0a26a14bb1f804f3d (commit) via f0df3d4a123545d4e0d0c1dddb7f0b524efb403d (commit) via 0cb012e03cd6ad6b12adf3b0547eb91fadbe7292 (commit) from 5a38fe2135c8f421e79027ff0f5d6525c6c4449f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=33ab8bdd0aad3e44e8d85a730daca64c26ad71b1 commit 33ab8bdd0aad3e44e8d85a730daca64c26ad71b1 Merge: 5a38fe2 cc4220e Author: Brad King AuthorDate: Thu Aug 25 14:30:30 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 14:30:30 2016 -0400 Merge topic 'import-libuv' into next cc4220e7 cmake: Add trivial usage of libuv b2a031f4 Do not build libuv on Mac OS X 10.4 and lower bde497f8 Add option to build CMake against a system libuv 9c57ac5a FindLibUV: Add module to find libuv package 98ca133e libuv: Avoid including macOS CoreServices header globally 33a62bb0 libuv: Always include our own header first 04abc90d libuv: Conditionally declare Windows APIs for VS 2008 and below b19a5e3e libuv: Fix anonymous union syntax 362e42d3 libuv: Fix Windows API function typedef syntax d08a3b2e libuv: Install LICENSE file with CMake documentation 98aabfff libuv: Disable warnings to avoid changing 3rd party code 738b10e4 libuv: Build the library within CMake dbc3fb0a Merge branch 'upstream-libuv' into import-libuv f0df3d4a libuv 2016-08-25 (9e641d25) 0cb012e0 Add script to update libuv from upstream https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cc4220e76c9a88baa0232b2ff525900e297b3827 commit cc4220e76c9a88baa0232b2ff525900e297b3827 Author: Brad King AuthorDate: Thu Aug 25 14:12:42 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 14:12:42 2016 -0400 cmake: Add trivial usage of libuv This will serve to make sure cmake actually compiles and links against libuv. diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 1505d00..db6d51b 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -27,6 +27,10 @@ #include "cmcmd.h" #include +#ifdef CMAKE_USE_LIBUV +#include "cm_uv.h" +#endif + #ifdef CMAKE_BUILD_WITH_CMAKE static const char* cmDocumentationName[][2] = { { CM_NULLPTR, " cmake - Cross-Platform Makefile Generator." }, @@ -172,6 +176,9 @@ int main(int ac, char const* const* av) #ifdef CMAKE_BUILD_WITH_CMAKE cmDynamicLoader::FlushCache(); #endif +#ifdef CMAKE_USE_LIBUV + uv_loop_close(uv_default_loop()); +#endif return ret; } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b2a031f4cb9f1d9180caa990fc13697c04459488 commit b2a031f4cb9f1d9180caa990fc13697c04459488 Author: Brad King AuthorDate: Thu Aug 25 13:43:50 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 13:53:55 2016 -0400 Do not build libuv on Mac OS X 10.4 and lower It needs APIs that have been available only since 10.5. Also check that the CoreServices header can be included. diff --git a/CMakeLists.txt b/CMakeLists.txt index 13e2401..b62f6a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -468,6 +468,20 @@ macro (CMAKE_BUILD_UTILITIES) # Build libuv library. if(NOT DEFINED CMAKE_USE_LIBUV) set(CMAKE_USE_LIBUV 1) + if(APPLE) + include(CheckCSourceCompiles) + check_c_source_compiles(" +#include +#include +#ifndef MAC_OS_X_VERSION_10_5 +#error \"MAC_OS_X_VERSION_10_5 is not defined\" +#endif +int main(void) { return 0; } +" HAVE_CoreServices_OS_X_10_5) + if(NOT HAVE_CoreServices_OS_X_10_5) + set(CMAKE_USE_LIBUV 0) + endif() + endif() endif() if(CMAKE_USE_LIBUV) if(CMAKE_USE_SYSTEM_LIBUV) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bde497f83d311371731b737cfdb9ced75af840c8 commit bde497f83d311371731b737cfdb9ced75af840c8 Author: Brad King AuthorDate: Tue Aug 16 17:01:23 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 13:52:37 2016 -0400 Add option to build CMake against a system libuv Create a CMAKE_USE_SYSTEM_LIBUV option. diff --git a/CMakeLists.txt b/CMakeLists.txt index 958beb6..13e2401 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,7 +112,7 @@ macro(CMAKE_HANDLE_SYSTEM_LIBRARIES) # Allow the user to enable/disable all system utility library options by # defining CMAKE_USE_SYSTEM_LIBRARIES or CMAKE_USE_SYSTEM_LIBRARY_${util}. - set(UTILITIES BZIP2 CURL EXPAT FORM JSONCPP LIBARCHIVE LIBLZMA ZLIB) + set(UTILITIES BZIP2 CURL EXPAT FORM JSONCPP LIBARCHIVE LIBLZMA LIBUV ZLIB) foreach(util ${UTILITIES}) if(NOT DEFINED CMAKE_USE_SYSTEM_LIBRARY_${util} AND DEFINED CMAKE_USE_SYSTEM_LIBRARIES) @@ -152,6 +152,7 @@ macro(CMAKE_HANDLE_SYSTEM_LIBRARIES) "${CMAKE_USE_SYSTEM_LIBRARY_LIBLZMA}" "NOT CMAKE_USE_SYSTEM_LIBARCHIVE" ON) option(CMAKE_USE_SYSTEM_FORM "Use system-installed libform" "${CMAKE_USE_SYSTEM_LIBRARY_FORM}") option(CMAKE_USE_SYSTEM_JSONCPP "Use system-installed jsoncpp" "${CMAKE_USE_SYSTEM_LIBRARY_JSONCPP}") + option(CMAKE_USE_SYSTEM_LIBUV "Use system-installed libuv" "${CMAKE_USE_SYSTEM_LIBRARY_LIBUV}") # For now use system KWIML only if explicitly requested rather # than activating via the general system libs options. @@ -469,9 +470,22 @@ macro (CMAKE_BUILD_UTILITIES) set(CMAKE_USE_LIBUV 1) endif() if(CMAKE_USE_LIBUV) - set(CMAKE_LIBUV_LIBRARIES cmlibuv) - add_subdirectory(Utilities/cmlibuv) - CMAKE_SET_TARGET_FOLDER(cmlibuv "Utilities/3rdParty") + if(CMAKE_USE_SYSTEM_LIBUV) + if(NOT CMAKE_VERSION VERSION_LESS 3.0) + include(${CMake_SOURCE_DIR}/Source/Modules/FindLibUV.cmake) + else() + message(FATAL_ERROR "CMAKE_USE_SYSTEM_LIBUV requires CMake >= 3.0") + endif() + if(NOT LIBUV_FOUND) + message(FATAL_ERROR + "CMAKE_USE_SYSTEM_LIBUV is ON but a libuv is not found!") + endif() + set(CMAKE_LIBUV_LIBRARIES LibUV::LibUV) + else() + set(CMAKE_LIBUV_LIBRARIES cmlibuv) + add_subdirectory(Utilities/cmlibuv) + CMAKE_SET_TARGET_FOLDER(cmlibuv "Utilities/3rdParty") + endif() else() set(CMAKE_LIBUV_LIBRARIES) endif() diff --git a/Utilities/cmThirdParty.h.in b/Utilities/cmThirdParty.h.in index 4c1177c..cb8f0d5 100644 --- a/Utilities/cmThirdParty.h.in +++ b/Utilities/cmThirdParty.h.in @@ -22,6 +22,7 @@ #cmakedefine CMAKE_USE_SYSTEM_LIBLZMA #cmakedefine CMAKE_USE_SYSTEM_FORM #cmakedefine CMAKE_USE_SYSTEM_JSONCPP +#cmakedefine CMAKE_USE_SYSTEM_LIBUV #cmakedefine CTEST_USE_XMLRPC #endif diff --git a/Utilities/cm_uv.h b/Utilities/cm_uv.h index 63ff597..baa9bfc 100644 --- a/Utilities/cm_uv.h +++ b/Utilities/cm_uv.h @@ -12,6 +12,12 @@ #ifndef cm_uv_h #define cm_uv_h +/* Use the libuv library configured for CMake. */ +#include "cmThirdParty.h" +#ifdef CMAKE_USE_SYSTEM_LIBUV +#include +#else #include +#endif #endif https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9c57ac5ad8f048dfdae7d5e28885ca7bfa70b938 commit 9c57ac5ad8f048dfdae7d5e28885ca7bfa70b938 Author: Brad King AuthorDate: Tue Aug 16 16:56:34 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 13:52:37 2016 -0400 FindLibUV: Add module to find libuv package Add it to a private source directory that is not installed so that we can use it for building CMake itself. This will allow it to mature before being distributed publicly. diff --git a/Source/Modules/FindLibUV.cmake b/Source/Modules/FindLibUV.cmake new file mode 100644 index 0000000..7391aa7 --- /dev/null +++ b/Source/Modules/FindLibUV.cmake @@ -0,0 +1,131 @@ +#[=======================================================================[.rst: +FindLibUV +--------- + +Find libuv includes and library. + +Imported Targets +^^^^^^^^^^^^^^^^ + +An :ref:`imported target ` named +``LibUV::LibUV`` is provided if libuv has been found. + +Result Variables +^^^^^^^^^^^^^^^^ + +This module defines the following variables: + +``LibUV_FOUND`` + True if libuv was found, false otherwise. +``LibUV_INCLUDE_DIRS`` + Include directories needed to include libuv headers. +``LibUV_LIBRARIES`` + Libraries needed to link to libuv. +``LibUV_VERSION`` + The version of libuv found. +``LibUV_VERSION_MAJOR`` + The major version of libuv. +``LibUV_VERSION_MINOR`` + The minor version of libuv. +``LibUV_VERSION_PATCH`` + The patch version of libuv. + +Cache Variables +^^^^^^^^^^^^^^^ + +This module uses the following cache variables: + +``LibUV_LIBRARY`` + The location of the libuv library file. +``LibUV_INCLUDE_DIR`` + The location of the libuv include directory containing ``uv.h``. + +The cache variables should not be used by project code. +They may be set by end users to point at libuv components. +#]=======================================================================] + +#============================================================================= +# Copyright 2014-2016 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +#----------------------------------------------------------------------------- +find_library(LibUV_LIBRARY + NAMES uv + ) +mark_as_advanced(LibUV_LIBRARY) + +find_path(LibUV_INCLUDE_DIR + NAMES uv.h + ) +mark_as_advanced(LibUV_INCLUDE_DIR) + +#----------------------------------------------------------------------------- +# Extract version number if possible. +set(_LibUV_H_REGEX "#[ \t]*define[ \t]+UV_VERSION_(MAJOR|MINOR|PATCH)[ \t]+[0-9]+") +if(LibUV_INCLUDE_DIR AND EXISTS "${LibUV_INCLUDE_DIR}/uv-version.h") + file(STRINGS "${LibUV_INCLUDE_DIR}/uv-version.h" _LibUV_H REGEX "${_LibUV_H_REGEX}") +elseif(LibUV_INCLUDE_DIR AND EXISTS "${LibUV_INCLUDE_DIR}/uv.h") + file(STRINGS "${LibUV_INCLUDE_DIR}/uv.h" _LibUV_H REGEX "${_LibUV_H_REGEX}") +else() + set(_LibUV_H "") +endif() +foreach(c MAJOR MINOR PATCH) + if(_LibUV_H MATCHES "#[ \t]*define[ \t]+UV_VERSION_${c}[ \t]+([0-9]+)") + set(_LibUV_VERSION_${c} "${CMAKE_MATCH_1}") + else() + unset(_LibUV_VERSION_${c}) + endif() +endforeach() +if(DEFINED _LibUV_VERSION_MAJOR AND DEFINED _LibUV_VERSION_MINOR) + set(LibUV_VERSION_MAJOR "${_LibUV_VERSION_MAJOR}") + set(LibUV_VERSION_MINOR "${_LibUV_VERSION_MINOR}") + set(LibUV_VERSION "${LibUV_VERSION_MAJOR}.${LibUV_VERSION_MINOR}") + if(DEFINED _LibUV_VERSION_PATCH) + set(LibUV_VERSION_PATCH "${_LibUV_VERSION_PATCH}") + set(LibUV_VERSION "${LibUV_VERSION}.${LibUV_VERSION_PATCH}") + else() + unset(LibUV_VERSION_PATCH) + endif() +else() + set(LibUV_VERSION_MAJOR "") + set(LibUV_VERSION_MINOR "") + set(LibUV_VERSION_PATCH "") + set(LibUV_VERSION "") +endif() +unset(_LibUV_VERSION_MAJOR) +unset(_LibUV_VERSION_MINOR) +unset(_LibUV_VERSION_PATCH) +unset(_LibUV_H_REGEX) +unset(_LibUV_H) + +#----------------------------------------------------------------------------- +include(${CMAKE_CURRENT_LIST_DIR}/../../Modules/FindPackageHandleStandardArgs.cmake) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibUV + FOUND_VAR LibUV_FOUND + REQUIRED_VARS LibUV_LIBRARY LibUV_INCLUDE_DIR + VERSION_VAR LibUV_VERSION + ) +set(LIBUV_FOUND ${LibUV_FOUND}) + +#----------------------------------------------------------------------------- +# Provide documented result variables and targets. +if(LibUV_FOUND) + set(LibUV_INCLUDE_DIRS ${LibUV_INCLUDE_DIR}) + set(LibUV_LIBRARIES ${LibUV_LIBRARY}) + if(NOT TARGET LibUV::LibUV) + add_library(LibUV::LibUV UNKNOWN IMPORTED) + set_target_properties(LibUV::LibUV PROPERTIES + IMPORTED_LOCATION "${LibUV_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${LibUV_INCLUDE_DIRS}" + ) + endif() +endif() diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index c119cfd..6494650 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1375,6 +1375,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release add_subdirectory(FindJsonCpp) endif() + if(CMake_TEST_FindLibUV) + add_subdirectory(FindLibUV) + endif() + if(CMake_TEST_FindLTTngUST) add_subdirectory(FindLTTngUST) endif() diff --git a/Tests/FindLibUV/CMakeLists.txt b/Tests/FindLibUV/CMakeLists.txt new file mode 100644 index 0000000..08aa958 --- /dev/null +++ b/Tests/FindLibUV/CMakeLists.txt @@ -0,0 +1,10 @@ +add_test(NAME FindLibUV.Test COMMAND + ${CMAKE_CTEST_COMMAND} -C $ + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindLibUV/Test" + "${CMake_BINARY_DIR}/Tests/FindLibUV/Test" + ${build_generator_args} + --build-project TestFindLibUV + --build-options ${build_options} + --test-command ${CMAKE_CTEST_COMMAND} -V -C $ + ) diff --git a/Tests/FindLibUV/Test/CMakeLists.txt b/Tests/FindLibUV/Test/CMakeLists.txt new file mode 100644 index 0000000..257ddf3 --- /dev/null +++ b/Tests/FindLibUV/Test/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.6) +project(TestFindLibUV C) +include(CTest) + +# CMake does not actually provide FindLibUV publicly. +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../Source/Modules) + +find_package(LibUV REQUIRED) + +add_executable(test_libuv_tgt main.c) +target_link_libraries(test_libuv_tgt LibUV::LibUV) +add_test(NAME test_libuv_tgt COMMAND test_libuv_tgt) + +add_executable(test_libuv_var main.c) +target_include_directories(test_libuv_var PRIVATE ${LibUV_INCLUDE_DIRS}) +target_link_libraries(test_libuv_var PRIVATE ${LibUV_LIBRARIES}) +add_test(NAME test_libuv_var COMMAND test_libuv_var) diff --git a/Tests/FindLibUV/Test/main.c b/Tests/FindLibUV/Test/main.c new file mode 100644 index 0000000..cbd0db3 --- /dev/null +++ b/Tests/FindLibUV/Test/main.c @@ -0,0 +1,7 @@ +#include + +int main() +{ + uv_loop_close(uv_default_loop()); + return 0; +} https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=98ca133e64258f812a2359e356b13759775a0af0 commit 98ca133e64258f812a2359e356b13759775a0af0 Author: Brad King AuthorDate: Thu Aug 25 11:36:45 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 13:52:37 2016 -0400 libuv: Avoid including macOS CoreServices header globally We only need the availability macros in `unix/internal.h`. We already include CoreServices where needed in implementation files. diff --git a/Utilities/cmlibuv/src/unix/internal.h b/Utilities/cmlibuv/src/unix/internal.h index c7b6019..2570026 100644 --- a/Utilities/cmlibuv/src/unix/internal.h +++ b/Utilities/cmlibuv/src/unix/internal.h @@ -51,10 +51,6 @@ # include #endif /* _AIX */ -#if defined(__APPLE__) && !TARGET_OS_IPHONE -# include -#endif - #if defined(__ANDROID__) int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); # ifdef pthread_sigmask @@ -272,6 +268,7 @@ int uv__make_socketpair(int fds[2], int flags); int uv__make_pipe(int fds[2], int flags); #if defined(__APPLE__) +#include int uv__fsevents_init(uv_fs_event_t* handle); int uv__fsevents_close(uv_fs_event_t* handle); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=33a62bb0e07dbb345fffff0387a34ef2305ab2fc commit 33a62bb0e07dbb345fffff0387a34ef2305ab2fc Author: Brad King AuthorDate: Wed Aug 24 15:11:47 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 13:52:37 2016 -0400 libuv: Always include our own header first diff --git a/Utilities/cmlibuv/src/inet.c b/Utilities/cmlibuv/src/inet.c index da63a68..7c75e43 100644 --- a/Utilities/cmlibuv/src/inet.c +++ b/Utilities/cmlibuv/src/inet.c @@ -15,6 +15,9 @@ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "uv.h" +#include "uv-common.h" + #include #include @@ -24,9 +27,6 @@ # include #endif -#include "uv.h" -#include "uv-common.h" - #define UV__INET_ADDRSTRLEN 16 #define UV__INET6_ADDRSTRLEN 46 diff --git a/Utilities/cmlibuv/src/unix/getnameinfo.c b/Utilities/cmlibuv/src/unix/getnameinfo.c index daa798a..b2879d6 100644 --- a/Utilities/cmlibuv/src/unix/getnameinfo.c +++ b/Utilities/cmlibuv/src/unix/getnameinfo.c @@ -19,14 +19,14 @@ * IN THE SOFTWARE. */ +#include "uv.h" +#include "internal.h" + #include #include #include #include -#include "uv.h" -#include "internal.h" - static void uv__getnameinfo_work(struct uv__work* w) { uv_getnameinfo_t* req; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=04abc90dfdc88b3759829a27f95fd8bb35727c10 commit 04abc90dfdc88b3759829a27f95fd8bb35727c10 Author: Brad King AuthorDate: Wed Aug 24 11:20:46 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 13:52:37 2016 -0400 libuv: Conditionally declare Windows APIs for VS 2008 and below diff --git a/Utilities/cmlibuv/include/uv-win.h b/Utilities/cmlibuv/include/uv-win.h index e8b9b15..89ee09a 100644 --- a/Utilities/cmlibuv/include/uv-win.h +++ b/Utilities/cmlibuv/include/uv-win.h @@ -99,23 +99,34 @@ typedef struct pollfd { # define WSAID_ACCEPTEX \ {0xb5367df1, 0xcbac, 0x11cf, \ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} +#endif +#ifndef WSAID_CONNECTEX # define WSAID_CONNECTEX \ {0x25a207b9, 0xddf3, 0x4660, \ {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}} +#endif +#ifndef WSAID_GETACCEPTEXSOCKADDRS # define WSAID_GETACCEPTEXSOCKADDRS \ {0xb5367df2, 0xcbac, 0x11cf, \ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} +#endif +#ifndef WSAID_DISCONNECTEX # define WSAID_DISCONNECTEX \ {0x7fda2e11, 0x8630, 0x436f, \ {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}} +#endif +#ifndef WSAID_TRANSMITFILE # define WSAID_TRANSMITFILE \ {0xb5367df0, 0xcbac, 0x11cf, \ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} +#endif +#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) \ + || (defined(_MSC_VER) && _MSC_VER < 1500) typedef BOOL (PASCAL *LPFN_ACCEPTEX) (SOCKET sListenSocket, SOCKET sAcceptSocket, diff --git a/Utilities/cmlibuv/src/win/winapi.h b/Utilities/cmlibuv/src/win/winapi.h index 341fcd0..597a93d 100644 --- a/Utilities/cmlibuv/src/win/winapi.h +++ b/Utilities/cmlibuv/src/win/winapi.h @@ -4118,6 +4118,14 @@ typedef const UNICODE_STRING *PCUNICODE_STRING; # define DEVICE_TYPE DWORD #endif +#ifndef VOLUME_NAME_DOS +# define VOLUME_NAME_DOS 0x0 +#endif + +#ifndef MAPVK_VK_TO_VSC +# define MAPVK_VK_TO_VSC (0) +#endif + /* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does * not. */ @@ -4583,7 +4591,8 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile) # define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 #endif -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) \ + || (defined(_MSC_VER) && _MSC_VER < 1500) typedef struct _OVERLAPPED_ENTRY { ULONG_PTR lpCompletionKey; LPOVERLAPPED lpOverlapped; diff --git a/Utilities/cmlibuv/src/win/winsock.h b/Utilities/cmlibuv/src/win/winsock.h index 7c007ab..3115fe3 100644 --- a/Utilities/cmlibuv/src/win/winsock.h +++ b/Utilities/cmlibuv/src/win/winsock.h @@ -146,7 +146,8 @@ typedef struct _AFD_RECV_INFO { #define IOCTL_AFD_POLL \ _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED) -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) \ + || (defined(_MSC_VER) && _MSC_VER < 1500) typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP { /* FIXME: __C89_NAMELESS was removed */ /* __C89_NAMELESS */ union { https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b19a5e3ebc1c53fb1c4b7c2881e2ef0ca57ff60f commit b19a5e3ebc1c53fb1c4b7c2881e2ef0ca57ff60f Author: Brad King AuthorDate: Wed Aug 24 11:18:25 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 13:52:37 2016 -0400 libuv: Fix anonymous union syntax diff --git a/Utilities/cmlibuv/src/win/winapi.h b/Utilities/cmlibuv/src/win/winapi.h index 16d9365..341fcd0 100644 --- a/Utilities/cmlibuv/src/win/winapi.h +++ b/Utilities/cmlibuv/src/win/winapi.h @@ -4145,7 +4145,7 @@ typedef const UNICODE_STRING *PCUNICODE_STRING; struct { UCHAR DataBuffer[1]; } GenericReparseBuffer; - } DUMMYUNIONNAME; + }; } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; #endif @@ -4153,7 +4153,7 @@ typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; PVOID Pointer; - } DUMMYUNIONNAME; + }; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=362e42d39e9b451b7e8aef05644bc26ffe964abf commit 362e42d39e9b451b7e8aef05644bc26ffe964abf Author: Brad King AuthorDate: Wed Aug 24 11:08:29 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 13:52:37 2016 -0400 libuv: Fix Windows API function typedef syntax diff --git a/Utilities/cmlibuv/include/uv-win.h b/Utilities/cmlibuv/include/uv-win.h index a75dba8..e8b9b15 100644 --- a/Utilities/cmlibuv/include/uv-win.h +++ b/Utilities/cmlibuv/include/uv-win.h @@ -116,7 +116,7 @@ typedef struct pollfd { {0xb5367df0, 0xcbac, 0x11cf, \ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} - typedef BOOL PASCAL (*LPFN_ACCEPTEX) + typedef BOOL (PASCAL *LPFN_ACCEPTEX) (SOCKET sListenSocket, SOCKET sAcceptSocket, PVOID lpOutputBuffer, @@ -126,7 +126,7 @@ typedef struct pollfd { LPDWORD lpdwBytesReceived, LPOVERLAPPED lpOverlapped); - typedef BOOL PASCAL (*LPFN_CONNECTEX) + typedef BOOL (PASCAL *LPFN_CONNECTEX) (SOCKET s, const struct sockaddr* name, int namelen, @@ -135,7 +135,7 @@ typedef struct pollfd { LPDWORD lpdwBytesSent, LPOVERLAPPED lpOverlapped); - typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS) + typedef void (PASCAL *LPFN_GETACCEPTEXSOCKADDRS) (PVOID lpOutputBuffer, DWORD dwReceiveDataLength, DWORD dwLocalAddressLength, @@ -145,13 +145,13 @@ typedef struct pollfd { LPSOCKADDR* RemoteSockaddr, LPINT RemoteSockaddrLength); - typedef BOOL PASCAL (*LPFN_DISCONNECTEX) + typedef BOOL (PASCAL *LPFN_DISCONNECTEX) (SOCKET hSocket, LPOVERLAPPED lpOverlapped, DWORD dwFlags, DWORD reserved); - typedef BOOL PASCAL (*LPFN_TRANSMITFILE) + typedef BOOL (PASCAL *LPFN_TRANSMITFILE) (SOCKET hSocket, HANDLE hFile, DWORD nNumberOfBytesToWrite, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d08a3b2ea3f9ea4b254a9bd70d66e05e60c82814 commit d08a3b2ea3f9ea4b254a9bd70d66e05e60c82814 Author: Brad King AuthorDate: Wed Aug 24 14:48:37 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 13:52:37 2016 -0400 libuv: Install LICENSE file with CMake documentation When we install using the bundled libuv source, notify users of its license terms. diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt index 55bdbeb..599f3f7 100644 --- a/Utilities/cmlibuv/CMakeLists.txt +++ b/Utilities/cmlibuv/CMakeLists.txt @@ -223,3 +223,5 @@ include_directories( add_library(cmlibuv STATIC ${uv_sources}) target_link_libraries(cmlibuv ${uv_libraries}) set_property(TARGET cmlibuv PROPERTY COMPILE_DEFINITIONS ${uv_defines}) + +install(FILES LICENSE DESTINATION ${CMAKE_DOC_DIR}/cmlibuv) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=98aabffff41aeef2b549c3a4e2cd0962c48d59bf commit 98aabffff41aeef2b549c3a4e2cd0962c48d59bf Author: Brad King AuthorDate: Wed Aug 17 10:16:57 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 13:52:37 2016 -0400 libuv: Disable warnings to avoid changing 3rd party code Add '-w' or equivalent flag on compilers supporting it. Tell MSVC to use its lowest warning level inside libuv sources. diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt index 7f2d587..55bdbeb 100644 --- a/Utilities/cmlibuv/CMakeLists.txt +++ b/Utilities/cmlibuv/CMakeLists.txt @@ -1,5 +1,13 @@ project(libuv C) +# Disable warnings to avoid changing 3rd party code. +if(CMAKE_CXX_COMPILER_ID MATCHES + "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w") +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "PathScale") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -woffall") +endif() + find_package(Threads) set(uv_libraries ${CMAKE_THREAD_LIBS_INIT}) diff --git a/Utilities/cmlibuv/src/win/internal.h b/Utilities/cmlibuv/src/win/internal.h index b8cfde9..8a17e94 100644 --- a/Utilities/cmlibuv/src/win/internal.h +++ b/Utilities/cmlibuv/src/win/internal.h @@ -22,6 +22,10 @@ #ifndef UV_WIN_INTERNAL_H_ #define UV_WIN_INTERNAL_H_ +#if defined(_MSC_VER) +# pragma warning(push,1) +#endif + #include "uv.h" #include "../uv-common.h" https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=738b10e44733c713961c3c54d35134434ee010cb commit 738b10e44733c713961c3c54d35134434ee010cb Author: Brad King AuthorDate: Tue Aug 16 16:26:39 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 13:52:37 2016 -0400 libuv: Build the library within CMake Take logic from upstream `Makefile.am` and `configure.ac` to build libuv sources. Update `uv.h` to include KWSys Large File Support configuration so that consistent stream libraries are used (on AIX with XL). Add a `cm_uv.h` header to include the CMake-provided copy of the `uv.h` header from CMake sources. diff --git a/CMakeLists.txt b/CMakeLists.txt index 3aef619..958beb6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -464,6 +464,19 @@ macro (CMAKE_BUILD_UTILITIES) endif() #--------------------------------------------------------------------- + # Build libuv library. + if(NOT DEFINED CMAKE_USE_LIBUV) + set(CMAKE_USE_LIBUV 1) + endif() + if(CMAKE_USE_LIBUV) + set(CMAKE_LIBUV_LIBRARIES cmlibuv) + add_subdirectory(Utilities/cmlibuv) + CMAKE_SET_TARGET_FOLDER(cmlibuv "Utilities/3rdParty") + else() + set(CMAKE_LIBUV_LIBRARIES) + endif() + + #--------------------------------------------------------------------- # Build XMLRPC library for CMake and CTest. if(CTEST_USE_XMLRPC) find_package(XMLRPC QUIET REQUIRED libwww-client) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 3b94df7..8c74f60 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -582,6 +582,7 @@ target_link_libraries(CMakeLib cmsys ${CMAKE_TAR_LIBRARIES} ${CMAKE_COMPRESS_LIBRARIES} ${CMAKE_CURL_LIBRARIES} ${CMAKE_JSONCPP_LIBRARIES} + ${CMAKE_LIBUV_LIBRARIES} ${CMake_KWIML_LIBRARIES} ) diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in index 7e48b2d..cb671dd 100644 --- a/Source/cmConfigure.cmake.h.in +++ b/Source/cmConfigure.cmake.h.in @@ -28,6 +28,7 @@ #cmakedefine HAVE_UNSETENV #cmakedefine CMAKE_USE_ELF_PARSER #cmakedefine CMAKE_USE_MACH_PARSER +#cmakedefine CMAKE_USE_LIBUV #cmakedefine CMAKE_ENCODING_UTF8 #cmakedefine CMake_HAVE_CXX_NULLPTR #cmakedefine CMake_HAVE_CXX_OVERRIDE diff --git a/Utilities/cm_uv.h b/Utilities/cm_uv.h new file mode 100644 index 0000000..63ff597 --- /dev/null +++ b/Utilities/cm_uv.h @@ -0,0 +1,17 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2016 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cm_uv_h +#define cm_uv_h + +#include + +#endif diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt new file mode 100644 index 0000000..7f2d587 --- /dev/null +++ b/Utilities/cmlibuv/CMakeLists.txt @@ -0,0 +1,217 @@ +project(libuv C) + +find_package(Threads) + +set(uv_libraries ${CMAKE_THREAD_LIBS_INIT}) +set(uv_includes include src) +set(uv_headers + include/uv.h + include/uv-errno.h + include/uv-threadpool.h + include/uv-version.h + ) +set(uv_sources + src/fs-poll.c + src/heap-inl.h + src/inet.c + src/queue.h + src/threadpool.c + src/uv-common.c + src/uv-common.h + src/version.c + ) +if(WIN32) + list(APPEND uv_libraries + ws2_32 + psapi + iphlpapi + shell32 + userenv + ) + list(APPEND uv_includes + src/win + ) + list(APPEND uv_defines + WIN32_LEAN_AND_MEAN + _WIN32_WINNT=0x0600 + ) + list(APPEND uv_headers + include/uv-win.h + include/tree.h + ) + list(APPEND uv_sources + src/win/async.c + src/win/atomicops-inl.h + src/win/core.c + src/win/detect-wakeup.c + src/win/dl.c + src/win/error.c + src/win/fs-event.c + src/win/fs.c + src/win/getaddrinfo.c + src/win/getnameinfo.c + src/win/handle.c + src/win/handle-inl.h + src/win/internal.h + src/win/loop-watcher.c + src/win/pipe.c + src/win/poll.c + src/win/process-stdio.c + src/win/process.c + src/win/req.c + src/win/req-inl.h + src/win/signal.c + src/win/snprintf.c + src/win/stream.c + src/win/stream-inl.h + src/win/tcp.c + src/win/thread.c + src/win/timer.c + src/win/tty.c + src/win/udp.c + src/win/util.c + src/win/winapi.c + src/win/winapi.h + src/win/winsock.c + src/win/winsock.h + ) +else() + list(APPEND uv_includes + src/unix + ) + list(APPEND uv_headers + include/uv-unix.h + ) + list(APPEND uv_sources + src/unix/async.c + src/unix/atomic-ops.h + src/unix/core.c + src/unix/dl.c + src/unix/fs.c + src/unix/getaddrinfo.c + src/unix/getnameinfo.c + src/unix/internal.h + src/unix/loop-watcher.c + src/unix/loop.c + src/unix/pipe.c + src/unix/poll.c + src/unix/process.c + src/unix/signal.c + src/unix/spinlock.h + src/unix/stream.c + src/unix/tcp.c + src/unix/thread.c + src/unix/timer.c + src/unix/tty.c + src/unix/udp.c + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "AIX") + list(APPEND uv_libraries + perfstat + ) + list(APPEND uv_headers + include/uv-aix.h + ) + list(APPEND uv_defines + _ALL_SOURCE + _XOPEN_SOURCE=500 + _LINUX_SOURCE_COMPAT + _THREAD_SAFE + ) + list(APPEND uv_sources + src/unix/aix.c + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + list(APPEND uv_headers + include/uv-darwin.h + include/pthread-barrier.h + ) + list(APPEND uv_defines + _DARWIN_USE_64_BIT_INODE=1 + _DARWIN_UNLIMITED_SELECT=1 + ) + list(APPEND uv_sources + src/unix/darwin.c + src/unix/darwin-proctitle.c + src/unix/fsevents.c + src/unix/kqueue.c + src/unix/proctitle.c + src/unix/pthread-barrier.c + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + list(APPEND uv_libraries dl rt) + list(APPEND uv_headers + include/uv-linux.h + ) + list(APPEND uv_defines _GNU_SOURCE) + list(APPEND uv_sources + src/unix/linux-core.c + src/unix/linux-inotify.c + src/unix/linux-syscalls.c + src/unix/linux-syscalls.h + src/unix/proctitle.c + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + list(APPEND uv_headers + include/uv-bsd.h + ) + list(APPEND uv_sources + src/unix/freebsd.c + src/unix/kqueue.c + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") + list(APPEND uv_headers + include/uv-bsd.h + ) + list(APPEND uv_sources + src/unix/netbsd.c + src/unix/kqueue.c + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + list(APPEND uv_headers + include/uv-bsd.h + ) + list(APPEND uv_sources + src/unix/openbsd.c + src/unix/kqueue.c + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "SunOS") + list(APPEND uv_libraries + kstat + nsl + sendfile + socket + ) + list(APPEND uv_headers + include/uv-sunos.h + ) + list(APPEND uv_defines + __EXTENSIONS__ + _XOPEN_SOURCE=500 + ) + list(APPEND uv_sources + src/unix/sunos.c + ) +endif() + +include_directories( + ${uv_includes} + ${KWSYS_HEADER_ROOT} + ) +add_library(cmlibuv STATIC ${uv_sources}) +target_link_libraries(cmlibuv ${uv_libraries}) +set_property(TARGET cmlibuv PROPERTY COMPILE_DEFINITIONS ${uv_defines}) diff --git a/Utilities/cmlibuv/include/uv.h b/Utilities/cmlibuv/include/uv.h index baa0b28..e3e20dc 100644 --- a/Utilities/cmlibuv/include/uv.h +++ b/Utilities/cmlibuv/include/uv.h @@ -23,6 +23,10 @@ #ifndef UV_H #define UV_H + +/* Include KWSys Large File Support configuration. */ +#include + #ifdef __cplusplus extern "C" { #endif https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=dbc3fb0a90ef09e1b1b31da0a26a14bb1f804f3d commit dbc3fb0a90ef09e1b1b31da0a26a14bb1f804f3d Merge: 0cb012e f0df3d4 Author: Brad King AuthorDate: Thu Aug 25 13:51:00 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 13:51:00 2016 -0400 Merge branch 'upstream-libuv' into import-libuv * upstream-libuv: libuv 2016-08-25 (9e641d25) diff --cc Utilities/cmlibuv/.gitattributes index 0000000,562b12e..562b12e mode 000000,100644..100644 --- a/Utilities/cmlibuv/.gitattributes +++ b/Utilities/cmlibuv/.gitattributes diff --cc Utilities/cmlibuv/LICENSE index 0000000,41ba44c..41ba44c mode 000000,100644..100644 --- a/Utilities/cmlibuv/LICENSE +++ b/Utilities/cmlibuv/LICENSE diff --cc Utilities/cmlibuv/include/android-ifaddrs.h index 0000000,9cd19fe..9cd19fe mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/android-ifaddrs.h +++ b/Utilities/cmlibuv/include/android-ifaddrs.h diff --cc Utilities/cmlibuv/include/pthread-barrier.h index 0000000,68468ad..68468ad mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/pthread-barrier.h +++ b/Utilities/cmlibuv/include/pthread-barrier.h diff --cc Utilities/cmlibuv/include/stdint-msvc2008.h index 0000000,d02608a..d02608a mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/stdint-msvc2008.h +++ b/Utilities/cmlibuv/include/stdint-msvc2008.h diff --cc Utilities/cmlibuv/include/tree.h index 0000000,f936416..f936416 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/tree.h +++ b/Utilities/cmlibuv/include/tree.h diff --cc Utilities/cmlibuv/include/uv-aix.h index 0000000,7dc992f..7dc992f mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-aix.h +++ b/Utilities/cmlibuv/include/uv-aix.h diff --cc Utilities/cmlibuv/include/uv-bsd.h index 0000000,2d72b3d..2d72b3d mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-bsd.h +++ b/Utilities/cmlibuv/include/uv-bsd.h diff --cc Utilities/cmlibuv/include/uv-darwin.h index 0000000,d226415..d226415 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-darwin.h +++ b/Utilities/cmlibuv/include/uv-darwin.h diff --cc Utilities/cmlibuv/include/uv-errno.h index 0000000,f137151..f137151 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-errno.h +++ b/Utilities/cmlibuv/include/uv-errno.h diff --cc Utilities/cmlibuv/include/uv-linux.h index 0000000,9b38405..9b38405 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-linux.h +++ b/Utilities/cmlibuv/include/uv-linux.h diff --cc Utilities/cmlibuv/include/uv-os390.h index 0000000,b0b068f..b0b068f mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-os390.h +++ b/Utilities/cmlibuv/include/uv-os390.h diff --cc Utilities/cmlibuv/include/uv-sunos.h index 0000000,0421664..0421664 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-sunos.h +++ b/Utilities/cmlibuv/include/uv-sunos.h diff --cc Utilities/cmlibuv/include/uv-threadpool.h index 0000000,9708ebd..9708ebd mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-threadpool.h +++ b/Utilities/cmlibuv/include/uv-threadpool.h diff --cc Utilities/cmlibuv/include/uv-unix.h index 0000000,bca2714..bca2714 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-unix.h +++ b/Utilities/cmlibuv/include/uv-unix.h diff --cc Utilities/cmlibuv/include/uv-version.h index 0000000,3cb9b5f..3cb9b5f mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-version.h +++ b/Utilities/cmlibuv/include/uv-version.h diff --cc Utilities/cmlibuv/include/uv-win.h index 0000000,a75dba8..a75dba8 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-win.h +++ b/Utilities/cmlibuv/include/uv-win.h diff --cc Utilities/cmlibuv/include/uv.h index 0000000,baa0b28..baa0b28 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv.h +++ b/Utilities/cmlibuv/include/uv.h diff --cc Utilities/cmlibuv/src/fs-poll.c index 0000000,ee73d5a..ee73d5a mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/fs-poll.c +++ b/Utilities/cmlibuv/src/fs-poll.c diff --cc Utilities/cmlibuv/src/heap-inl.h index 0000000,1e2ed60..1e2ed60 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/heap-inl.h +++ b/Utilities/cmlibuv/src/heap-inl.h diff --cc Utilities/cmlibuv/src/inet.c index 0000000,da63a68..da63a68 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/inet.c +++ b/Utilities/cmlibuv/src/inet.c diff --cc Utilities/cmlibuv/src/queue.h index 0000000,ff3540a..ff3540a mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/queue.h +++ b/Utilities/cmlibuv/src/queue.h diff --cc Utilities/cmlibuv/src/threadpool.c index 0000000,2c5152b..2c5152b mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/threadpool.c +++ b/Utilities/cmlibuv/src/threadpool.c diff --cc Utilities/cmlibuv/src/unix/aix.c index 0000000,652cd98..652cd98 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/aix.c +++ b/Utilities/cmlibuv/src/unix/aix.c diff --cc Utilities/cmlibuv/src/unix/android-ifaddrs.c index 0000000,30f681b..30f681b mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/android-ifaddrs.c +++ b/Utilities/cmlibuv/src/unix/android-ifaddrs.c diff --cc Utilities/cmlibuv/src/unix/async.c index 0000000,393cdeb..393cdeb mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/async.c +++ b/Utilities/cmlibuv/src/unix/async.c diff --cc Utilities/cmlibuv/src/unix/atomic-ops.h index 0000000,815e355..815e355 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/atomic-ops.h +++ b/Utilities/cmlibuv/src/unix/atomic-ops.h diff --cc Utilities/cmlibuv/src/unix/core.c index 0000000,d88fc1d..d88fc1d mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/core.c +++ b/Utilities/cmlibuv/src/unix/core.c diff --cc Utilities/cmlibuv/src/unix/darwin-proctitle.c index 0000000,1142311..1142311 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/darwin-proctitle.c +++ b/Utilities/cmlibuv/src/unix/darwin-proctitle.c diff --cc Utilities/cmlibuv/src/unix/darwin.c index 0000000,cf95da2..cf95da2 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/darwin.c +++ b/Utilities/cmlibuv/src/unix/darwin.c diff --cc Utilities/cmlibuv/src/unix/dl.c index 0000000,fc1c052..fc1c052 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/dl.c +++ b/Utilities/cmlibuv/src/unix/dl.c diff --cc Utilities/cmlibuv/src/unix/freebsd.c index 0000000,cba44a3..cba44a3 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/freebsd.c +++ b/Utilities/cmlibuv/src/unix/freebsd.c diff --cc Utilities/cmlibuv/src/unix/fs.c index 0000000,216ef97..216ef97 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/fs.c +++ b/Utilities/cmlibuv/src/unix/fs.c diff --cc Utilities/cmlibuv/src/unix/fsevents.c index 0000000,d331a13..d331a13 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/fsevents.c +++ b/Utilities/cmlibuv/src/unix/fsevents.c diff --cc Utilities/cmlibuv/src/unix/getaddrinfo.c index 0000000,2049aea..2049aea mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/getaddrinfo.c +++ b/Utilities/cmlibuv/src/unix/getaddrinfo.c diff --cc Utilities/cmlibuv/src/unix/getnameinfo.c index 0000000,daa798a..daa798a mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/getnameinfo.c +++ b/Utilities/cmlibuv/src/unix/getnameinfo.c diff --cc Utilities/cmlibuv/src/unix/internal.h index 0000000,c7b6019..c7b6019 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/internal.h +++ b/Utilities/cmlibuv/src/unix/internal.h diff --cc Utilities/cmlibuv/src/unix/kqueue.c index 0000000,fffd462..fffd462 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/kqueue.c +++ b/Utilities/cmlibuv/src/unix/kqueue.c diff --cc Utilities/cmlibuv/src/unix/linux-core.c index 0000000,58dd813..58dd813 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/linux-core.c +++ b/Utilities/cmlibuv/src/unix/linux-core.c diff --cc Utilities/cmlibuv/src/unix/linux-inotify.c index 0000000,4708c05..4708c05 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/linux-inotify.c +++ b/Utilities/cmlibuv/src/unix/linux-inotify.c diff --cc Utilities/cmlibuv/src/unix/linux-syscalls.c index 0000000,89998de..89998de mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/linux-syscalls.c +++ b/Utilities/cmlibuv/src/unix/linux-syscalls.c diff --cc Utilities/cmlibuv/src/unix/linux-syscalls.h index 0000000,4c095e9..4c095e9 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/linux-syscalls.h +++ b/Utilities/cmlibuv/src/unix/linux-syscalls.h diff --cc Utilities/cmlibuv/src/unix/loop-watcher.c index 0000000,340bb0d..340bb0d mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/loop-watcher.c +++ b/Utilities/cmlibuv/src/unix/loop-watcher.c diff --cc Utilities/cmlibuv/src/unix/loop.c index 0000000,bd63c2f..bd63c2f mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/loop.c +++ b/Utilities/cmlibuv/src/unix/loop.c diff --cc Utilities/cmlibuv/src/unix/netbsd.c index 0000000,4a9e6cb..4a9e6cb mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/netbsd.c +++ b/Utilities/cmlibuv/src/unix/netbsd.c diff --cc Utilities/cmlibuv/src/unix/openbsd.c index 0000000,909288c..909288c mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/openbsd.c +++ b/Utilities/cmlibuv/src/unix/openbsd.c diff --cc Utilities/cmlibuv/src/unix/os390.c index 0000000,bcdbc4b..bcdbc4b mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/os390.c +++ b/Utilities/cmlibuv/src/unix/os390.c diff --cc Utilities/cmlibuv/src/unix/pipe.c index 0000000,b73994c..b73994c mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/pipe.c +++ b/Utilities/cmlibuv/src/unix/pipe.c diff --cc Utilities/cmlibuv/src/unix/poll.c index 0000000,4c0d478..4c0d478 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/poll.c +++ b/Utilities/cmlibuv/src/unix/poll.c diff --cc Utilities/cmlibuv/src/unix/process.c index 0000000,45f5b45..45f5b45 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/process.c +++ b/Utilities/cmlibuv/src/unix/process.c diff --cc Utilities/cmlibuv/src/unix/proctitle.c index 0000000,08d875f..08d875f mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/proctitle.c +++ b/Utilities/cmlibuv/src/unix/proctitle.c diff --cc Utilities/cmlibuv/src/unix/pthread-barrier.c index 0000000,f57bf25..f57bf25 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/pthread-barrier.c +++ b/Utilities/cmlibuv/src/unix/pthread-barrier.c diff --cc Utilities/cmlibuv/src/unix/pthread-fixes.c index 0000000,fb17995..fb17995 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/pthread-fixes.c +++ b/Utilities/cmlibuv/src/unix/pthread-fixes.c diff --cc Utilities/cmlibuv/src/unix/signal.c index 0000000,d82b9b7..d82b9b7 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/signal.c +++ b/Utilities/cmlibuv/src/unix/signal.c diff --cc Utilities/cmlibuv/src/unix/spinlock.h index 0000000,a20c83c..a20c83c mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/spinlock.h +++ b/Utilities/cmlibuv/src/unix/spinlock.h diff --cc Utilities/cmlibuv/src/unix/stream.c index 0000000,d20d0bc..d20d0bc mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/stream.c +++ b/Utilities/cmlibuv/src/unix/stream.c diff --cc Utilities/cmlibuv/src/unix/sunos.c index 0000000,3e7a759..3e7a759 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/sunos.c +++ b/Utilities/cmlibuv/src/unix/sunos.c diff --cc Utilities/cmlibuv/src/unix/tcp.c index 0000000,c423dcb..c423dcb mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/tcp.c +++ b/Utilities/cmlibuv/src/unix/tcp.c diff --cc Utilities/cmlibuv/src/unix/thread.c index 0000000,52989f7..52989f7 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/thread.c +++ b/Utilities/cmlibuv/src/unix/thread.c diff --cc Utilities/cmlibuv/src/unix/timer.c index 0000000,ca3ec3d..ca3ec3d mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/timer.c +++ b/Utilities/cmlibuv/src/unix/timer.c diff --cc Utilities/cmlibuv/src/unix/tty.c index 0000000,b2d37f4..b2d37f4 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/tty.c +++ b/Utilities/cmlibuv/src/unix/tty.c diff --cc Utilities/cmlibuv/src/unix/udp.c index 0000000,1cd4925..1cd4925 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/udp.c +++ b/Utilities/cmlibuv/src/unix/udp.c diff --cc Utilities/cmlibuv/src/uv-common.c index 0000000,434a502..434a502 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/uv-common.c +++ b/Utilities/cmlibuv/src/uv-common.c diff --cc Utilities/cmlibuv/src/uv-common.h index 0000000,27902fd..27902fd mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/uv-common.h +++ b/Utilities/cmlibuv/src/uv-common.h diff --cc Utilities/cmlibuv/src/version.c index 0000000,686dedd..686dedd mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/version.c +++ b/Utilities/cmlibuv/src/version.c diff --cc Utilities/cmlibuv/src/win/async.c index 0000000,ad240ab..ad240ab mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/async.c +++ b/Utilities/cmlibuv/src/win/async.c diff --cc Utilities/cmlibuv/src/win/atomicops-inl.h index 0000000,61e0060..61e0060 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/atomicops-inl.h +++ b/Utilities/cmlibuv/src/win/atomicops-inl.h diff --cc Utilities/cmlibuv/src/win/core.c index 0000000,9d00afc..9d00afc mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/core.c +++ b/Utilities/cmlibuv/src/win/core.c diff --cc Utilities/cmlibuv/src/win/detect-wakeup.c index 0000000,a12179f..a12179f mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/detect-wakeup.c +++ b/Utilities/cmlibuv/src/win/detect-wakeup.c diff --cc Utilities/cmlibuv/src/win/dl.c index 0000000,39e400a..39e400a mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/dl.c +++ b/Utilities/cmlibuv/src/win/dl.c diff --cc Utilities/cmlibuv/src/win/error.c index 0000000,c512f35..c512f35 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/error.c +++ b/Utilities/cmlibuv/src/win/error.c diff --cc Utilities/cmlibuv/src/win/fs-event.c index 0000000,03e4adc..03e4adc mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/fs-event.c +++ b/Utilities/cmlibuv/src/win/fs-event.c diff --cc Utilities/cmlibuv/src/win/fs.c index 0000000,6a4157b..6a4157b mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/fs.c +++ b/Utilities/cmlibuv/src/win/fs.c diff --cc Utilities/cmlibuv/src/win/getaddrinfo.c index 0000000,744f8e0..744f8e0 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/getaddrinfo.c +++ b/Utilities/cmlibuv/src/win/getaddrinfo.c diff --cc Utilities/cmlibuv/src/win/getnameinfo.c index 0000000,66b64b8..66b64b8 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/getnameinfo.c +++ b/Utilities/cmlibuv/src/win/getnameinfo.c diff --cc Utilities/cmlibuv/src/win/handle-inl.h index 0000000,8d0334c..8d0334c mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/handle-inl.h +++ b/Utilities/cmlibuv/src/win/handle-inl.h diff --cc Utilities/cmlibuv/src/win/handle.c index 0000000,72b49d9..72b49d9 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/handle.c +++ b/Utilities/cmlibuv/src/win/handle.c diff --cc Utilities/cmlibuv/src/win/internal.h index 0000000,b8cfde9..b8cfde9 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/internal.h +++ b/Utilities/cmlibuv/src/win/internal.h diff --cc Utilities/cmlibuv/src/win/loop-watcher.c index 0000000,20e4509..20e4509 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/loop-watcher.c +++ b/Utilities/cmlibuv/src/win/loop-watcher.c diff --cc Utilities/cmlibuv/src/win/pipe.c index 0000000,2442be7..2442be7 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/pipe.c +++ b/Utilities/cmlibuv/src/win/pipe.c diff --cc Utilities/cmlibuv/src/win/poll.c index 0000000,d479e52..d479e52 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/poll.c +++ b/Utilities/cmlibuv/src/win/poll.c diff --cc Utilities/cmlibuv/src/win/process-stdio.c index 0000000,e3c06f5..e3c06f5 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/process-stdio.c +++ b/Utilities/cmlibuv/src/win/process-stdio.c diff --cc Utilities/cmlibuv/src/win/process.c index 0000000,855c374..855c374 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/process.c +++ b/Utilities/cmlibuv/src/win/process.c diff --cc Utilities/cmlibuv/src/win/req-inl.h index 0000000,b5e502e..b5e502e mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/req-inl.h +++ b/Utilities/cmlibuv/src/win/req-inl.h diff --cc Utilities/cmlibuv/src/win/req.c index 0000000,111cc5e..111cc5e mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/req.c +++ b/Utilities/cmlibuv/src/win/req.c diff --cc Utilities/cmlibuv/src/win/signal.c index 0000000,2c64a55..2c64a55 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/signal.c +++ b/Utilities/cmlibuv/src/win/signal.c diff --cc Utilities/cmlibuv/src/win/snprintf.c index 0000000,776c0e3..776c0e3 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/snprintf.c +++ b/Utilities/cmlibuv/src/win/snprintf.c diff --cc Utilities/cmlibuv/src/win/stream-inl.h index 0000000,b7a3c11..b7a3c11 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/stream-inl.h +++ b/Utilities/cmlibuv/src/win/stream-inl.h diff --cc Utilities/cmlibuv/src/win/stream.c index 0000000,a2466e5..a2466e5 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/stream.c +++ b/Utilities/cmlibuv/src/win/stream.c diff --cc Utilities/cmlibuv/src/win/tcp.c index 0000000,0709696..0709696 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/tcp.c +++ b/Utilities/cmlibuv/src/win/tcp.c diff --cc Utilities/cmlibuv/src/win/thread.c index 0000000,91684e9..91684e9 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/thread.c +++ b/Utilities/cmlibuv/src/win/thread.c diff --cc Utilities/cmlibuv/src/win/timer.c index 0000000,27ca771..27ca771 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/timer.c +++ b/Utilities/cmlibuv/src/win/timer.c diff --cc Utilities/cmlibuv/src/win/tty.c index 0000000,9bb7879..9bb7879 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/tty.c +++ b/Utilities/cmlibuv/src/win/tty.c diff --cc Utilities/cmlibuv/src/win/udp.c index 0000000,9bf1453..9bf1453 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/udp.c +++ b/Utilities/cmlibuv/src/win/udp.c diff --cc Utilities/cmlibuv/src/win/util.c index 0000000,4a2e501..4a2e501 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/util.c +++ b/Utilities/cmlibuv/src/win/util.c diff --cc Utilities/cmlibuv/src/win/winapi.c index 0000000,1fa179b..1fa179b mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/winapi.c +++ b/Utilities/cmlibuv/src/win/winapi.c diff --cc Utilities/cmlibuv/src/win/winapi.h index 0000000,16d9365..16d9365 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/winapi.h +++ b/Utilities/cmlibuv/src/win/winapi.h diff --cc Utilities/cmlibuv/src/win/winsock.c index 0000000,d2e667e..d2e667e mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/winsock.c +++ b/Utilities/cmlibuv/src/win/winsock.c diff --cc Utilities/cmlibuv/src/win/winsock.h index 0000000,7c007ab..7c007ab mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/winsock.h +++ b/Utilities/cmlibuv/src/win/winsock.h https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f0df3d4a123545d4e0d0c1dddb7f0b524efb403d commit f0df3d4a123545d4e0d0c1dddb7f0b524efb403d Author: libuv upstream AuthorDate: Thu Aug 25 13:04:04 2016 +0100 Commit: Brad King CommitDate: Thu Aug 25 13:50:58 2016 -0400 libuv 2016-08-25 (9e641d25) Code extracted from: https://github.com/libuv/libuv.git at commit 9e641d251fa48c74faabd2b5506f8d972bdb93f3 (v1.x). diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..562b12e --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* -whitespace diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..41ba44c --- /dev/null +++ b/LICENSE @@ -0,0 +1,70 @@ +libuv is licensed for use as follows: + +==== +Copyright (c) 2015-present libuv project contributors. + +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. +==== + +This license applies to parts of libuv originating from the +https://github.com/joyent/libuv repository: + +==== + +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +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. + +==== + +This license applies to all parts of libuv that are not externally +maintained libraries. + +The externally maintained libraries used by libuv are: + + - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license. + + - inet_pton and inet_ntop implementations, contained in src/inet.c, are + copyright the Internet Systems Consortium, Inc., and licensed under the ISC + license. + + - stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three + clause BSD license. + + - pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile + Communications AB. Three clause BSD license. + + - android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design + Inc, Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement + n? 289016). Three clause BSD license. diff --git a/include/android-ifaddrs.h b/include/android-ifaddrs.h new file mode 100644 index 0000000..9cd19fe --- /dev/null +++ b/include/android-ifaddrs.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1995, 1999 + * Berkeley Software Design, 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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. + * + * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp + */ + +#ifndef _IFADDRS_H_ +#define _IFADDRS_H_ + +struct ifaddrs { + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + struct sockaddr *ifa_dstaddr; + void *ifa_data; +}; + +/* + * This may have been defined in . Note that if is + * to be included it must be included before this header file. + */ +#ifndef ifa_broadaddr +#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ +#endif + +#include + +__BEGIN_DECLS +extern int getifaddrs(struct ifaddrs **ifap); +extern void freeifaddrs(struct ifaddrs *ifa); +__END_DECLS + +#endif diff --git a/include/pthread-barrier.h b/include/pthread-barrier.h new file mode 100644 index 0000000..68468ad --- /dev/null +++ b/include/pthread-barrier.h @@ -0,0 +1,66 @@ +/* +Copyright (c) 2016, Kari Tristan Helgason + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _UV_PTHREAD_BARRIER_ +#define _UV_PTHREAD_BARRIER_ +#include +#include +#include /* sem_t */ + +#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 + +/* + * To maintain ABI compatibility with + * libuv v1.x struct is padded according + * to target platform + */ +#if defined(__ANDROID__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + sizeof(pthread_cond_t) + \ + sizeof(unsigned int) - \ + sizeof(void *) +#elif defined(__APPLE__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + 2 * sizeof(sem_t) + \ + 2 * sizeof(unsigned int) - \ + sizeof(void *) +#elif defined(__MVS__) +# define UV_BARRIER_STRUCT_PADDING 0 +#endif + +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; + unsigned threshold; + unsigned in; + unsigned out; +} _uv_barrier; + +typedef struct { + _uv_barrier* b; + char _pad[UV_BARRIER_STRUCT_PADDING]; +} pthread_barrier_t; + +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count); + +int pthread_barrier_wait(pthread_barrier_t* barrier); +int pthread_barrier_destroy(pthread_barrier_t *barrier); + +#endif /* _UV_PTHREAD_BARRIER_ */ diff --git a/include/stdint-msvc2008.h b/include/stdint-msvc2008.h new file mode 100644 index 0000000..d02608a --- /dev/null +++ b/include/stdint-msvc2008.h @@ -0,0 +1,247 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. 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. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] diff --git a/include/tree.h b/include/tree.h new file mode 100644 index 0000000..f936416 --- /dev/null +++ b/include/tree.h @@ -0,0 +1,768 @@ +/*- + * Copyright 2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef UV_TREE_H_ +#define UV_TREE_H_ + +#ifndef UV__UNUSED +# if __GNUC__ +# define UV__UNUSED __attribute__((unused)) +# else +# define UV__UNUSED +# endif +#endif + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type) \ +struct name { \ + struct type *sph_root; /* root of the tree */ \ +} + +#define SPLAY_INITIALIZER(root) \ + { NULL } + +#define SPLAY_INIT(root) do { \ + (root)->sph_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ENTRY(type) \ +struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ +} + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKLEFT(head, tmp, field) do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKRIGHT(head, tmp, field) do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ +void name##_SPLAY(struct name *, struct type *); \ +void name##_SPLAY_MINMAX(struct name *, int); \ +struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ +struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ +/* Finds the node with the same key as elm */ \ +static __inline struct type * \ +name##_SPLAY_FIND(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) \ + return(NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_NEXT(struct name *head, struct type *elm) \ +{ \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_MIN_MAX(struct name *head, int val) \ +{ \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ +} + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ +struct type * \ +name##_SPLAY_INSERT(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if(__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ +} \ + \ +struct type * \ +name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ +} \ + \ +void \ +name##_SPLAY(struct name *head, struct type *elm) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ + \ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \ + __left = __right = &__node; \ + \ + while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0){ \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} \ + \ +/* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ +void name##_SPLAY_MINMAX(struct name *head, int __comp) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + \ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \ + __left = __right = &__node; \ + \ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-black tree */ +#define RB_HEAD(name, type) \ +struct name { \ + struct type *rbh_root; /* root of the tree */ \ +} + +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#define RB_SET_BLACKRED(black, red, field) do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) do {} while (0) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) +#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp, UV__UNUSED static) +#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ +attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ +attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ +attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ +attr struct type *name##_RB_INSERT(struct name *, struct type *); \ +attr struct type *name##_RB_FIND(struct name *, struct type *); \ +attr struct type *name##_RB_NFIND(struct name *, struct type *); \ +attr struct type *name##_RB_NEXT(struct type *); \ +attr struct type *name##_RB_PREV(struct type *); \ +attr struct type *name##_RB_MINMAX(struct name *, int); \ + \ + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp,) +#define RB_GENERATE_STATIC(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp, UV__UNUSED static) +#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ +attr void \ +name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ +{ \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) != NULL && \ + RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field); \ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field); \ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field); \ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field); \ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ +} \ + \ +attr void \ +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, \ + struct type *elm) \ +{ \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field); \ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) { \ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)) \ + != NULL) \ + RB_COLOR(oleft, field) = RB_BLACK; \ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field); \ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field); \ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \ + RB_ROTATE_LEFT(head, parent, tmp, field); \ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field); \ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) { \ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)) \ + != NULL) \ + RB_COLOR(oright, field) = RB_BLACK; \ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field); \ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field); \ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \ + RB_ROTATE_RIGHT(head, parent, tmp, field); \ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ +} \ + \ +attr struct type * \ +name##_RB_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field)) != NULL) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old) \ + RB_LEFT(RB_PARENT(old, field), field) = elm; \ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm; \ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field)) != NULL); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ +color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ +} \ + \ +/* Inserts a node into the RB tree */ \ +attr struct type * \ +name##_RB_INSERT(struct name *head, struct type *elm) \ +{ \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = elm; \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ +} \ + \ +/* Finds the node with the same key as elm */ \ +attr struct type * \ +name##_RB_FIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ +} \ + \ +/* Finds the first node greater than or equal to the search key */ \ +attr struct type * \ +name##_RB_NFIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *res = NULL; \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) { \ + res = tmp; \ + tmp = RB_LEFT(tmp, field); \ + } \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (res); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_NEXT(struct type *elm) \ +{ \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_PREV(struct type *elm) \ +{ \ + if (RB_LEFT(elm, field)) { \ + elm = RB_LEFT(elm, field); \ + while (RB_RIGHT(elm, field)) \ + elm = RB_RIGHT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +attr struct type * \ +name##_RB_MINMAX(struct name *head, int val) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ +} + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_PREV(name, x, y) name##_RB_PREV(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) + +#define RB_FOREACH_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_SAFE(x, name, head, y) \ + for ((x) = RB_MIN(name, head); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE(x, name, head) \ + for ((x) = RB_MAX(name, head); \ + (x) != NULL; \ + (x) = name##_RB_PREV(x)) + +#define RB_FOREACH_REVERSE_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ + for ((x) = RB_MAX(name, head); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) + +#endif /* UV_TREE_H_ */ diff --git a/include/uv-aix.h b/include/uv-aix.h new file mode 100644 index 0000000..7dc992f --- /dev/null +++ b/include/uv-aix.h @@ -0,0 +1,32 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_AIX_H +#define UV_AIX_H + +#define UV_PLATFORM_LOOP_FIELDS \ + int fs_fd; \ + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + uv__io_t event_watcher; \ + char *dir_filename; \ + +#endif /* UV_AIX_H */ diff --git a/include/uv-bsd.h b/include/uv-bsd.h new file mode 100644 index 0000000..2d72b3d --- /dev/null +++ b/include/uv-bsd.h @@ -0,0 +1,34 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_BSD_H +#define UV_BSD_H + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + uv__io_t event_watcher; \ + +#define UV_IO_PRIVATE_PLATFORM_FIELDS \ + int rcount; \ + int wcount; \ + +#define UV_HAVE_KQUEUE 1 + +#endif /* UV_BSD_H */ diff --git a/include/uv-darwin.h b/include/uv-darwin.h new file mode 100644 index 0000000..d226415 --- /dev/null +++ b/include/uv-darwin.h @@ -0,0 +1,61 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_DARWIN_H +#define UV_DARWIN_H + +#if defined(__APPLE__) && defined(__MACH__) +# include +# include +# include +# include +# define UV_PLATFORM_SEM_T semaphore_t +#endif + +#define UV_IO_PRIVATE_PLATFORM_FIELDS \ + int rcount; \ + int wcount; \ + +#define UV_PLATFORM_LOOP_FIELDS \ + uv_thread_t cf_thread; \ + void* _cf_reserved; \ + void* cf_state; \ + uv_mutex_t cf_mutex; \ + uv_sem_t cf_sem; \ + void* cf_signals[2]; \ + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + uv__io_t event_watcher; \ + char* realpath; \ + int realpath_len; \ + int cf_flags; \ + uv_async_t* cf_cb; \ + void* cf_events[2]; \ + void* cf_member[2]; \ + int cf_error; \ + uv_mutex_t cf_mutex; \ + +#define UV_STREAM_PRIVATE_PLATFORM_FIELDS \ + void* select; \ + +#define UV_HAVE_KQUEUE 1 + +#endif /* UV_DARWIN_H */ diff --git a/include/uv-errno.h b/include/uv-errno.h new file mode 100644 index 0000000..f137151 --- /dev/null +++ b/include/uv-errno.h @@ -0,0 +1,419 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_ERRNO_H_ +#define UV_ERRNO_H_ + +#include + +#define UV__EOF (-4095) +#define UV__UNKNOWN (-4094) + +#define UV__EAI_ADDRFAMILY (-3000) +#define UV__EAI_AGAIN (-3001) +#define UV__EAI_BADFLAGS (-3002) +#define UV__EAI_CANCELED (-3003) +#define UV__EAI_FAIL (-3004) +#define UV__EAI_FAMILY (-3005) +#define UV__EAI_MEMORY (-3006) +#define UV__EAI_NODATA (-3007) +#define UV__EAI_NONAME (-3008) +#define UV__EAI_OVERFLOW (-3009) +#define UV__EAI_SERVICE (-3010) +#define UV__EAI_SOCKTYPE (-3011) +#define UV__EAI_BADHINTS (-3013) +#define UV__EAI_PROTOCOL (-3014) + +/* Only map to the system errno on non-Windows platforms. It's apparently + * a fairly common practice for Windows programmers to redefine errno codes. + */ +#if defined(E2BIG) && !defined(_WIN32) +# define UV__E2BIG (-E2BIG) +#else +# define UV__E2BIG (-4093) +#endif + +#if defined(EACCES) && !defined(_WIN32) +# define UV__EACCES (-EACCES) +#else +# define UV__EACCES (-4092) +#endif + +#if defined(EADDRINUSE) && !defined(_WIN32) +# define UV__EADDRINUSE (-EADDRINUSE) +#else +# define UV__EADDRINUSE (-4091) +#endif + +#if defined(EADDRNOTAVAIL) && !defined(_WIN32) +# define UV__EADDRNOTAVAIL (-EADDRNOTAVAIL) +#else +# define UV__EADDRNOTAVAIL (-4090) +#endif + +#if defined(EAFNOSUPPORT) && !defined(_WIN32) +# define UV__EAFNOSUPPORT (-EAFNOSUPPORT) +#else +# define UV__EAFNOSUPPORT (-4089) +#endif + +#if defined(EAGAIN) && !defined(_WIN32) +# define UV__EAGAIN (-EAGAIN) +#else +# define UV__EAGAIN (-4088) +#endif + +#if defined(EALREADY) && !defined(_WIN32) +# define UV__EALREADY (-EALREADY) +#else +# define UV__EALREADY (-4084) +#endif + +#if defined(EBADF) && !defined(_WIN32) +# define UV__EBADF (-EBADF) +#else +# define UV__EBADF (-4083) +#endif + +#if defined(EBUSY) && !defined(_WIN32) +# define UV__EBUSY (-EBUSY) +#else +# define UV__EBUSY (-4082) +#endif + +#if defined(ECANCELED) && !defined(_WIN32) +# define UV__ECANCELED (-ECANCELED) +#else +# define UV__ECANCELED (-4081) +#endif + +#if defined(ECHARSET) && !defined(_WIN32) +# define UV__ECHARSET (-ECHARSET) +#else +# define UV__ECHARSET (-4080) +#endif + +#if defined(ECONNABORTED) && !defined(_WIN32) +# define UV__ECONNABORTED (-ECONNABORTED) +#else +# define UV__ECONNABORTED (-4079) +#endif + +#if defined(ECONNREFUSED) && !defined(_WIN32) +# define UV__ECONNREFUSED (-ECONNREFUSED) +#else +# define UV__ECONNREFUSED (-4078) +#endif + +#if defined(ECONNRESET) && !defined(_WIN32) +# define UV__ECONNRESET (-ECONNRESET) +#else +# define UV__ECONNRESET (-4077) +#endif + +#if defined(EDESTADDRREQ) && !defined(_WIN32) +# define UV__EDESTADDRREQ (-EDESTADDRREQ) +#else +# define UV__EDESTADDRREQ (-4076) +#endif + +#if defined(EEXIST) && !defined(_WIN32) +# define UV__EEXIST (-EEXIST) +#else +# define UV__EEXIST (-4075) +#endif + +#if defined(EFAULT) && !defined(_WIN32) +# define UV__EFAULT (-EFAULT) +#else +# define UV__EFAULT (-4074) +#endif + +#if defined(EHOSTUNREACH) && !defined(_WIN32) +# define UV__EHOSTUNREACH (-EHOSTUNREACH) +#else +# define UV__EHOSTUNREACH (-4073) +#endif + +#if defined(EINTR) && !defined(_WIN32) +# define UV__EINTR (-EINTR) +#else +# define UV__EINTR (-4072) +#endif + +#if defined(EINVAL) && !defined(_WIN32) +# define UV__EINVAL (-EINVAL) +#else +# define UV__EINVAL (-4071) +#endif + +#if defined(EIO) && !defined(_WIN32) +# define UV__EIO (-EIO) +#else +# define UV__EIO (-4070) +#endif + +#if defined(EISCONN) && !defined(_WIN32) +# define UV__EISCONN (-EISCONN) +#else +# define UV__EISCONN (-4069) +#endif + +#if defined(EISDIR) && !defined(_WIN32) +# define UV__EISDIR (-EISDIR) +#else +# define UV__EISDIR (-4068) +#endif + +#if defined(ELOOP) && !defined(_WIN32) +# define UV__ELOOP (-ELOOP) +#else +# define UV__ELOOP (-4067) +#endif + +#if defined(EMFILE) && !defined(_WIN32) +# define UV__EMFILE (-EMFILE) +#else +# define UV__EMFILE (-4066) +#endif + +#if defined(EMSGSIZE) && !defined(_WIN32) +# define UV__EMSGSIZE (-EMSGSIZE) +#else +# define UV__EMSGSIZE (-4065) +#endif + +#if defined(ENAMETOOLONG) && !defined(_WIN32) +# define UV__ENAMETOOLONG (-ENAMETOOLONG) +#else +# define UV__ENAMETOOLONG (-4064) +#endif + +#if defined(ENETDOWN) && !defined(_WIN32) +# define UV__ENETDOWN (-ENETDOWN) +#else +# define UV__ENETDOWN (-4063) +#endif + +#if defined(ENETUNREACH) && !defined(_WIN32) +# define UV__ENETUNREACH (-ENETUNREACH) +#else +# define UV__ENETUNREACH (-4062) +#endif + +#if defined(ENFILE) && !defined(_WIN32) +# define UV__ENFILE (-ENFILE) +#else +# define UV__ENFILE (-4061) +#endif + +#if defined(ENOBUFS) && !defined(_WIN32) +# define UV__ENOBUFS (-ENOBUFS) +#else +# define UV__ENOBUFS (-4060) +#endif + +#if defined(ENODEV) && !defined(_WIN32) +# define UV__ENODEV (-ENODEV) +#else +# define UV__ENODEV (-4059) +#endif + +#if defined(ENOENT) && !defined(_WIN32) +# define UV__ENOENT (-ENOENT) +#else +# define UV__ENOENT (-4058) +#endif + +#if defined(ENOMEM) && !defined(_WIN32) +# define UV__ENOMEM (-ENOMEM) +#else +# define UV__ENOMEM (-4057) +#endif + +#if defined(ENONET) && !defined(_WIN32) +# define UV__ENONET (-ENONET) +#else +# define UV__ENONET (-4056) +#endif + +#if defined(ENOSPC) && !defined(_WIN32) +# define UV__ENOSPC (-ENOSPC) +#else +# define UV__ENOSPC (-4055) +#endif + +#if defined(ENOSYS) && !defined(_WIN32) +# define UV__ENOSYS (-ENOSYS) +#else +# define UV__ENOSYS (-4054) +#endif + +#if defined(ENOTCONN) && !defined(_WIN32) +# define UV__ENOTCONN (-ENOTCONN) +#else +# define UV__ENOTCONN (-4053) +#endif + +#if defined(ENOTDIR) && !defined(_WIN32) +# define UV__ENOTDIR (-ENOTDIR) +#else +# define UV__ENOTDIR (-4052) +#endif + +#if defined(ENOTEMPTY) && !defined(_WIN32) +# define UV__ENOTEMPTY (-ENOTEMPTY) +#else +# define UV__ENOTEMPTY (-4051) +#endif + +#if defined(ENOTSOCK) && !defined(_WIN32) +# define UV__ENOTSOCK (-ENOTSOCK) +#else +# define UV__ENOTSOCK (-4050) +#endif + +#if defined(ENOTSUP) && !defined(_WIN32) +# define UV__ENOTSUP (-ENOTSUP) +#else +# define UV__ENOTSUP (-4049) +#endif + +#if defined(EPERM) && !defined(_WIN32) +# define UV__EPERM (-EPERM) +#else +# define UV__EPERM (-4048) +#endif + +#if defined(EPIPE) && !defined(_WIN32) +# define UV__EPIPE (-EPIPE) +#else +# define UV__EPIPE (-4047) +#endif + +#if defined(EPROTO) && !defined(_WIN32) +# define UV__EPROTO (-EPROTO) +#else +# define UV__EPROTO (-4046) +#endif + +#if defined(EPROTONOSUPPORT) && !defined(_WIN32) +# define UV__EPROTONOSUPPORT (-EPROTONOSUPPORT) +#else +# define UV__EPROTONOSUPPORT (-4045) +#endif + +#if defined(EPROTOTYPE) && !defined(_WIN32) +# define UV__EPROTOTYPE (-EPROTOTYPE) +#else +# define UV__EPROTOTYPE (-4044) +#endif + +#if defined(EROFS) && !defined(_WIN32) +# define UV__EROFS (-EROFS) +#else +# define UV__EROFS (-4043) +#endif + +#if defined(ESHUTDOWN) && !defined(_WIN32) +# define UV__ESHUTDOWN (-ESHUTDOWN) +#else +# define UV__ESHUTDOWN (-4042) +#endif + +#if defined(ESPIPE) && !defined(_WIN32) +# define UV__ESPIPE (-ESPIPE) +#else +# define UV__ESPIPE (-4041) +#endif + +#if defined(ESRCH) && !defined(_WIN32) +# define UV__ESRCH (-ESRCH) +#else +# define UV__ESRCH (-4040) +#endif + +#if defined(ETIMEDOUT) && !defined(_WIN32) +# define UV__ETIMEDOUT (-ETIMEDOUT) +#else +# define UV__ETIMEDOUT (-4039) +#endif + +#if defined(ETXTBSY) && !defined(_WIN32) +# define UV__ETXTBSY (-ETXTBSY) +#else +# define UV__ETXTBSY (-4038) +#endif + +#if defined(EXDEV) && !defined(_WIN32) +# define UV__EXDEV (-EXDEV) +#else +# define UV__EXDEV (-4037) +#endif + +#if defined(EFBIG) && !defined(_WIN32) +# define UV__EFBIG (-EFBIG) +#else +# define UV__EFBIG (-4036) +#endif + +#if defined(ENOPROTOOPT) && !defined(_WIN32) +# define UV__ENOPROTOOPT (-ENOPROTOOPT) +#else +# define UV__ENOPROTOOPT (-4035) +#endif + +#if defined(ERANGE) && !defined(_WIN32) +# define UV__ERANGE (-ERANGE) +#else +# define UV__ERANGE (-4034) +#endif + +#if defined(ENXIO) && !defined(_WIN32) +# define UV__ENXIO (-ENXIO) +#else +# define UV__ENXIO (-4033) +#endif + +#if defined(EMLINK) && !defined(_WIN32) +# define UV__EMLINK (-EMLINK) +#else +# define UV__EMLINK (-4032) +#endif + +/* EHOSTDOWN is not visible on BSD-like systems when _POSIX_C_SOURCE is + * defined. Fortunately, its value is always 64 so it's possible albeit + * icky to hard-code it. + */ +#if defined(EHOSTDOWN) && !defined(_WIN32) +# define UV__EHOSTDOWN (-EHOSTDOWN) +#elif defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) +# define UV__EHOSTDOWN (-64) +#else +# define UV__EHOSTDOWN (-4031) +#endif + +#endif /* UV_ERRNO_H_ */ diff --git a/include/uv-linux.h b/include/uv-linux.h new file mode 100644 index 0000000..9b38405 --- /dev/null +++ b/include/uv-linux.h @@ -0,0 +1,34 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_LINUX_H +#define UV_LINUX_H + +#define UV_PLATFORM_LOOP_FIELDS \ + uv__io_t inotify_read_watcher; \ + void* inotify_watchers; \ + int inotify_fd; \ + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + void* watchers[2]; \ + int wd; \ + +#endif /* UV_LINUX_H */ diff --git a/include/uv-os390.h b/include/uv-os390.h new file mode 100644 index 0000000..b0b068f --- /dev/null +++ b/include/uv-os390.h @@ -0,0 +1,27 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * 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 UV_MVS_H +#define UV_MVS_H + +#define UV_PLATFORM_SEM_T int + +#endif /* UV_MVS_H */ diff --git a/include/uv-sunos.h b/include/uv-sunos.h new file mode 100644 index 0000000..0421664 --- /dev/null +++ b/include/uv-sunos.h @@ -0,0 +1,44 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_SUNOS_H +#define UV_SUNOS_H + +#include +#include + +/* For the sake of convenience and reduced #ifdef-ery in src/unix/sunos.c, + * add the fs_event fields even when this version of SunOS doesn't support + * file watching. + */ +#define UV_PLATFORM_LOOP_FIELDS \ + uv__io_t fs_event_watcher; \ + int fs_fd; \ + +#if defined(PORT_SOURCE_FILE) + +# define UV_PLATFORM_FS_EVENT_FIELDS \ + file_obj_t fo; \ + int fd; \ + +#endif /* defined(PORT_SOURCE_FILE) */ + +#endif /* UV_SUNOS_H */ diff --git a/include/uv-threadpool.h b/include/uv-threadpool.h new file mode 100644 index 0000000..9708ebd --- /dev/null +++ b/include/uv-threadpool.h @@ -0,0 +1,37 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +/* + * This file is private to libuv. It provides common functionality to both + * Windows and Unix backends. + */ + +#ifndef UV_THREADPOOL_H_ +#define UV_THREADPOOL_H_ + +struct uv__work { + void (*work)(struct uv__work *w); + void (*done)(struct uv__work *w, int status); + struct uv_loop_s* loop; + void* wq[2]; +}; + +#endif /* UV_THREADPOOL_H_ */ diff --git a/include/uv-unix.h b/include/uv-unix.h new file mode 100644 index 0000000..bca2714 --- /dev/null +++ b/include/uv-unix.h @@ -0,0 +1,371 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_UNIX_H +#define UV_UNIX_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "uv-threadpool.h" + +#if defined(__linux__) +# include "uv-linux.h" +#elif defined(_AIX) +# include "uv-aix.h" +#elif defined(__sun) +# include "uv-sunos.h" +#elif defined(__APPLE__) +# include "uv-darwin.h" +#elif defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# include "uv-bsd.h" +#endif + +#ifndef PTHREAD_BARRIER_SERIAL_THREAD +# include "pthread-barrier.h" +#endif + +#ifndef NI_MAXHOST +# define NI_MAXHOST 1025 +#endif + +#ifndef NI_MAXSERV +# define NI_MAXSERV 32 +#endif + +#ifndef UV_IO_PRIVATE_PLATFORM_FIELDS +# define UV_IO_PRIVATE_PLATFORM_FIELDS /* empty */ +#endif + +struct uv__io_s; +struct uv__async; +struct uv_loop_s; + +typedef void (*uv__io_cb)(struct uv_loop_s* loop, + struct uv__io_s* w, + unsigned int events); +typedef struct uv__io_s uv__io_t; + +struct uv__io_s { + uv__io_cb cb; + void* pending_queue[2]; + void* watcher_queue[2]; + unsigned int pevents; /* Pending event mask i.e. mask at next tick. */ + unsigned int events; /* Current event mask. */ + int fd; + UV_IO_PRIVATE_PLATFORM_FIELDS +}; + +typedef void (*uv__async_cb)(struct uv_loop_s* loop, + struct uv__async* w, + unsigned int nevents); + +struct uv__async { + uv__async_cb cb; + uv__io_t io_watcher; + int wfd; +}; + +#ifndef UV_PLATFORM_SEM_T +# define UV_PLATFORM_SEM_T sem_t +#endif + +#ifndef UV_PLATFORM_LOOP_FIELDS +# define UV_PLATFORM_LOOP_FIELDS /* empty */ +#endif + +#ifndef UV_PLATFORM_FS_EVENT_FIELDS +# define UV_PLATFORM_FS_EVENT_FIELDS /* empty */ +#endif + +#ifndef UV_STREAM_PRIVATE_PLATFORM_FIELDS +# define UV_STREAM_PRIVATE_PLATFORM_FIELDS /* empty */ +#endif + +/* Note: May be cast to struct iovec. See writev(2). */ +typedef struct uv_buf_t { + char* base; + size_t len; +} uv_buf_t; + +typedef int uv_file; +typedef int uv_os_sock_t; +typedef int uv_os_fd_t; + +#define UV_ONCE_INIT PTHREAD_ONCE_INIT + +typedef pthread_once_t uv_once_t; +typedef pthread_t uv_thread_t; +typedef pthread_mutex_t uv_mutex_t; +typedef pthread_rwlock_t uv_rwlock_t; +typedef UV_PLATFORM_SEM_T uv_sem_t; +typedef pthread_cond_t uv_cond_t; +typedef pthread_key_t uv_key_t; +typedef pthread_barrier_t uv_barrier_t; + + +/* Platform-specific definitions for uv_spawn support. */ +typedef gid_t uv_gid_t; +typedef uid_t uv_uid_t; + +typedef struct dirent uv__dirent_t; + +#if defined(DT_UNKNOWN) +# define HAVE_DIRENT_TYPES +# if defined(DT_REG) +# define UV__DT_FILE DT_REG +# else +# define UV__DT_FILE -1 +# endif +# if defined(DT_DIR) +# define UV__DT_DIR DT_DIR +# else +# define UV__DT_DIR -2 +# endif +# if defined(DT_LNK) +# define UV__DT_LINK DT_LNK +# else +# define UV__DT_LINK -3 +# endif +# if defined(DT_FIFO) +# define UV__DT_FIFO DT_FIFO +# else +# define UV__DT_FIFO -4 +# endif +# if defined(DT_SOCK) +# define UV__DT_SOCKET DT_SOCK +# else +# define UV__DT_SOCKET -5 +# endif +# if defined(DT_CHR) +# define UV__DT_CHAR DT_CHR +# else +# define UV__DT_CHAR -6 +# endif +# if defined(DT_BLK) +# define UV__DT_BLOCK DT_BLK +# else +# define UV__DT_BLOCK -7 +# endif +#endif + +/* Platform-specific definitions for uv_dlopen support. */ +#define UV_DYNAMIC /* empty */ + +typedef struct { + void* handle; + char* errmsg; +} uv_lib_t; + +#define UV_LOOP_PRIVATE_FIELDS \ + unsigned long flags; \ + int backend_fd; \ + void* pending_queue[2]; \ + void* watcher_queue[2]; \ + uv__io_t** watchers; \ + unsigned int nwatchers; \ + unsigned int nfds; \ + void* wq[2]; \ + uv_mutex_t wq_mutex; \ + uv_async_t wq_async; \ + uv_rwlock_t cloexec_lock; \ + uv_handle_t* closing_handles; \ + void* process_handles[2]; \ + void* prepare_handles[2]; \ + void* check_handles[2]; \ + void* idle_handles[2]; \ + void* async_handles[2]; \ + struct uv__async async_watcher; \ + struct { \ + void* min; \ + unsigned int nelts; \ + } timer_heap; \ + uint64_t timer_counter; \ + uint64_t time; \ + int signal_pipefd[2]; \ + uv__io_t signal_io_watcher; \ + uv_signal_t child_watcher; \ + int emfile_fd; \ + UV_PLATFORM_LOOP_FIELDS \ + +#define UV_REQ_TYPE_PRIVATE /* empty */ + +#define UV_REQ_PRIVATE_FIELDS /* empty */ + +#define UV_PRIVATE_REQ_TYPES /* empty */ + +#define UV_WRITE_PRIVATE_FIELDS \ + void* queue[2]; \ + unsigned int write_index; \ + uv_buf_t* bufs; \ + unsigned int nbufs; \ + int error; \ + uv_buf_t bufsml[4]; \ + +#define UV_CONNECT_PRIVATE_FIELDS \ + void* queue[2]; \ + +#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */ + +#define UV_UDP_SEND_PRIVATE_FIELDS \ + void* queue[2]; \ + struct sockaddr_storage addr; \ + unsigned int nbufs; \ + uv_buf_t* bufs; \ + ssize_t status; \ + uv_udp_send_cb send_cb; \ + uv_buf_t bufsml[4]; \ + +#define UV_HANDLE_PRIVATE_FIELDS \ + uv_handle_t* next_closing; \ + unsigned int flags; \ + +#define UV_STREAM_PRIVATE_FIELDS \ + uv_connect_t *connect_req; \ + uv_shutdown_t *shutdown_req; \ + uv__io_t io_watcher; \ + void* write_queue[2]; \ + void* write_completed_queue[2]; \ + uv_connection_cb connection_cb; \ + int delayed_error; \ + int accepted_fd; \ + void* queued_fds; \ + UV_STREAM_PRIVATE_PLATFORM_FIELDS \ + +#define UV_TCP_PRIVATE_FIELDS /* empty */ + +#define UV_UDP_PRIVATE_FIELDS \ + uv_alloc_cb alloc_cb; \ + uv_udp_recv_cb recv_cb; \ + uv__io_t io_watcher; \ + void* write_queue[2]; \ + void* write_completed_queue[2]; \ + +#define UV_PIPE_PRIVATE_FIELDS \ + const char* pipe_fname; /* strdup'ed */ + +#define UV_POLL_PRIVATE_FIELDS \ + uv__io_t io_watcher; + +#define UV_PREPARE_PRIVATE_FIELDS \ + uv_prepare_cb prepare_cb; \ + void* queue[2]; \ + +#define UV_CHECK_PRIVATE_FIELDS \ + uv_check_cb check_cb; \ + void* queue[2]; \ + +#define UV_IDLE_PRIVATE_FIELDS \ + uv_idle_cb idle_cb; \ + void* queue[2]; \ + +#define UV_ASYNC_PRIVATE_FIELDS \ + uv_async_cb async_cb; \ + void* queue[2]; \ + int pending; \ + +#define UV_TIMER_PRIVATE_FIELDS \ + uv_timer_cb timer_cb; \ + void* heap_node[3]; \ + uint64_t timeout; \ + uint64_t repeat; \ + uint64_t start_id; + +#define UV_GETADDRINFO_PRIVATE_FIELDS \ + struct uv__work work_req; \ + uv_getaddrinfo_cb cb; \ + struct addrinfo* hints; \ + char* hostname; \ + char* service; \ + struct addrinfo* addrinfo; \ + int retcode; + +#define UV_GETNAMEINFO_PRIVATE_FIELDS \ + struct uv__work work_req; \ + uv_getnameinfo_cb getnameinfo_cb; \ + struct sockaddr_storage storage; \ + int flags; \ + char host[NI_MAXHOST]; \ + char service[NI_MAXSERV]; \ + int retcode; + +#define UV_PROCESS_PRIVATE_FIELDS \ + void* queue[2]; \ + int status; \ + +#define UV_FS_PRIVATE_FIELDS \ + const char *new_path; \ + uv_file file; \ + int flags; \ + mode_t mode; \ + unsigned int nbufs; \ + uv_buf_t* bufs; \ + off_t off; \ + uv_uid_t uid; \ + uv_gid_t gid; \ + double atime; \ + double mtime; \ + struct uv__work work_req; \ + uv_buf_t bufsml[4]; \ + +#define UV_WORK_PRIVATE_FIELDS \ + struct uv__work work_req; + +#define UV_TTY_PRIVATE_FIELDS \ + struct termios orig_termios; \ + int mode; + +#define UV_SIGNAL_PRIVATE_FIELDS \ + /* RB_ENTRY(uv_signal_s) tree_entry; */ \ + struct { \ + struct uv_signal_s* rbe_left; \ + struct uv_signal_s* rbe_right; \ + struct uv_signal_s* rbe_parent; \ + int rbe_color; \ + } tree_entry; \ + /* Use two counters here so we don have to fiddle with atomics. */ \ + unsigned int caught_signals; \ + unsigned int dispatched_signals; + +#define UV_FS_EVENT_PRIVATE_FIELDS \ + uv_fs_event_cb cb; \ + UV_PLATFORM_FS_EVENT_FIELDS \ + +#endif /* UV_UNIX_H */ diff --git a/include/uv-version.h b/include/uv-version.h new file mode 100644 index 0000000..3cb9b5f --- /dev/null +++ b/include/uv-version.h @@ -0,0 +1,43 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_VERSION_H +#define UV_VERSION_H + + /* + * Versions with the same major number are ABI stable. API is allowed to + * evolve between minor releases, but only in a backwards compatible way. + * Make sure you update the -soname directives in configure.ac + * and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but + * not UV_VERSION_PATCH.) + */ + +#define UV_VERSION_MAJOR 1 +#define UV_VERSION_MINOR 9 +#define UV_VERSION_PATCH 2 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" + +#define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ + (UV_VERSION_MINOR << 8) | \ + (UV_VERSION_PATCH)) + +#endif /* UV_VERSION_H */ diff --git a/include/uv-win.h b/include/uv-win.h new file mode 100644 index 0000000..a75dba8 --- /dev/null +++ b/include/uv-win.h @@ -0,0 +1,649 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 _WIN32_WINNT +# define _WIN32_WINNT 0x0502 +#endif + +#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED) +typedef intptr_t ssize_t; +# define _SSIZE_T_ +# define _SSIZE_T_DEFINED +#endif + +#include + +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +typedef struct pollfd { + SOCKET fd; + short events; + short revents; +} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD; +#endif + +#ifndef LOCALE_INVARIANT +# define LOCALE_INVARIANT 0x007f +#endif + +#include +#include +#include + +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#include "tree.h" +#include "uv-threadpool.h" + +#define MAX_PIPENAME_LEN 256 + +#ifndef S_IFLNK +# define S_IFLNK 0xA000 +#endif + +/* Additional signals supported by uv_signal and or uv_kill. The CRT defines + * the following signals already: + * + * #define SIGINT 2 + * #define SIGILL 4 + * #define SIGABRT_COMPAT 6 + * #define SIGFPE 8 + * #define SIGSEGV 11 + * #define SIGTERM 15 + * #define SIGBREAK 21 + * #define SIGABRT 22 + * + * The additional signals have values that are common on other Unix + * variants (Linux and Darwin) + */ +#define SIGHUP 1 +#define SIGKILL 9 +#define SIGWINCH 28 + +/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many */ +/* unix-like platforms. However MinGW doesn't define it, so we do. */ +#ifndef SIGABRT_COMPAT +# define SIGABRT_COMPAT 6 +#endif + +/* + * Guids and typedefs for winsock extension functions + * Mingw32 doesn't have these :-( + */ +#ifndef WSAID_ACCEPTEX +# define WSAID_ACCEPTEX \ + {0xb5367df1, 0xcbac, 0x11cf, \ + {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} + +# define WSAID_CONNECTEX \ + {0x25a207b9, 0xddf3, 0x4660, \ + {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}} + +# define WSAID_GETACCEPTEXSOCKADDRS \ + {0xb5367df2, 0xcbac, 0x11cf, \ + {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} + +# define WSAID_DISCONNECTEX \ + {0x7fda2e11, 0x8630, 0x436f, \ + {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}} + +# define WSAID_TRANSMITFILE \ + {0xb5367df0, 0xcbac, 0x11cf, \ + {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} + + typedef BOOL PASCAL (*LPFN_ACCEPTEX) + (SOCKET sListenSocket, + SOCKET sAcceptSocket, + PVOID lpOutputBuffer, + DWORD dwReceiveDataLength, + DWORD dwLocalAddressLength, + DWORD dwRemoteAddressLength, + LPDWORD lpdwBytesReceived, + LPOVERLAPPED lpOverlapped); + + typedef BOOL PASCAL (*LPFN_CONNECTEX) + (SOCKET s, + const struct sockaddr* name, + int namelen, + PVOID lpSendBuffer, + DWORD dwSendDataLength, + LPDWORD lpdwBytesSent, + LPOVERLAPPED lpOverlapped); + + typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS) + (PVOID lpOutputBuffer, + DWORD dwReceiveDataLength, + DWORD dwLocalAddressLength, + DWORD dwRemoteAddressLength, + LPSOCKADDR* LocalSockaddr, + LPINT LocalSockaddrLength, + LPSOCKADDR* RemoteSockaddr, + LPINT RemoteSockaddrLength); + + typedef BOOL PASCAL (*LPFN_DISCONNECTEX) + (SOCKET hSocket, + LPOVERLAPPED lpOverlapped, + DWORD dwFlags, + DWORD reserved); + + typedef BOOL PASCAL (*LPFN_TRANSMITFILE) + (SOCKET hSocket, + HANDLE hFile, + DWORD nNumberOfBytesToWrite, + DWORD nNumberOfBytesPerSend, + LPOVERLAPPED lpOverlapped, + LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, + DWORD dwFlags); + + typedef PVOID RTL_SRWLOCK; + typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK; +#endif + +typedef int (WSAAPI* LPFN_WSARECV) + (SOCKET socket, + LPWSABUF buffers, + DWORD buffer_count, + LPDWORD bytes, + LPDWORD flags, + LPWSAOVERLAPPED overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); + +typedef int (WSAAPI* LPFN_WSARECVFROM) + (SOCKET socket, + LPWSABUF buffers, + DWORD buffer_count, + LPDWORD bytes, + LPDWORD flags, + struct sockaddr* addr, + LPINT addr_len, + LPWSAOVERLAPPED overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); + +#ifndef _NTDEF_ + typedef LONG NTSTATUS; + typedef NTSTATUS *PNTSTATUS; +#endif + +#ifndef RTL_CONDITION_VARIABLE_INIT + typedef PVOID CONDITION_VARIABLE, *PCONDITION_VARIABLE; +#endif + +typedef struct _AFD_POLL_HANDLE_INFO { + HANDLE Handle; + ULONG Events; + NTSTATUS Status; +} AFD_POLL_HANDLE_INFO, *PAFD_POLL_HANDLE_INFO; + +typedef struct _AFD_POLL_INFO { + LARGE_INTEGER Timeout; + ULONG NumberOfHandles; + ULONG Exclusive; + AFD_POLL_HANDLE_INFO Handles[1]; +} AFD_POLL_INFO, *PAFD_POLL_INFO; + +#define UV_MSAFD_PROVIDER_COUNT 3 + + +/** + * It should be possible to cast uv_buf_t[] to WSABUF[] + * see http://msdn.microsoft.com/en-us/library/ms741542(v=vs.85).aspx + */ +typedef struct uv_buf_t { + ULONG len; + char* base; +} uv_buf_t; + +typedef int uv_file; +typedef SOCKET uv_os_sock_t; +typedef HANDLE uv_os_fd_t; + +typedef HANDLE uv_thread_t; + +typedef HANDLE uv_sem_t; + +typedef CRITICAL_SECTION uv_mutex_t; + +/* This condition variable implementation is based on the SetEvent solution + * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html + * We could not use the SignalObjectAndWait solution (section 3.4) because + * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and + * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs. + */ + +typedef union { + CONDITION_VARIABLE cond_var; + struct { + unsigned int waiters_count; + CRITICAL_SECTION waiters_count_lock; + HANDLE signal_event; + HANDLE broadcast_event; + } fallback; +} uv_cond_t; + +typedef union { + struct { + unsigned int num_readers_; + CRITICAL_SECTION num_readers_lock_; + HANDLE write_semaphore_; + } state_; + /* TODO: remove me in v2.x. */ + struct { + SRWLOCK unused_; + } unused1_; + /* TODO: remove me in v2.x. */ + struct { + uv_mutex_t unused1_; + uv_mutex_t unused2_; + } unused2_; +} uv_rwlock_t; + +typedef struct { + unsigned int n; + unsigned int count; + uv_mutex_t mutex; + uv_sem_t turnstile1; + uv_sem_t turnstile2; +} uv_barrier_t; + +typedef struct { + DWORD tls_index; +} uv_key_t; + +#define UV_ONCE_INIT { 0, NULL } + +typedef struct uv_once_s { + unsigned char ran; + HANDLE event; +} uv_once_t; + +/* Platform-specific definitions for uv_spawn support. */ +typedef unsigned char uv_uid_t; +typedef unsigned char uv_gid_t; + +typedef struct uv__dirent_s { + int d_type; + char d_name[1]; +} uv__dirent_t; + +#define HAVE_DIRENT_TYPES +#define UV__DT_DIR UV_DIRENT_DIR +#define UV__DT_FILE UV_DIRENT_FILE +#define UV__DT_LINK UV_DIRENT_LINK +#define UV__DT_FIFO UV_DIRENT_FIFO +#define UV__DT_SOCKET UV_DIRENT_SOCKET +#define UV__DT_CHAR UV_DIRENT_CHAR +#define UV__DT_BLOCK UV_DIRENT_BLOCK + +/* Platform-specific definitions for uv_dlopen support. */ +#define UV_DYNAMIC FAR WINAPI +typedef struct { + HMODULE handle; + char* errmsg; +} uv_lib_t; + +RB_HEAD(uv_timer_tree_s, uv_timer_s); + +#define UV_LOOP_PRIVATE_FIELDS \ + /* The loop's I/O completion port */ \ + HANDLE iocp; \ + /* The current time according to the event loop. in msecs. */ \ + uint64_t time; \ + /* Tail of a single-linked circular queue of pending reqs. If the queue */ \ + /* is empty, tail_ is NULL. If there is only one item, */ \ + /* tail_->next_req == tail_ */ \ + uv_req_t* pending_reqs_tail; \ + /* Head of a single-linked list of closed handles */ \ + uv_handle_t* endgame_handles; \ + /* The head of the timers tree */ \ + struct uv_timer_tree_s timers; \ + /* Lists of active loop (prepare / check / idle) watchers */ \ + uv_prepare_t* prepare_handles; \ + uv_check_t* check_handles; \ + uv_idle_t* idle_handles; \ + /* This pointer will refer to the prepare/check/idle handle whose */ \ + /* callback is scheduled to be called next. This is needed to allow */ \ + /* safe removal from one of the lists above while that list being */ \ + /* iterated over. */ \ + uv_prepare_t* next_prepare_handle; \ + uv_check_t* next_check_handle; \ + uv_idle_t* next_idle_handle; \ + /* This handle holds the peer sockets for the fast variant of uv_poll_t */ \ + SOCKET poll_peer_sockets[UV_MSAFD_PROVIDER_COUNT]; \ + /* Counter to keep track of active tcp streams */ \ + unsigned int active_tcp_streams; \ + /* Counter to keep track of active udp streams */ \ + unsigned int active_udp_streams; \ + /* Counter to started timer */ \ + uint64_t timer_counter; \ + /* Threadpool */ \ + void* wq[2]; \ + uv_mutex_t wq_mutex; \ + uv_async_t wq_async; + +#define UV_REQ_TYPE_PRIVATE \ + /* TODO: remove the req suffix */ \ + UV_ACCEPT, \ + UV_FS_EVENT_REQ, \ + UV_POLL_REQ, \ + UV_PROCESS_EXIT, \ + UV_READ, \ + UV_UDP_RECV, \ + UV_WAKEUP, \ + UV_SIGNAL_REQ, + +#define UV_REQ_PRIVATE_FIELDS \ + union { \ + /* Used by I/O operations */ \ + struct { \ + OVERLAPPED overlapped; \ + size_t queued_bytes; \ + } io; \ + } u; \ + struct uv_req_s* next_req; + +#define UV_WRITE_PRIVATE_FIELDS \ + int ipc_header; \ + uv_buf_t write_buffer; \ + HANDLE event_handle; \ + HANDLE wait_handle; + +#define UV_CONNECT_PRIVATE_FIELDS \ + /* empty */ + +#define UV_SHUTDOWN_PRIVATE_FIELDS \ + /* empty */ + +#define UV_UDP_SEND_PRIVATE_FIELDS \ + /* empty */ + +#define UV_PRIVATE_REQ_TYPES \ + typedef struct uv_pipe_accept_s { \ + UV_REQ_FIELDS \ + HANDLE pipeHandle; \ + struct uv_pipe_accept_s* next_pending; \ + } uv_pipe_accept_t; \ + \ + typedef struct uv_tcp_accept_s { \ + UV_REQ_FIELDS \ + SOCKET accept_socket; \ + char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \ + HANDLE event_handle; \ + HANDLE wait_handle; \ + struct uv_tcp_accept_s* next_pending; \ + } uv_tcp_accept_t; \ + \ + typedef struct uv_read_s { \ + UV_REQ_FIELDS \ + HANDLE event_handle; \ + HANDLE wait_handle; \ + } uv_read_t; + +#define uv_stream_connection_fields \ + unsigned int write_reqs_pending; \ + uv_shutdown_t* shutdown_req; + +#define uv_stream_server_fields \ + uv_connection_cb connection_cb; + +#define UV_STREAM_PRIVATE_FIELDS \ + unsigned int reqs_pending; \ + int activecnt; \ + uv_read_t read_req; \ + union { \ + struct { uv_stream_connection_fields } conn; \ + struct { uv_stream_server_fields } serv; \ + } stream; + +#define uv_tcp_server_fields \ + uv_tcp_accept_t* accept_reqs; \ + unsigned int processed_accepts; \ + uv_tcp_accept_t* pending_accepts; \ + LPFN_ACCEPTEX func_acceptex; + +#define uv_tcp_connection_fields \ + uv_buf_t read_buffer; \ + LPFN_CONNECTEX func_connectex; + +#define UV_TCP_PRIVATE_FIELDS \ + SOCKET socket; \ + int delayed_error; \ + union { \ + struct { uv_tcp_server_fields } serv; \ + struct { uv_tcp_connection_fields } conn; \ + } tcp; + +#define UV_UDP_PRIVATE_FIELDS \ + SOCKET socket; \ + unsigned int reqs_pending; \ + int activecnt; \ + uv_req_t recv_req; \ + uv_buf_t recv_buffer; \ + struct sockaddr_storage recv_from; \ + int recv_from_len; \ + uv_udp_recv_cb recv_cb; \ + uv_alloc_cb alloc_cb; \ + LPFN_WSARECV func_wsarecv; \ + LPFN_WSARECVFROM func_wsarecvfrom; + +#define uv_pipe_server_fields \ + int pending_instances; \ + uv_pipe_accept_t* accept_reqs; \ + uv_pipe_accept_t* pending_accepts; + +#define uv_pipe_connection_fields \ + uv_timer_t* eof_timer; \ + uv_write_t ipc_header_write_req; \ + int ipc_pid; \ + uint64_t remaining_ipc_rawdata_bytes; \ + struct { \ + void* queue[2]; \ + int queue_len; \ + } pending_ipc_info; \ + uv_write_t* non_overlapped_writes_tail; \ + uv_mutex_t readfile_mutex; \ + volatile HANDLE readfile_thread; + +#define UV_PIPE_PRIVATE_FIELDS \ + HANDLE handle; \ + WCHAR* name; \ + union { \ + struct { uv_pipe_server_fields } serv; \ + struct { uv_pipe_connection_fields } conn; \ + } pipe; + +/* TODO: put the parser states in an union - TTY handles are always */ +/* half-duplex so read-state can safely overlap write-state. */ +#define UV_TTY_PRIVATE_FIELDS \ + HANDLE handle; \ + union { \ + struct { \ + /* Used for readable TTY handles */ \ + /* TODO: remove me in v2.x. */ \ + HANDLE unused_; \ + uv_buf_t read_line_buffer; \ + HANDLE read_raw_wait; \ + /* Fields used for translating win keystrokes into vt100 characters */ \ + char last_key[8]; \ + unsigned char last_key_offset; \ + unsigned char last_key_len; \ + WCHAR last_utf16_high_surrogate; \ + INPUT_RECORD last_input_record; \ + } rd; \ + struct { \ + /* Used for writable TTY handles */ \ + /* utf8-to-utf16 conversion state */ \ + unsigned int utf8_codepoint; \ + unsigned char utf8_bytes_left; \ + /* eol conversion state */ \ + unsigned char previous_eol; \ + /* ansi parser state */ \ + unsigned char ansi_parser_state; \ + unsigned char ansi_csi_argc; \ + unsigned short ansi_csi_argv[4]; \ + COORD saved_position; \ + WORD saved_attributes; \ + } wr; \ + } tty; + +#define UV_POLL_PRIVATE_FIELDS \ + SOCKET socket; \ + /* Used in fast mode */ \ + SOCKET peer_socket; \ + AFD_POLL_INFO afd_poll_info_1; \ + AFD_POLL_INFO afd_poll_info_2; \ + /* Used in fast and slow mode. */ \ + uv_req_t poll_req_1; \ + uv_req_t poll_req_2; \ + unsigned char submitted_events_1; \ + unsigned char submitted_events_2; \ + unsigned char mask_events_1; \ + unsigned char mask_events_2; \ + unsigned char events; + +#define UV_TIMER_PRIVATE_FIELDS \ + RB_ENTRY(uv_timer_s) tree_entry; \ + uint64_t due; \ + uint64_t repeat; \ + uint64_t start_id; \ + uv_timer_cb timer_cb; + +#define UV_ASYNC_PRIVATE_FIELDS \ + struct uv_req_s async_req; \ + uv_async_cb async_cb; \ + /* char to avoid alignment issues */ \ + char volatile async_sent; + +#define UV_PREPARE_PRIVATE_FIELDS \ + uv_prepare_t* prepare_prev; \ + uv_prepare_t* prepare_next; \ + uv_prepare_cb prepare_cb; + +#define UV_CHECK_PRIVATE_FIELDS \ + uv_check_t* check_prev; \ + uv_check_t* check_next; \ + uv_check_cb check_cb; + +#define UV_IDLE_PRIVATE_FIELDS \ + uv_idle_t* idle_prev; \ + uv_idle_t* idle_next; \ + uv_idle_cb idle_cb; + +#define UV_HANDLE_PRIVATE_FIELDS \ + uv_handle_t* endgame_next; \ + unsigned int flags; + +#define UV_GETADDRINFO_PRIVATE_FIELDS \ + struct uv__work work_req; \ + uv_getaddrinfo_cb getaddrinfo_cb; \ + void* alloc; \ + WCHAR* node; \ + WCHAR* service; \ + /* The addrinfoW field is used to store a pointer to the hints, and */ \ + /* later on to store the result of GetAddrInfoW. The final result will */ \ + /* be converted to struct addrinfo* and stored in the addrinfo field. */ \ + struct addrinfoW* addrinfow; \ + struct addrinfo* addrinfo; \ + int retcode; + +#define UV_GETNAMEINFO_PRIVATE_FIELDS \ + struct uv__work work_req; \ + uv_getnameinfo_cb getnameinfo_cb; \ + struct sockaddr_storage storage; \ + int flags; \ + char host[NI_MAXHOST]; \ + char service[NI_MAXSERV]; \ + int retcode; + +#define UV_PROCESS_PRIVATE_FIELDS \ + struct uv_process_exit_s { \ + UV_REQ_FIELDS \ + } exit_req; \ + BYTE* child_stdio_buffer; \ + int exit_signal; \ + HANDLE wait_handle; \ + HANDLE process_handle; \ + volatile char exit_cb_pending; + +#define UV_FS_PRIVATE_FIELDS \ + struct uv__work work_req; \ + int flags; \ + DWORD sys_errno_; \ + union { \ + /* TODO: remove me in 0.9. */ \ + WCHAR* pathw; \ + int fd; \ + } file; \ + union { \ + struct { \ + int mode; \ + WCHAR* new_pathw; \ + int file_flags; \ + int fd_out; \ + unsigned int nbufs; \ + uv_buf_t* bufs; \ + int64_t offset; \ + uv_buf_t bufsml[4]; \ + } info; \ + struct { \ + double atime; \ + double mtime; \ + } time; \ + } fs; + +#define UV_WORK_PRIVATE_FIELDS \ + struct uv__work work_req; + +#define UV_FS_EVENT_PRIVATE_FIELDS \ + struct uv_fs_event_req_s { \ + UV_REQ_FIELDS \ + } req; \ + HANDLE dir_handle; \ + int req_pending; \ + uv_fs_event_cb cb; \ + WCHAR* filew; \ + WCHAR* short_filew; \ + WCHAR* dirw; \ + char* buffer; + +#define UV_SIGNAL_PRIVATE_FIELDS \ + RB_ENTRY(uv_signal_s) tree_entry; \ + struct uv_req_s signal_req; \ + unsigned long pending_signum; + +#ifndef F_OK +#define F_OK 0 +#endif +#ifndef R_OK +#define R_OK 4 +#endif +#ifndef W_OK +#define W_OK 2 +#endif +#ifndef X_OK +#define X_OK 1 +#endif diff --git a/include/uv.h b/include/uv.h new file mode 100644 index 0000000..baa0b28 --- /dev/null +++ b/include/uv.h @@ -0,0 +1,1495 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +/* See https://github.com/libuv/libuv#documentation for documentation. */ + +#ifndef UV_H +#define UV_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 + /* Windows - set up dll import/export decorators. */ +# if defined(BUILDING_UV_SHARED) + /* Building shared library. */ +# define UV_EXTERN __declspec(dllexport) +# elif defined(USING_UV_SHARED) + /* Using shared library. */ +# define UV_EXTERN __declspec(dllimport) +# else + /* Building static library. */ +# define UV_EXTERN /* nothing */ +# endif +#elif __GNUC__ >= 4 +# define UV_EXTERN __attribute__((visibility("default"))) +#else +# define UV_EXTERN /* nothing */ +#endif + +#include "uv-errno.h" +#include "uv-version.h" +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#if defined(_WIN32) +# include "uv-win.h" +#else +# include "uv-unix.h" +#endif + +/* Expand this list if necessary. */ +#define UV_ERRNO_MAP(XX) \ + XX(E2BIG, "argument list too long") \ + XX(EACCES, "permission denied") \ + XX(EADDRINUSE, "address already in use") \ + XX(EADDRNOTAVAIL, "address not available") \ + XX(EAFNOSUPPORT, "address family not supported") \ + XX(EAGAIN, "resource temporarily unavailable") \ + XX(EAI_ADDRFAMILY, "address family not supported") \ + XX(EAI_AGAIN, "temporary failure") \ + XX(EAI_BADFLAGS, "bad ai_flags value") \ + XX(EAI_BADHINTS, "invalid value for hints") \ + XX(EAI_CANCELED, "request canceled") \ + XX(EAI_FAIL, "permanent failure") \ + XX(EAI_FAMILY, "ai_family not supported") \ + XX(EAI_MEMORY, "out of memory") \ + XX(EAI_NODATA, "no address") \ + XX(EAI_NONAME, "unknown node or service") \ + XX(EAI_OVERFLOW, "argument buffer overflow") \ + XX(EAI_PROTOCOL, "resolved protocol is unknown") \ + XX(EAI_SERVICE, "service not available for socket type") \ + XX(EAI_SOCKTYPE, "socket type not supported") \ + XX(EALREADY, "connection already in progress") \ + XX(EBADF, "bad file descriptor") \ + XX(EBUSY, "resource busy or locked") \ + XX(ECANCELED, "operation canceled") \ + XX(ECHARSET, "invalid Unicode character") \ + XX(ECONNABORTED, "software caused connection abort") \ + XX(ECONNREFUSED, "connection refused") \ + XX(ECONNRESET, "connection reset by peer") \ + XX(EDESTADDRREQ, "destination address required") \ + XX(EEXIST, "file already exists") \ + XX(EFAULT, "bad address in system call argument") \ + XX(EFBIG, "file too large") \ + XX(EHOSTUNREACH, "host is unreachable") \ + XX(EINTR, "interrupted system call") \ + XX(EINVAL, "invalid argument") \ + XX(EIO, "i/o error") \ + XX(EISCONN, "socket is already connected") \ + XX(EISDIR, "illegal operation on a directory") \ + XX(ELOOP, "too many symbolic links encountered") \ + XX(EMFILE, "too many open files") \ + XX(EMSGSIZE, "message too long") \ + XX(ENAMETOOLONG, "name too long") \ + XX(ENETDOWN, "network is down") \ + XX(ENETUNREACH, "network is unreachable") \ + XX(ENFILE, "file table overflow") \ + XX(ENOBUFS, "no buffer space available") \ + XX(ENODEV, "no such device") \ + XX(ENOENT, "no such file or directory") \ + XX(ENOMEM, "not enough memory") \ + XX(ENONET, "machine is not on the network") \ + XX(ENOPROTOOPT, "protocol not available") \ + XX(ENOSPC, "no space left on device") \ + XX(ENOSYS, "function not implemented") \ + XX(ENOTCONN, "socket is not connected") \ + XX(ENOTDIR, "not a directory") \ + XX(ENOTEMPTY, "directory not empty") \ + XX(ENOTSOCK, "socket operation on non-socket") \ + XX(ENOTSUP, "operation not supported on socket") \ + XX(EPERM, "operation not permitted") \ + XX(EPIPE, "broken pipe") \ + XX(EPROTO, "protocol error") \ + XX(EPROTONOSUPPORT, "protocol not supported") \ + XX(EPROTOTYPE, "protocol wrong type for socket") \ + XX(ERANGE, "result too large") \ + XX(EROFS, "read-only file system") \ + XX(ESHUTDOWN, "cannot send after transport endpoint shutdown") \ + XX(ESPIPE, "invalid seek") \ + XX(ESRCH, "no such process") \ + XX(ETIMEDOUT, "connection timed out") \ + XX(ETXTBSY, "text file is busy") \ + XX(EXDEV, "cross-device link not permitted") \ + XX(UNKNOWN, "unknown error") \ + XX(EOF, "end of file") \ + XX(ENXIO, "no such device or address") \ + XX(EMLINK, "too many links") \ + XX(EHOSTDOWN, "host is down") \ + +#define UV_HANDLE_TYPE_MAP(XX) \ + XX(ASYNC, async) \ + XX(CHECK, check) \ + XX(FS_EVENT, fs_event) \ + XX(FS_POLL, fs_poll) \ + XX(HANDLE, handle) \ + XX(IDLE, idle) \ + XX(NAMED_PIPE, pipe) \ + XX(POLL, poll) \ + XX(PREPARE, prepare) \ + XX(PROCESS, process) \ + XX(STREAM, stream) \ + XX(TCP, tcp) \ + XX(TIMER, timer) \ + XX(TTY, tty) \ + XX(UDP, udp) \ + XX(SIGNAL, signal) \ + +#define UV_REQ_TYPE_MAP(XX) \ + XX(REQ, req) \ + XX(CONNECT, connect) \ + XX(WRITE, write) \ + XX(SHUTDOWN, shutdown) \ + XX(UDP_SEND, udp_send) \ + XX(FS, fs) \ + XX(WORK, work) \ + XX(GETADDRINFO, getaddrinfo) \ + XX(GETNAMEINFO, getnameinfo) \ + +typedef enum { +#define XX(code, _) UV_ ## code = UV__ ## code, + UV_ERRNO_MAP(XX) +#undef XX + UV_ERRNO_MAX = UV__EOF - 1 +} uv_errno_t; + +typedef enum { + UV_UNKNOWN_HANDLE = 0, +#define XX(uc, lc) UV_##uc, + UV_HANDLE_TYPE_MAP(XX) +#undef XX + UV_FILE, + UV_HANDLE_TYPE_MAX +} uv_handle_type; + +typedef enum { + UV_UNKNOWN_REQ = 0, +#define XX(uc, lc) UV_##uc, + UV_REQ_TYPE_MAP(XX) +#undef XX + UV_REQ_TYPE_PRIVATE + UV_REQ_TYPE_MAX +} uv_req_type; + + +/* Handle types. */ +typedef struct uv_loop_s uv_loop_t; +typedef struct uv_handle_s uv_handle_t; +typedef struct uv_stream_s uv_stream_t; +typedef struct uv_tcp_s uv_tcp_t; +typedef struct uv_udp_s uv_udp_t; +typedef struct uv_pipe_s uv_pipe_t; +typedef struct uv_tty_s uv_tty_t; +typedef struct uv_poll_s uv_poll_t; +typedef struct uv_timer_s uv_timer_t; +typedef struct uv_prepare_s uv_prepare_t; +typedef struct uv_check_s uv_check_t; +typedef struct uv_idle_s uv_idle_t; +typedef struct uv_async_s uv_async_t; +typedef struct uv_process_s uv_process_t; +typedef struct uv_fs_event_s uv_fs_event_t; +typedef struct uv_fs_poll_s uv_fs_poll_t; +typedef struct uv_signal_s uv_signal_t; + +/* Request types. */ +typedef struct uv_req_s uv_req_t; +typedef struct uv_getaddrinfo_s uv_getaddrinfo_t; +typedef struct uv_getnameinfo_s uv_getnameinfo_t; +typedef struct uv_shutdown_s uv_shutdown_t; +typedef struct uv_write_s uv_write_t; +typedef struct uv_connect_s uv_connect_t; +typedef struct uv_udp_send_s uv_udp_send_t; +typedef struct uv_fs_s uv_fs_t; +typedef struct uv_work_s uv_work_t; + +/* None of the above. */ +typedef struct uv_cpu_info_s uv_cpu_info_t; +typedef struct uv_interface_address_s uv_interface_address_t; +typedef struct uv_dirent_s uv_dirent_t; +typedef struct uv_passwd_s uv_passwd_t; + +typedef enum { + UV_LOOP_BLOCK_SIGNAL +} uv_loop_option; + +typedef enum { + UV_RUN_DEFAULT = 0, + UV_RUN_ONCE, + UV_RUN_NOWAIT +} uv_run_mode; + + +UV_EXTERN unsigned int uv_version(void); +UV_EXTERN const char* uv_version_string(void); + +typedef void* (*uv_malloc_func)(size_t size); +typedef void* (*uv_realloc_func)(void* ptr, size_t size); +typedef void* (*uv_calloc_func)(size_t count, size_t size); +typedef void (*uv_free_func)(void* ptr); + +UV_EXTERN int uv_replace_allocator(uv_malloc_func malloc_func, + uv_realloc_func realloc_func, + uv_calloc_func calloc_func, + uv_free_func free_func); + +UV_EXTERN uv_loop_t* uv_default_loop(void); +UV_EXTERN int uv_loop_init(uv_loop_t* loop); +UV_EXTERN int uv_loop_close(uv_loop_t* loop); +/* + * NOTE: + * This function is DEPRECATED (to be removed after 0.12), users should + * allocate the loop manually and use uv_loop_init instead. + */ +UV_EXTERN uv_loop_t* uv_loop_new(void); +/* + * NOTE: + * This function is DEPRECATED (to be removed after 0.12). Users should use + * uv_loop_close and free the memory manually instead. + */ +UV_EXTERN void uv_loop_delete(uv_loop_t*); +UV_EXTERN size_t uv_loop_size(void); +UV_EXTERN int uv_loop_alive(const uv_loop_t* loop); +UV_EXTERN int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...); + +UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode); +UV_EXTERN void uv_stop(uv_loop_t*); + +UV_EXTERN void uv_ref(uv_handle_t*); +UV_EXTERN void uv_unref(uv_handle_t*); +UV_EXTERN int uv_has_ref(const uv_handle_t*); + +UV_EXTERN void uv_update_time(uv_loop_t*); +UV_EXTERN uint64_t uv_now(const uv_loop_t*); + +UV_EXTERN int uv_backend_fd(const uv_loop_t*); +UV_EXTERN int uv_backend_timeout(const uv_loop_t*); + +typedef void (*uv_alloc_cb)(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf); +typedef void (*uv_read_cb)(uv_stream_t* stream, + ssize_t nread, + const uv_buf_t* buf); +typedef void (*uv_write_cb)(uv_write_t* req, int status); +typedef void (*uv_connect_cb)(uv_connect_t* req, int status); +typedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status); +typedef void (*uv_connection_cb)(uv_stream_t* server, int status); +typedef void (*uv_close_cb)(uv_handle_t* handle); +typedef void (*uv_poll_cb)(uv_poll_t* handle, int status, int events); +typedef void (*uv_timer_cb)(uv_timer_t* handle); +typedef void (*uv_async_cb)(uv_async_t* handle); +typedef void (*uv_prepare_cb)(uv_prepare_t* handle); +typedef void (*uv_check_cb)(uv_check_t* handle); +typedef void (*uv_idle_cb)(uv_idle_t* handle); +typedef void (*uv_exit_cb)(uv_process_t*, int64_t exit_status, int term_signal); +typedef void (*uv_walk_cb)(uv_handle_t* handle, void* arg); +typedef void (*uv_fs_cb)(uv_fs_t* req); +typedef void (*uv_work_cb)(uv_work_t* req); +typedef void (*uv_after_work_cb)(uv_work_t* req, int status); +typedef void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req, + int status, + struct addrinfo* res); +typedef void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req, + int status, + const char* hostname, + const char* service); + +typedef struct { + long tv_sec; + long tv_nsec; +} uv_timespec_t; + + +typedef struct { + uint64_t st_dev; + uint64_t st_mode; + uint64_t st_nlink; + uint64_t st_uid; + uint64_t st_gid; + uint64_t st_rdev; + uint64_t st_ino; + uint64_t st_size; + uint64_t st_blksize; + uint64_t st_blocks; + uint64_t st_flags; + uint64_t st_gen; + uv_timespec_t st_atim; + uv_timespec_t st_mtim; + uv_timespec_t st_ctim; + uv_timespec_t st_birthtim; +} uv_stat_t; + + +typedef void (*uv_fs_event_cb)(uv_fs_event_t* handle, + const char* filename, + int events, + int status); + +typedef void (*uv_fs_poll_cb)(uv_fs_poll_t* handle, + int status, + const uv_stat_t* prev, + const uv_stat_t* curr); + +typedef void (*uv_signal_cb)(uv_signal_t* handle, int signum); + + +typedef enum { + UV_LEAVE_GROUP = 0, + UV_JOIN_GROUP +} uv_membership; + + +UV_EXTERN const char* uv_strerror(int err); +UV_EXTERN const char* uv_err_name(int err); + + +#define UV_REQ_FIELDS \ + /* public */ \ + void* data; \ + /* read-only */ \ + uv_req_type type; \ + /* private */ \ + void* active_queue[2]; \ + void* reserved[4]; \ + UV_REQ_PRIVATE_FIELDS \ + +/* Abstract base class of all requests. */ +struct uv_req_s { + UV_REQ_FIELDS +}; + + +/* Platform-specific request types. */ +UV_PRIVATE_REQ_TYPES + + +UV_EXTERN int uv_shutdown(uv_shutdown_t* req, + uv_stream_t* handle, + uv_shutdown_cb cb); + +struct uv_shutdown_s { + UV_REQ_FIELDS + uv_stream_t* handle; + uv_shutdown_cb cb; + UV_SHUTDOWN_PRIVATE_FIELDS +}; + + +#define UV_HANDLE_FIELDS \ + /* public */ \ + void* data; \ + /* read-only */ \ + uv_loop_t* loop; \ + uv_handle_type type; \ + /* private */ \ + uv_close_cb close_cb; \ + void* handle_queue[2]; \ + union { \ + int fd; \ + void* reserved[4]; \ + } u; \ + UV_HANDLE_PRIVATE_FIELDS \ + +/* The abstract base class of all handles. */ +struct uv_handle_s { + UV_HANDLE_FIELDS +}; + +UV_EXTERN size_t uv_handle_size(uv_handle_type type); +UV_EXTERN size_t uv_req_size(uv_req_type type); + +UV_EXTERN int uv_is_active(const uv_handle_t* handle); + +UV_EXTERN void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg); + +/* Helpers for ad hoc debugging, no API/ABI stability guaranteed. */ +UV_EXTERN void uv_print_all_handles(uv_loop_t* loop, FILE* stream); +UV_EXTERN void uv_print_active_handles(uv_loop_t* loop, FILE* stream); + +UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb); + +UV_EXTERN int uv_send_buffer_size(uv_handle_t* handle, int* value); +UV_EXTERN int uv_recv_buffer_size(uv_handle_t* handle, int* value); + +UV_EXTERN int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd); + +UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len); + + +#define UV_STREAM_FIELDS \ + /* number of bytes queued for writing */ \ + size_t write_queue_size; \ + uv_alloc_cb alloc_cb; \ + uv_read_cb read_cb; \ + /* private */ \ + UV_STREAM_PRIVATE_FIELDS + +/* + * uv_stream_t is a subclass of uv_handle_t. + * + * uv_stream is an abstract class. + * + * uv_stream_t is the parent class of uv_tcp_t, uv_pipe_t and uv_tty_t. + */ +struct uv_stream_s { + UV_HANDLE_FIELDS + UV_STREAM_FIELDS +}; + +UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb); +UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client); + +UV_EXTERN int uv_read_start(uv_stream_t*, + uv_alloc_cb alloc_cb, + uv_read_cb read_cb); +UV_EXTERN int uv_read_stop(uv_stream_t*); + +UV_EXTERN int uv_write(uv_write_t* req, + uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb); +UV_EXTERN int uv_write2(uv_write_t* req, + uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb); +UV_EXTERN int uv_try_write(uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs); + +/* uv_write_t is a subclass of uv_req_t. */ +struct uv_write_s { + UV_REQ_FIELDS + uv_write_cb cb; + uv_stream_t* send_handle; + uv_stream_t* handle; + UV_WRITE_PRIVATE_FIELDS +}; + + +UV_EXTERN int uv_is_readable(const uv_stream_t* handle); +UV_EXTERN int uv_is_writable(const uv_stream_t* handle); + +UV_EXTERN int uv_stream_set_blocking(uv_stream_t* handle, int blocking); + +UV_EXTERN int uv_is_closing(const uv_handle_t* handle); + + +/* + * uv_tcp_t is a subclass of uv_stream_t. + * + * Represents a TCP stream or TCP server. + */ +struct uv_tcp_s { + UV_HANDLE_FIELDS + UV_STREAM_FIELDS + UV_TCP_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle); +UV_EXTERN int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, unsigned int flags); +UV_EXTERN int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock); +UV_EXTERN int uv_tcp_nodelay(uv_tcp_t* handle, int enable); +UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle, + int enable, + unsigned int delay); +UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable); + +enum uv_tcp_flags { + /* Used with uv_tcp_bind, when an IPv6 address is used. */ + UV_TCP_IPV6ONLY = 1 +}; + +UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int flags); +UV_EXTERN int uv_tcp_getsockname(const uv_tcp_t* handle, + struct sockaddr* name, + int* namelen); +UV_EXTERN int uv_tcp_getpeername(const uv_tcp_t* handle, + struct sockaddr* name, + int* namelen); +UV_EXTERN int uv_tcp_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + uv_connect_cb cb); + +/* uv_connect_t is a subclass of uv_req_t. */ +struct uv_connect_s { + UV_REQ_FIELDS + uv_connect_cb cb; + uv_stream_t* handle; + UV_CONNECT_PRIVATE_FIELDS +}; + + +/* + * UDP support. + */ + +enum uv_udp_flags { + /* Disables dual stack mode. */ + UV_UDP_IPV6ONLY = 1, + /* + * Indicates message was truncated because read buffer was too small. The + * remainder was discarded by the OS. Used in uv_udp_recv_cb. + */ + UV_UDP_PARTIAL = 2, + /* + * Indicates if SO_REUSEADDR will be set when binding the handle. + * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other + * Unix platforms, it sets the SO_REUSEADDR flag. What that means is that + * multiple threads or processes can bind to the same address without error + * (provided they all set the flag) but only the last one to bind will receive + * any traffic, in effect "stealing" the port from the previous listener. + */ + UV_UDP_REUSEADDR = 4 +}; + +typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status); +typedef void (*uv_udp_recv_cb)(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags); + +/* uv_udp_t is a subclass of uv_handle_t. */ +struct uv_udp_s { + UV_HANDLE_FIELDS + /* read-only */ + /* + * Number of bytes queued for sending. This field strictly shows how much + * information is currently queued. + */ + size_t send_queue_size; + /* + * Number of send requests currently in the queue awaiting to be processed. + */ + size_t send_queue_count; + UV_UDP_PRIVATE_FIELDS +}; + +/* uv_udp_send_t is a subclass of uv_req_t. */ +struct uv_udp_send_s { + UV_REQ_FIELDS + uv_udp_t* handle; + uv_udp_send_cb cb; + UV_UDP_SEND_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_udp_init(uv_loop_t*, uv_udp_t* handle); +UV_EXTERN int uv_udp_init_ex(uv_loop_t*, uv_udp_t* handle, unsigned int flags); +UV_EXTERN int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock); +UV_EXTERN int uv_udp_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int flags); + +UV_EXTERN int uv_udp_getsockname(const uv_udp_t* handle, + struct sockaddr* name, + int* namelen); +UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle, + const char* multicast_addr, + const char* interface_addr, + uv_membership membership); +UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on); +UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl); +UV_EXTERN int uv_udp_set_multicast_interface(uv_udp_t* handle, + const char* interface_addr); +UV_EXTERN int uv_udp_set_broadcast(uv_udp_t* handle, int on); +UV_EXTERN int uv_udp_set_ttl(uv_udp_t* handle, int ttl); +UV_EXTERN int uv_udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + uv_udp_send_cb send_cb); +UV_EXTERN int uv_udp_try_send(uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr); +UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle, + uv_alloc_cb alloc_cb, + uv_udp_recv_cb recv_cb); +UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle); + + +/* + * uv_tty_t is a subclass of uv_stream_t. + * + * Representing a stream for the console. + */ +struct uv_tty_s { + UV_HANDLE_FIELDS + UV_STREAM_FIELDS + UV_TTY_PRIVATE_FIELDS +}; + +typedef enum { + /* Initial/normal terminal mode */ + UV_TTY_MODE_NORMAL, + /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */ + UV_TTY_MODE_RAW, + /* Binary-safe I/O mode for IPC (Unix-only) */ + UV_TTY_MODE_IO +} uv_tty_mode_t; + +UV_EXTERN int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable); +UV_EXTERN int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode); +UV_EXTERN int uv_tty_reset_mode(void); +UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height); + +#ifdef __cplusplus +extern "C++" { + +inline int uv_tty_set_mode(uv_tty_t* handle, int mode) { + return uv_tty_set_mode(handle, static_cast(mode)); +} + +} +#endif + +UV_EXTERN uv_handle_type uv_guess_handle(uv_file file); + +/* + * uv_pipe_t is a subclass of uv_stream_t. + * + * Representing a pipe stream or pipe server. On Windows this is a Named + * Pipe. On Unix this is a Unix domain socket. + */ +struct uv_pipe_s { + UV_HANDLE_FIELDS + UV_STREAM_FIELDS + int ipc; /* non-zero if this pipe is used for passing handles */ + UV_PIPE_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc); +UV_EXTERN int uv_pipe_open(uv_pipe_t*, uv_file file); +UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name); +UV_EXTERN void uv_pipe_connect(uv_connect_t* req, + uv_pipe_t* handle, + const char* name, + uv_connect_cb cb); +UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle, + char* buffer, + size_t* size); +UV_EXTERN int uv_pipe_getpeername(const uv_pipe_t* handle, + char* buffer, + size_t* size); +UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count); +UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle); +UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle); + + +struct uv_poll_s { + UV_HANDLE_FIELDS + uv_poll_cb poll_cb; + UV_POLL_PRIVATE_FIELDS +}; + +enum uv_poll_event { + UV_READABLE = 1, + UV_WRITABLE = 2, + UV_DISCONNECT = 4 +}; + +UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd); +UV_EXTERN int uv_poll_init_socket(uv_loop_t* loop, + uv_poll_t* handle, + uv_os_sock_t socket); +UV_EXTERN int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb); +UV_EXTERN int uv_poll_stop(uv_poll_t* handle); + + +struct uv_prepare_s { + UV_HANDLE_FIELDS + UV_PREPARE_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_prepare_init(uv_loop_t*, uv_prepare_t* prepare); +UV_EXTERN int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb); +UV_EXTERN int uv_prepare_stop(uv_prepare_t* prepare); + + +struct uv_check_s { + UV_HANDLE_FIELDS + UV_CHECK_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_check_init(uv_loop_t*, uv_check_t* check); +UV_EXTERN int uv_check_start(uv_check_t* check, uv_check_cb cb); +UV_EXTERN int uv_check_stop(uv_check_t* check); + + +struct uv_idle_s { + UV_HANDLE_FIELDS + UV_IDLE_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_idle_init(uv_loop_t*, uv_idle_t* idle); +UV_EXTERN int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb); +UV_EXTERN int uv_idle_stop(uv_idle_t* idle); + + +struct uv_async_s { + UV_HANDLE_FIELDS + UV_ASYNC_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_async_init(uv_loop_t*, + uv_async_t* async, + uv_async_cb async_cb); +UV_EXTERN int uv_async_send(uv_async_t* async); + + +/* + * uv_timer_t is a subclass of uv_handle_t. + * + * Used to get woken up at a specified time in the future. + */ +struct uv_timer_s { + UV_HANDLE_FIELDS + UV_TIMER_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_timer_init(uv_loop_t*, uv_timer_t* handle); +UV_EXTERN int uv_timer_start(uv_timer_t* handle, + uv_timer_cb cb, + uint64_t timeout, + uint64_t repeat); +UV_EXTERN int uv_timer_stop(uv_timer_t* handle); +UV_EXTERN int uv_timer_again(uv_timer_t* handle); +UV_EXTERN void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat); +UV_EXTERN uint64_t uv_timer_get_repeat(const uv_timer_t* handle); + + +/* + * uv_getaddrinfo_t is a subclass of uv_req_t. + * + * Request object for uv_getaddrinfo. + */ +struct uv_getaddrinfo_s { + UV_REQ_FIELDS + /* read-only */ + uv_loop_t* loop; + /* struct addrinfo* addrinfo is marked as private, but it really isn't. */ + UV_GETADDRINFO_PRIVATE_FIELDS +}; + + +UV_EXTERN int uv_getaddrinfo(uv_loop_t* loop, + uv_getaddrinfo_t* req, + uv_getaddrinfo_cb getaddrinfo_cb, + const char* node, + const char* service, + const struct addrinfo* hints); +UV_EXTERN void uv_freeaddrinfo(struct addrinfo* ai); + + +/* +* uv_getnameinfo_t is a subclass of uv_req_t. +* +* Request object for uv_getnameinfo. +*/ +struct uv_getnameinfo_s { + UV_REQ_FIELDS + /* read-only */ + uv_loop_t* loop; + /* host and service are marked as private, but they really aren't. */ + UV_GETNAMEINFO_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_getnameinfo(uv_loop_t* loop, + uv_getnameinfo_t* req, + uv_getnameinfo_cb getnameinfo_cb, + const struct sockaddr* addr, + int flags); + + +/* uv_spawn() options. */ +typedef enum { + UV_IGNORE = 0x00, + UV_CREATE_PIPE = 0x01, + UV_INHERIT_FD = 0x02, + UV_INHERIT_STREAM = 0x04, + + /* + * When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and UV_WRITABLE_PIPE + * determine the direction of flow, from the child process' perspective. Both + * flags may be specified to create a duplex data stream. + */ + UV_READABLE_PIPE = 0x10, + UV_WRITABLE_PIPE = 0x20 +} uv_stdio_flags; + +typedef struct uv_stdio_container_s { + uv_stdio_flags flags; + + union { + uv_stream_t* stream; + int fd; + } data; +} uv_stdio_container_t; + +typedef struct uv_process_options_s { + uv_exit_cb exit_cb; /* Called after the process exits. */ + const char* file; /* Path to program to execute. */ + /* + * Command line arguments. args[0] should be the path to the program. On + * Windows this uses CreateProcess which concatenates the arguments into a + * string this can cause some strange errors. See the note at + * windows_verbatim_arguments. + */ + char** args; + /* + * This will be set as the environ variable in the subprocess. If this is + * NULL then the parents environ will be used. + */ + char** env; + /* + * If non-null this represents a directory the subprocess should execute + * in. Stands for current working directory. + */ + const char* cwd; + /* + * Various flags that control how uv_spawn() behaves. See the definition of + * `enum uv_process_flags` below. + */ + unsigned int flags; + /* + * The `stdio` field points to an array of uv_stdio_container_t structs that + * describe the file descriptors that will be made available to the child + * process. The convention is that stdio[0] points to stdin, fd 1 is used for + * stdout, and fd 2 is stderr. + * + * Note that on windows file descriptors greater than 2 are available to the + * child process only if the child processes uses the MSVCRT runtime. + */ + int stdio_count; + uv_stdio_container_t* stdio; + /* + * Libuv can change the child process' user/group id. This happens only when + * the appropriate bits are set in the flags fields. This is not supported on + * windows; uv_spawn() will fail and set the error to UV_ENOTSUP. + */ + uv_uid_t uid; + uv_gid_t gid; +} uv_process_options_t; + +/* + * These are the flags that can be used for the uv_process_options.flags field. + */ +enum uv_process_flags { + /* + * Set the child process' user id. The user id is supplied in the `uid` field + * of the options struct. This does not work on windows; setting this flag + * will cause uv_spawn() to fail. + */ + UV_PROCESS_SETUID = (1 << 0), + /* + * Set the child process' group id. The user id is supplied in the `gid` + * field of the options struct. This does not work on windows; setting this + * flag will cause uv_spawn() to fail. + */ + UV_PROCESS_SETGID = (1 << 1), + /* + * Do not wrap any arguments in quotes, or perform any other escaping, when + * converting the argument list into a command line string. This option is + * only meaningful on Windows systems. On Unix it is silently ignored. + */ + UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2), + /* + * Spawn the child process in a detached state - this will make it a process + * group leader, and will effectively enable the child to keep running after + * the parent exits. Note that the child process will still keep the + * parent's event loop alive unless the parent process calls uv_unref() on + * the child's process handle. + */ + UV_PROCESS_DETACHED = (1 << 3), + /* + * Hide the subprocess console window that would normally be created. This + * option is only meaningful on Windows systems. On Unix it is silently + * ignored. + */ + UV_PROCESS_WINDOWS_HIDE = (1 << 4) +}; + +/* + * uv_process_t is a subclass of uv_handle_t. + */ +struct uv_process_s { + UV_HANDLE_FIELDS + uv_exit_cb exit_cb; + int pid; + UV_PROCESS_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_spawn(uv_loop_t* loop, + uv_process_t* handle, + const uv_process_options_t* options); +UV_EXTERN int uv_process_kill(uv_process_t*, int signum); +UV_EXTERN int uv_kill(int pid, int signum); + + +/* + * uv_work_t is a subclass of uv_req_t. + */ +struct uv_work_s { + UV_REQ_FIELDS + uv_loop_t* loop; + uv_work_cb work_cb; + uv_after_work_cb after_work_cb; + UV_WORK_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_queue_work(uv_loop_t* loop, + uv_work_t* req, + uv_work_cb work_cb, + uv_after_work_cb after_work_cb); + +UV_EXTERN int uv_cancel(uv_req_t* req); + + +struct uv_cpu_info_s { + char* model; + int speed; + struct uv_cpu_times_s { + uint64_t user; + uint64_t nice; + uint64_t sys; + uint64_t idle; + uint64_t irq; + } cpu_times; +}; + +struct uv_interface_address_s { + char* name; + char phys_addr[6]; + int is_internal; + union { + struct sockaddr_in address4; + struct sockaddr_in6 address6; + } address; + union { + struct sockaddr_in netmask4; + struct sockaddr_in6 netmask6; + } netmask; +}; + +struct uv_passwd_s { + char* username; + long uid; + long gid; + char* shell; + char* homedir; +}; + +typedef enum { + UV_DIRENT_UNKNOWN, + UV_DIRENT_FILE, + UV_DIRENT_DIR, + UV_DIRENT_LINK, + UV_DIRENT_FIFO, + UV_DIRENT_SOCKET, + UV_DIRENT_CHAR, + UV_DIRENT_BLOCK +} uv_dirent_type_t; + +struct uv_dirent_s { + const char* name; + uv_dirent_type_t type; +}; + +UV_EXTERN char** uv_setup_args(int argc, char** argv); +UV_EXTERN int uv_get_process_title(char* buffer, size_t size); +UV_EXTERN int uv_set_process_title(const char* title); +UV_EXTERN int uv_resident_set_memory(size_t* rss); +UV_EXTERN int uv_uptime(double* uptime); + +typedef struct { + long tv_sec; + long tv_usec; +} uv_timeval_t; + +typedef struct { + uv_timeval_t ru_utime; /* user CPU time used */ + uv_timeval_t ru_stime; /* system CPU time used */ + uint64_t ru_maxrss; /* maximum resident set size */ + uint64_t ru_ixrss; /* integral shared memory size */ + uint64_t ru_idrss; /* integral unshared data size */ + uint64_t ru_isrss; /* integral unshared stack size */ + uint64_t ru_minflt; /* page reclaims (soft page faults) */ + uint64_t ru_majflt; /* page faults (hard page faults) */ + uint64_t ru_nswap; /* swaps */ + uint64_t ru_inblock; /* block input operations */ + uint64_t ru_oublock; /* block output operations */ + uint64_t ru_msgsnd; /* IPC messages sent */ + uint64_t ru_msgrcv; /* IPC messages received */ + uint64_t ru_nsignals; /* signals received */ + uint64_t ru_nvcsw; /* voluntary context switches */ + uint64_t ru_nivcsw; /* involuntary context switches */ +} uv_rusage_t; + +UV_EXTERN int uv_getrusage(uv_rusage_t* rusage); + +UV_EXTERN int uv_os_homedir(char* buffer, size_t* size); +UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size); +UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd); +UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd); + +UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); +UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); + +UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses, + int* count); +UV_EXTERN void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count); + + +typedef enum { + UV_FS_UNKNOWN = -1, + UV_FS_CUSTOM, + UV_FS_OPEN, + UV_FS_CLOSE, + UV_FS_READ, + UV_FS_WRITE, + UV_FS_SENDFILE, + UV_FS_STAT, + UV_FS_LSTAT, + UV_FS_FSTAT, + UV_FS_FTRUNCATE, + UV_FS_UTIME, + UV_FS_FUTIME, + UV_FS_ACCESS, + UV_FS_CHMOD, + UV_FS_FCHMOD, + UV_FS_FSYNC, + UV_FS_FDATASYNC, + UV_FS_UNLINK, + UV_FS_RMDIR, + UV_FS_MKDIR, + UV_FS_MKDTEMP, + UV_FS_RENAME, + UV_FS_SCANDIR, + UV_FS_LINK, + UV_FS_SYMLINK, + UV_FS_READLINK, + UV_FS_CHOWN, + UV_FS_FCHOWN, + UV_FS_REALPATH +} uv_fs_type; + +/* uv_fs_t is a subclass of uv_req_t. */ +struct uv_fs_s { + UV_REQ_FIELDS + uv_fs_type fs_type; + uv_loop_t* loop; + uv_fs_cb cb; + ssize_t result; + void* ptr; + const char* path; + uv_stat_t statbuf; /* Stores the result of uv_fs_stat() and uv_fs_fstat(). */ + UV_FS_PRIVATE_FIELDS +}; + +UV_EXTERN void uv_fs_req_cleanup(uv_fs_t* req); +UV_EXTERN int uv_fs_close(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_fs_cb cb); +UV_EXTERN int uv_fs_open(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + int mode, + uv_fs_cb cb); +UV_EXTERN int uv_fs_read(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t offset, + uv_fs_cb cb); +UV_EXTERN int uv_fs_unlink(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_write(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t offset, + uv_fs_cb cb); +UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int mode, + uv_fs_cb cb); +UV_EXTERN int uv_fs_mkdtemp(uv_loop_t* loop, + uv_fs_t* req, + const char* tpl, + uv_fs_cb cb); +UV_EXTERN int uv_fs_rmdir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_scandir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + uv_fs_cb cb); +UV_EXTERN int uv_fs_scandir_next(uv_fs_t* req, + uv_dirent_t* ent); +UV_EXTERN int uv_fs_stat(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_fstat(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_fs_cb cb); +UV_EXTERN int uv_fs_rename(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_fsync(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_fs_cb cb); +UV_EXTERN int uv_fs_fdatasync(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_fs_cb cb); +UV_EXTERN int uv_fs_ftruncate(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + int64_t offset, + uv_fs_cb cb); +UV_EXTERN int uv_fs_sendfile(uv_loop_t* loop, + uv_fs_t* req, + uv_file out_fd, + uv_file in_fd, + int64_t in_offset, + size_t length, + uv_fs_cb cb); +UV_EXTERN int uv_fs_access(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int mode, + uv_fs_cb cb); +UV_EXTERN int uv_fs_chmod(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int mode, + uv_fs_cb cb); +UV_EXTERN int uv_fs_utime(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + double atime, + double mtime, + uv_fs_cb cb); +UV_EXTERN int uv_fs_futime(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + double atime, + double mtime, + uv_fs_cb cb); +UV_EXTERN int uv_fs_lstat(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_link(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + uv_fs_cb cb); + +/* + * This flag can be used with uv_fs_symlink() on Windows to specify whether + * path argument points to a directory. + */ +#define UV_FS_SYMLINK_DIR 0x0001 + +/* + * This flag can be used with uv_fs_symlink() on Windows to specify whether + * the symlink is to be created using junction points. + */ +#define UV_FS_SYMLINK_JUNCTION 0x0002 + +UV_EXTERN int uv_fs_symlink(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + int flags, + uv_fs_cb cb); +UV_EXTERN int uv_fs_readlink(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_realpath(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_fchmod(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + int mode, + uv_fs_cb cb); +UV_EXTERN int uv_fs_chown(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb); +UV_EXTERN int uv_fs_fchown(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb); + + +enum uv_fs_event { + UV_RENAME = 1, + UV_CHANGE = 2 +}; + + +struct uv_fs_event_s { + UV_HANDLE_FIELDS + /* private */ + char* path; + UV_FS_EVENT_PRIVATE_FIELDS +}; + + +/* + * uv_fs_stat() based polling file watcher. + */ +struct uv_fs_poll_s { + UV_HANDLE_FIELDS + /* Private, don't touch. */ + void* poll_ctx; +}; + +UV_EXTERN int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle); +UV_EXTERN int uv_fs_poll_start(uv_fs_poll_t* handle, + uv_fs_poll_cb poll_cb, + const char* path, + unsigned int interval); +UV_EXTERN int uv_fs_poll_stop(uv_fs_poll_t* handle); +UV_EXTERN int uv_fs_poll_getpath(uv_fs_poll_t* handle, + char* buffer, + size_t* size); + + +struct uv_signal_s { + UV_HANDLE_FIELDS + uv_signal_cb signal_cb; + int signum; + UV_SIGNAL_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle); +UV_EXTERN int uv_signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum); +UV_EXTERN int uv_signal_stop(uv_signal_t* handle); + +UV_EXTERN void uv_loadavg(double avg[3]); + + +/* + * Flags to be passed to uv_fs_event_start(). + */ +enum uv_fs_event_flags { + /* + * By default, if the fs event watcher is given a directory name, we will + * watch for all events in that directory. This flags overrides this behavior + * and makes fs_event report only changes to the directory entry itself. This + * flag does not affect individual files watched. + * This flag is currently not implemented yet on any backend. + */ + UV_FS_EVENT_WATCH_ENTRY = 1, + + /* + * By default uv_fs_event will try to use a kernel interface such as inotify + * or kqueue to detect events. This may not work on remote filesystems such + * as NFS mounts. This flag makes fs_event fall back to calling stat() on a + * regular interval. + * This flag is currently not implemented yet on any backend. + */ + UV_FS_EVENT_STAT = 2, + + /* + * By default, event watcher, when watching directory, is not registering + * (is ignoring) changes in it's subdirectories. + * This flag will override this behaviour on platforms that support it. + */ + UV_FS_EVENT_RECURSIVE = 4 +}; + + +UV_EXTERN int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle); +UV_EXTERN int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* path, + unsigned int flags); +UV_EXTERN int uv_fs_event_stop(uv_fs_event_t* handle); +UV_EXTERN int uv_fs_event_getpath(uv_fs_event_t* handle, + char* buffer, + size_t* size); + +UV_EXTERN int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr); +UV_EXTERN int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr); + +UV_EXTERN int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size); +UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size); + +UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size); +UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst); + +UV_EXTERN int uv_exepath(char* buffer, size_t* size); + +UV_EXTERN int uv_cwd(char* buffer, size_t* size); + +UV_EXTERN int uv_chdir(const char* dir); + +UV_EXTERN uint64_t uv_get_free_memory(void); +UV_EXTERN uint64_t uv_get_total_memory(void); + +UV_EXTERN uint64_t uv_hrtime(void); + +UV_EXTERN void uv_disable_stdio_inheritance(void); + +UV_EXTERN int uv_dlopen(const char* filename, uv_lib_t* lib); +UV_EXTERN void uv_dlclose(uv_lib_t* lib); +UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr); +UV_EXTERN const char* uv_dlerror(const uv_lib_t* lib); + +UV_EXTERN int uv_mutex_init(uv_mutex_t* handle); +UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle); +UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle); +UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle); +UV_EXTERN void uv_mutex_unlock(uv_mutex_t* handle); + +UV_EXTERN int uv_rwlock_init(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_destroy(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_rdlock(uv_rwlock_t* rwlock); +UV_EXTERN int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_rdunlock(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_wrlock(uv_rwlock_t* rwlock); +UV_EXTERN int uv_rwlock_trywrlock(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_wrunlock(uv_rwlock_t* rwlock); + +UV_EXTERN int uv_sem_init(uv_sem_t* sem, unsigned int value); +UV_EXTERN void uv_sem_destroy(uv_sem_t* sem); +UV_EXTERN void uv_sem_post(uv_sem_t* sem); +UV_EXTERN void uv_sem_wait(uv_sem_t* sem); +UV_EXTERN int uv_sem_trywait(uv_sem_t* sem); + +UV_EXTERN int uv_cond_init(uv_cond_t* cond); +UV_EXTERN void uv_cond_destroy(uv_cond_t* cond); +UV_EXTERN void uv_cond_signal(uv_cond_t* cond); +UV_EXTERN void uv_cond_broadcast(uv_cond_t* cond); + +UV_EXTERN int uv_barrier_init(uv_barrier_t* barrier, unsigned int count); +UV_EXTERN void uv_barrier_destroy(uv_barrier_t* barrier); +UV_EXTERN int uv_barrier_wait(uv_barrier_t* barrier); + +UV_EXTERN void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex); +UV_EXTERN int uv_cond_timedwait(uv_cond_t* cond, + uv_mutex_t* mutex, + uint64_t timeout); + +UV_EXTERN void uv_once(uv_once_t* guard, void (*callback)(void)); + +UV_EXTERN int uv_key_create(uv_key_t* key); +UV_EXTERN void uv_key_delete(uv_key_t* key); +UV_EXTERN void* uv_key_get(uv_key_t* key); +UV_EXTERN void uv_key_set(uv_key_t* key, void* value); + +typedef void (*uv_thread_cb)(void* arg); + +UV_EXTERN int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg); +UV_EXTERN uv_thread_t uv_thread_self(void); +UV_EXTERN int uv_thread_join(uv_thread_t *tid); +UV_EXTERN int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2); + +/* The presence of these unions force similar struct layout. */ +#define XX(_, name) uv_ ## name ## _t name; +union uv_any_handle { + UV_HANDLE_TYPE_MAP(XX) +}; + +union uv_any_req { + UV_REQ_TYPE_MAP(XX) +}; +#undef XX + + +struct uv_loop_s { + /* User data - use this for whatever. */ + void* data; + /* Loop reference counting. */ + unsigned int active_handles; + void* handle_queue[2]; + void* active_reqs[2]; + /* Internal flag to signal loop stop. */ + unsigned int stop_flag; + UV_LOOP_PRIVATE_FIELDS +}; + + +/* Don't export the private CPP symbols. */ +#undef UV_HANDLE_TYPE_PRIVATE +#undef UV_REQ_TYPE_PRIVATE +#undef UV_REQ_PRIVATE_FIELDS +#undef UV_STREAM_PRIVATE_FIELDS +#undef UV_TCP_PRIVATE_FIELDS +#undef UV_PREPARE_PRIVATE_FIELDS +#undef UV_CHECK_PRIVATE_FIELDS +#undef UV_IDLE_PRIVATE_FIELDS +#undef UV_ASYNC_PRIVATE_FIELDS +#undef UV_TIMER_PRIVATE_FIELDS +#undef UV_GETADDRINFO_PRIVATE_FIELDS +#undef UV_GETNAMEINFO_PRIVATE_FIELDS +#undef UV_FS_REQ_PRIVATE_FIELDS +#undef UV_WORK_PRIVATE_FIELDS +#undef UV_FS_EVENT_PRIVATE_FIELDS +#undef UV_SIGNAL_PRIVATE_FIELDS +#undef UV_LOOP_PRIVATE_FIELDS +#undef UV_LOOP_PRIVATE_PLATFORM_FIELDS + +#ifdef __cplusplus +} +#endif +#endif /* UV_H */ diff --git a/src/fs-poll.c b/src/fs-poll.c new file mode 100644 index 0000000..ee73d5a --- /dev/null +++ b/src/fs-poll.c @@ -0,0 +1,256 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "uv-common.h" + +#include +#include +#include + +struct poll_ctx { + uv_fs_poll_t* parent_handle; /* NULL if parent has been stopped or closed */ + int busy_polling; + unsigned int interval; + uint64_t start_time; + uv_loop_t* loop; + uv_fs_poll_cb poll_cb; + uv_timer_t timer_handle; + uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */ + uv_stat_t statbuf; + char path[1]; /* variable length */ +}; + +static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b); +static void poll_cb(uv_fs_t* req); +static void timer_cb(uv_timer_t* timer); +static void timer_close_cb(uv_handle_t* handle); + +static uv_stat_t zero_statbuf; + + +int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL); + return 0; +} + + +int uv_fs_poll_start(uv_fs_poll_t* handle, + uv_fs_poll_cb cb, + const char* path, + unsigned int interval) { + struct poll_ctx* ctx; + uv_loop_t* loop; + size_t len; + int err; + + if (uv__is_active(handle)) + return 0; + + loop = handle->loop; + len = strlen(path); + ctx = uv__calloc(1, sizeof(*ctx) + len); + + if (ctx == NULL) + return UV_ENOMEM; + + ctx->loop = loop; + ctx->poll_cb = cb; + ctx->interval = interval ? interval : 1; + ctx->start_time = uv_now(loop); + ctx->parent_handle = handle; + memcpy(ctx->path, path, len + 1); + + err = uv_timer_init(loop, &ctx->timer_handle); + if (err < 0) + goto error; + + ctx->timer_handle.flags |= UV__HANDLE_INTERNAL; + uv__handle_unref(&ctx->timer_handle); + + err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb); + if (err < 0) + goto error; + + handle->poll_ctx = ctx; + uv__handle_start(handle); + + return 0; + +error: + uv__free(ctx); + return err; +} + + +int uv_fs_poll_stop(uv_fs_poll_t* handle) { + struct poll_ctx* ctx; + + if (!uv__is_active(handle)) + return 0; + + ctx = handle->poll_ctx; + assert(ctx != NULL); + assert(ctx->parent_handle != NULL); + ctx->parent_handle = NULL; + handle->poll_ctx = NULL; + + /* Close the timer if it's active. If it's inactive, there's a stat request + * in progress and poll_cb will take care of the cleanup. + */ + if (uv__is_active(&ctx->timer_handle)) + uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); + + uv__handle_stop(handle); + + return 0; +} + + +int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) { + struct poll_ctx* ctx; + size_t required_len; + + if (!uv__is_active(handle)) { + *size = 0; + return UV_EINVAL; + } + + ctx = handle->poll_ctx; + assert(ctx != NULL); + + required_len = strlen(ctx->path); + if (required_len >= *size) { + *size = required_len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, ctx->path, required_len); + *size = required_len; + buffer[required_len] = '\0'; + + return 0; +} + + +void uv__fs_poll_close(uv_fs_poll_t* handle) { + uv_fs_poll_stop(handle); +} + + +static void timer_cb(uv_timer_t* timer) { + struct poll_ctx* ctx; + + ctx = container_of(timer, struct poll_ctx, timer_handle); + assert(ctx->parent_handle != NULL); + assert(ctx->parent_handle->poll_ctx == ctx); + ctx->start_time = uv_now(ctx->loop); + + if (uv_fs_stat(ctx->loop, &ctx->fs_req, ctx->path, poll_cb)) + abort(); +} + + +static void poll_cb(uv_fs_t* req) { + uv_stat_t* statbuf; + struct poll_ctx* ctx; + uint64_t interval; + + ctx = container_of(req, struct poll_ctx, fs_req); + + if (ctx->parent_handle == NULL) { /* handle has been stopped or closed */ + uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); + uv_fs_req_cleanup(req); + return; + } + + if (req->result != 0) { + if (ctx->busy_polling != req->result) { + ctx->poll_cb(ctx->parent_handle, + req->result, + &ctx->statbuf, + &zero_statbuf); + ctx->busy_polling = req->result; + } + goto out; + } + + statbuf = &req->statbuf; + + if (ctx->busy_polling != 0) + if (ctx->busy_polling < 0 || !statbuf_eq(&ctx->statbuf, statbuf)) + ctx->poll_cb(ctx->parent_handle, 0, &ctx->statbuf, statbuf); + + ctx->statbuf = *statbuf; + ctx->busy_polling = 1; + +out: + uv_fs_req_cleanup(req); + + if (ctx->parent_handle == NULL) { /* handle has been stopped by callback */ + uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); + return; + } + + /* Reschedule timer, subtract the delay from doing the stat(). */ + interval = ctx->interval; + interval -= (uv_now(ctx->loop) - ctx->start_time) % interval; + + if (uv_timer_start(&ctx->timer_handle, timer_cb, interval, 0)) + abort(); +} + + +static void timer_close_cb(uv_handle_t* handle) { + uv__free(container_of(handle, struct poll_ctx, timer_handle)); +} + + +static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) { + return a->st_ctim.tv_nsec == b->st_ctim.tv_nsec + && a->st_mtim.tv_nsec == b->st_mtim.tv_nsec + && a->st_birthtim.tv_nsec == b->st_birthtim.tv_nsec + && a->st_ctim.tv_sec == b->st_ctim.tv_sec + && a->st_mtim.tv_sec == b->st_mtim.tv_sec + && a->st_birthtim.tv_sec == b->st_birthtim.tv_sec + && a->st_size == b->st_size + && a->st_mode == b->st_mode + && a->st_uid == b->st_uid + && a->st_gid == b->st_gid + && a->st_ino == b->st_ino + && a->st_dev == b->st_dev + && a->st_flags == b->st_flags + && a->st_gen == b->st_gen; +} + + +#if defined(_WIN32) + +#include "win/internal.h" +#include "win/handle-inl.h" + +void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) { + assert(handle->flags & UV__HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); +} + +#endif /* _WIN32 */ diff --git a/src/heap-inl.h b/src/heap-inl.h new file mode 100644 index 0000000..1e2ed60 --- /dev/null +++ b/src/heap-inl.h @@ -0,0 +1,245 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef UV_SRC_HEAP_H_ +#define UV_SRC_HEAP_H_ + +#include /* NULL */ + +#if defined(__GNUC__) +# define HEAP_EXPORT(declaration) __attribute__((unused)) static declaration +#else +# define HEAP_EXPORT(declaration) static declaration +#endif + +struct heap_node { + struct heap_node* left; + struct heap_node* right; + struct heap_node* parent; +}; + +/* A binary min heap. The usual properties hold: the root is the lowest + * element in the set, the height of the tree is at most log2(nodes) and + * it's always a complete binary tree. + * + * The heap function try hard to detect corrupted tree nodes at the cost + * of a minor reduction in performance. Compile with -DNDEBUG to disable. + */ +struct heap { + struct heap_node* min; + unsigned int nelts; +}; + +/* Return non-zero if a < b. */ +typedef int (*heap_compare_fn)(const struct heap_node* a, + const struct heap_node* b); + +/* Public functions. */ +HEAP_EXPORT(void heap_init(struct heap* heap)); +HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap)); +HEAP_EXPORT(void heap_insert(struct heap* heap, + struct heap_node* newnode, + heap_compare_fn less_than)); +HEAP_EXPORT(void heap_remove(struct heap* heap, + struct heap_node* node, + heap_compare_fn less_than)); +HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)); + +/* Implementation follows. */ + +HEAP_EXPORT(void heap_init(struct heap* heap)) { + heap->min = NULL; + heap->nelts = 0; +} + +HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap)) { + return heap->min; +} + +/* Swap parent with child. Child moves closer to the root, parent moves away. */ +static void heap_node_swap(struct heap* heap, + struct heap_node* parent, + struct heap_node* child) { + struct heap_node* sibling; + struct heap_node t; + + t = *parent; + *parent = *child; + *child = t; + + parent->parent = child; + if (child->left == child) { + child->left = parent; + sibling = child->right; + } else { + child->right = parent; + sibling = child->left; + } + if (sibling != NULL) + sibling->parent = child; + + if (parent->left != NULL) + parent->left->parent = parent; + if (parent->right != NULL) + parent->right->parent = parent; + + if (child->parent == NULL) + heap->min = child; + else if (child->parent->left == parent) + child->parent->left = child; + else + child->parent->right = child; +} + +HEAP_EXPORT(void heap_insert(struct heap* heap, + struct heap_node* newnode, + heap_compare_fn less_than)) { + struct heap_node** parent; + struct heap_node** child; + unsigned int path; + unsigned int n; + unsigned int k; + + newnode->left = NULL; + newnode->right = NULL; + newnode->parent = NULL; + + /* Calculate the path from the root to the insertion point. This is a min + * heap so we always insert at the left-most free node of the bottom row. + */ + path = 0; + for (k = 0, n = 1 + heap->nelts; n >= 2; k += 1, n /= 2) + path = (path << 1) | (n & 1); + + /* Now traverse the heap using the path we calculated in the previous step. */ + parent = child = &heap->min; + while (k > 0) { + parent = child; + if (path & 1) + child = &(*child)->right; + else + child = &(*child)->left; + path >>= 1; + k -= 1; + } + + /* Insert the new node. */ + newnode->parent = *parent; + *child = newnode; + heap->nelts += 1; + + /* Walk up the tree and check at each node if the heap property holds. + * It's a min heap so parent < child must be true. + */ + while (newnode->parent != NULL && less_than(newnode, newnode->parent)) + heap_node_swap(heap, newnode->parent, newnode); +} + +HEAP_EXPORT(void heap_remove(struct heap* heap, + struct heap_node* node, + heap_compare_fn less_than)) { + struct heap_node* smallest; + struct heap_node** max; + struct heap_node* child; + unsigned int path; + unsigned int k; + unsigned int n; + + if (heap->nelts == 0) + return; + + /* Calculate the path from the min (the root) to the max, the left-most node + * of the bottom row. + */ + path = 0; + for (k = 0, n = heap->nelts; n >= 2; k += 1, n /= 2) + path = (path << 1) | (n & 1); + + /* Now traverse the heap using the path we calculated in the previous step. */ + max = &heap->min; + while (k > 0) { + if (path & 1) + max = &(*max)->right; + else + max = &(*max)->left; + path >>= 1; + k -= 1; + } + + heap->nelts -= 1; + + /* Unlink the max node. */ + child = *max; + *max = NULL; + + if (child == node) { + /* We're removing either the max or the last node in the tree. */ + if (child == heap->min) { + heap->min = NULL; + } + return; + } + + /* Replace the to be deleted node with the max node. */ + child->left = node->left; + child->right = node->right; + child->parent = node->parent; + + if (child->left != NULL) { + child->left->parent = child; + } + + if (child->right != NULL) { + child->right->parent = child; + } + + if (node->parent == NULL) { + heap->min = child; + } else if (node->parent->left == node) { + node->parent->left = child; + } else { + node->parent->right = child; + } + + /* Walk down the subtree and check at each node if the heap property holds. + * It's a min heap so parent < child must be true. If the parent is bigger, + * swap it with the smallest child. + */ + for (;;) { + smallest = child; + if (child->left != NULL && less_than(child->left, smallest)) + smallest = child->left; + if (child->right != NULL && less_than(child->right, smallest)) + smallest = child->right; + if (smallest == child) + break; + heap_node_swap(heap, child, smallest); + } + + /* Walk up the subtree and check that each parent is less than the node + * this is required, because `max` node is not guaranteed to be the + * actual maximum in tree + */ + while (child->parent != NULL && less_than(child, child->parent)) + heap_node_swap(heap, child->parent, child); +} + +HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)) { + heap_remove(heap, heap->min, less_than); +} + +#undef HEAP_EXPORT + +#endif /* UV_SRC_HEAP_H_ */ diff --git a/src/inet.c b/src/inet.c new file mode 100644 index 0000000..da63a68 --- /dev/null +++ b/src/inet.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#include "uv.h" +#include "uv-common.h" + +#define UV__INET_ADDRSTRLEN 16 +#define UV__INET6_ADDRSTRLEN 46 + + +static int inet_ntop4(const unsigned char *src, char *dst, size_t size); +static int inet_ntop6(const unsigned char *src, char *dst, size_t size); +static int inet_pton4(const char *src, unsigned char *dst); +static int inet_pton6(const char *src, unsigned char *dst); + + +int uv_inet_ntop(int af, const void* src, char* dst, size_t size) { + switch (af) { + case AF_INET: + return (inet_ntop4(src, dst, size)); + case AF_INET6: + return (inet_ntop6(src, dst, size)); + default: + return UV_EAFNOSUPPORT; + } + /* NOTREACHED */ +} + + +static int inet_ntop4(const unsigned char *src, char *dst, size_t size) { + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[UV__INET_ADDRSTRLEN]; + int l; + + l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); + if (l <= 0 || (size_t) l >= size) { + return UV_ENOSPC; + } + strncpy(dst, tmp, size); + dst[size - 1] = '\0'; + return 0; +} + + +static int inet_ntop6(const unsigned char *src, char *dst, size_t size) { + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[UV__INET6_ADDRSTRLEN], *tp; + struct { int base, len; } best, cur; + unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < (int) sizeof(struct in6_addr); i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + best.len = 0; + cur.base = -1; + cur.len = 0; + for (i = 0; i < (int) ARRAY_SIZE(words); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (int) ARRAY_SIZE(words); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && (best.len == 6 || + (best.len == 7 && words[7] != 0x0001) || + (best.len == 5 && words[5] == 0xffff))) { + int err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)); + if (err) + return err; + tp += strlen(tp); + break; + } + tp += sprintf(tp, "%x", words[i]); + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + return UV_ENOSPC; + } + strcpy(dst, tmp); + return 0; +} + + +int uv_inet_pton(int af, const char* src, void* dst) { + if (src == NULL || dst == NULL) + return UV_EINVAL; + + switch (af) { + case AF_INET: + return (inet_pton4(src, dst)); + case AF_INET6: { + int len; + char tmp[UV__INET6_ADDRSTRLEN], *s, *p; + s = (char*) src; + p = strchr(src, '%'); + if (p != NULL) { + s = tmp; + len = p - src; + if (len > UV__INET6_ADDRSTRLEN-1) + return UV_EINVAL; + memcpy(s, src, len); + s[len] = '\0'; + } + return inet_pton6(s, dst); + } + default: + return UV_EAFNOSUPPORT; + } + /* NOTREACHED */ +} + + +static int inet_pton4(const char *src, unsigned char *dst) { + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + unsigned char tmp[sizeof(struct in_addr)], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + unsigned int nw = *tp * 10 + (pch - digits); + + if (saw_digit && *tp == 0) + return UV_EINVAL; + if (nw > 255) + return UV_EINVAL; + *tp = nw; + if (!saw_digit) { + if (++octets > 4) + return UV_EINVAL; + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return UV_EINVAL; + *++tp = 0; + saw_digit = 0; + } else + return UV_EINVAL; + } + if (octets < 4) + return UV_EINVAL; + memcpy(dst, tmp, sizeof(struct in_addr)); + return 0; +} + + +static int inet_pton6(const char *src, unsigned char *dst) { + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[sizeof(struct in6_addr)], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, seen_xdigits; + unsigned int val; + + memset((tp = tmp), '\0', sizeof tmp); + endp = tp + sizeof tmp; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return UV_EINVAL; + curtok = src; + seen_xdigits = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (++seen_xdigits > 4) + return UV_EINVAL; + continue; + } + if (ch == ':') { + curtok = src; + if (!seen_xdigits) { + if (colonp) + return UV_EINVAL; + colonp = tp; + continue; + } else if (*src == '\0') { + return UV_EINVAL; + } + if (tp + sizeof(uint16_t) > endp) + return UV_EINVAL; + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + seen_xdigits = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) { + int err = inet_pton4(curtok, tp); + if (err == 0) { + tp += sizeof(struct in_addr); + seen_xdigits = 0; + break; /*%< '\\0' was seen by inet_pton4(). */ + } + } + return UV_EINVAL; + } + if (seen_xdigits) { + if (tp + sizeof(uint16_t) > endp) + return UV_EINVAL; + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + if (tp == endp) + return UV_EINVAL; + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return UV_EINVAL; + memcpy(dst, tmp, sizeof tmp); + return 0; +} diff --git a/src/queue.h b/src/queue.h new file mode 100644 index 0000000..ff3540a --- /dev/null +++ b/src/queue.h @@ -0,0 +1,108 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef QUEUE_H_ +#define QUEUE_H_ + +#include + +typedef void *QUEUE[2]; + +/* Private macros. */ +#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0])) +#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1])) +#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q))) +#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q))) + +/* Public macros. */ +#define QUEUE_DATA(ptr, type, field) \ + ((type *) ((char *) (ptr) - offsetof(type, field))) + +/* Important note: mutating the list while QUEUE_FOREACH is + * iterating over its elements results in undefined behavior. + */ +#define QUEUE_FOREACH(q, h) \ + for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q)) + +#define QUEUE_EMPTY(q) \ + ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q)) + +#define QUEUE_HEAD(q) \ + (QUEUE_NEXT(q)) + +#define QUEUE_INIT(q) \ + do { \ + QUEUE_NEXT(q) = (q); \ + QUEUE_PREV(q) = (q); \ + } \ + while (0) + +#define QUEUE_ADD(h, n) \ + do { \ + QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \ + QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \ + QUEUE_PREV(h) = QUEUE_PREV(n); \ + QUEUE_PREV_NEXT(h) = (h); \ + } \ + while (0) + +#define QUEUE_SPLIT(h, q, n) \ + do { \ + QUEUE_PREV(n) = QUEUE_PREV(h); \ + QUEUE_PREV_NEXT(n) = (n); \ + QUEUE_NEXT(n) = (q); \ + QUEUE_PREV(h) = QUEUE_PREV(q); \ + QUEUE_PREV_NEXT(h) = (h); \ + QUEUE_PREV(q) = (n); \ + } \ + while (0) + +#define QUEUE_MOVE(h, n) \ + do { \ + if (QUEUE_EMPTY(h)) \ + QUEUE_INIT(n); \ + else { \ + QUEUE* q = QUEUE_HEAD(h); \ + QUEUE_SPLIT(h, q, n); \ + } \ + } \ + while (0) + +#define QUEUE_INSERT_HEAD(h, q) \ + do { \ + QUEUE_NEXT(q) = QUEUE_NEXT(h); \ + QUEUE_PREV(q) = (h); \ + QUEUE_NEXT_PREV(q) = (q); \ + QUEUE_NEXT(h) = (q); \ + } \ + while (0) + +#define QUEUE_INSERT_TAIL(h, q) \ + do { \ + QUEUE_NEXT(q) = (h); \ + QUEUE_PREV(q) = QUEUE_PREV(h); \ + QUEUE_PREV_NEXT(q) = (q); \ + QUEUE_PREV(h) = (q); \ + } \ + while (0) + +#define QUEUE_REMOVE(q) \ + do { \ + QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \ + QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \ + } \ + while (0) + +#endif /* QUEUE_H_ */ diff --git a/src/threadpool.c b/src/threadpool.c new file mode 100644 index 0000000..2c5152b --- /dev/null +++ b/src/threadpool.c @@ -0,0 +1,303 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv-common.h" + +#if !defined(_WIN32) +# include "unix/internal.h" +#else +# include "win/req-inl.h" +/* TODO(saghul): unify internal req functions */ +static void uv__req_init(uv_loop_t* loop, + uv_req_t* req, + uv_req_type type) { + uv_req_init(loop, req); + req->type = type; + uv__req_register(loop, req); +} +# define uv__req_init(loop, req, type) \ + uv__req_init((loop), (uv_req_t*)(req), (type)) +#endif + +#include + +#define MAX_THREADPOOL_SIZE 128 + +static uv_once_t once = UV_ONCE_INIT; +static uv_cond_t cond; +static uv_mutex_t mutex; +static unsigned int idle_threads; +static unsigned int nthreads; +static uv_thread_t* threads; +static uv_thread_t default_threads[4]; +static QUEUE exit_message; +static QUEUE wq; +static volatile int initialized; + + +static void uv__cancelled(struct uv__work* w) { + abort(); +} + + +/* To avoid deadlock with uv_cancel() it's crucial that the worker + * never holds the global mutex and the loop-local mutex at the same time. + */ +static void worker(void* arg) { + struct uv__work* w; + QUEUE* q; + + (void) arg; + + for (;;) { + uv_mutex_lock(&mutex); + + while (QUEUE_EMPTY(&wq)) { + idle_threads += 1; + uv_cond_wait(&cond, &mutex); + idle_threads -= 1; + } + + q = QUEUE_HEAD(&wq); + + if (q == &exit_message) + uv_cond_signal(&cond); + else { + QUEUE_REMOVE(q); + QUEUE_INIT(q); /* Signal uv_cancel() that the work req is + executing. */ + } + + uv_mutex_unlock(&mutex); + + if (q == &exit_message) + break; + + w = QUEUE_DATA(q, struct uv__work, wq); + w->work(w); + + uv_mutex_lock(&w->loop->wq_mutex); + w->work = NULL; /* Signal uv_cancel() that the work req is done + executing. */ + QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq); + uv_async_send(&w->loop->wq_async); + uv_mutex_unlock(&w->loop->wq_mutex); + } +} + + +static void post(QUEUE* q) { + uv_mutex_lock(&mutex); + QUEUE_INSERT_TAIL(&wq, q); + if (idle_threads > 0) + uv_cond_signal(&cond); + uv_mutex_unlock(&mutex); +} + + +#ifndef _WIN32 +UV_DESTRUCTOR(static void cleanup(void)) { + unsigned int i; + + if (initialized == 0) + return; + + post(&exit_message); + + for (i = 0; i < nthreads; i++) + if (uv_thread_join(threads + i)) + abort(); + + if (threads != default_threads) + uv__free(threads); + + uv_mutex_destroy(&mutex); + uv_cond_destroy(&cond); + + threads = NULL; + nthreads = 0; + initialized = 0; +} +#endif + + +static void init_once(void) { + unsigned int i; + const char* val; + + nthreads = ARRAY_SIZE(default_threads); + val = getenv("UV_THREADPOOL_SIZE"); + if (val != NULL) + nthreads = atoi(val); + if (nthreads == 0) + nthreads = 1; + if (nthreads > MAX_THREADPOOL_SIZE) + nthreads = MAX_THREADPOOL_SIZE; + + threads = default_threads; + if (nthreads > ARRAY_SIZE(default_threads)) { + threads = uv__malloc(nthreads * sizeof(threads[0])); + if (threads == NULL) { + nthreads = ARRAY_SIZE(default_threads); + threads = default_threads; + } + } + + if (uv_cond_init(&cond)) + abort(); + + if (uv_mutex_init(&mutex)) + abort(); + + QUEUE_INIT(&wq); + + for (i = 0; i < nthreads; i++) + if (uv_thread_create(threads + i, worker, NULL)) + abort(); + + initialized = 1; +} + + +void uv__work_submit(uv_loop_t* loop, + struct uv__work* w, + void (*work)(struct uv__work* w), + void (*done)(struct uv__work* w, int status)) { + uv_once(&once, init_once); + w->loop = loop; + w->work = work; + w->done = done; + post(&w->wq); +} + + +static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) { + int cancelled; + + uv_mutex_lock(&mutex); + uv_mutex_lock(&w->loop->wq_mutex); + + cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL; + if (cancelled) + QUEUE_REMOVE(&w->wq); + + uv_mutex_unlock(&w->loop->wq_mutex); + uv_mutex_unlock(&mutex); + + if (!cancelled) + return UV_EBUSY; + + w->work = uv__cancelled; + uv_mutex_lock(&loop->wq_mutex); + QUEUE_INSERT_TAIL(&loop->wq, &w->wq); + uv_async_send(&loop->wq_async); + uv_mutex_unlock(&loop->wq_mutex); + + return 0; +} + + +void uv__work_done(uv_async_t* handle) { + struct uv__work* w; + uv_loop_t* loop; + QUEUE* q; + QUEUE wq; + int err; + + loop = container_of(handle, uv_loop_t, wq_async); + uv_mutex_lock(&loop->wq_mutex); + QUEUE_MOVE(&loop->wq, &wq); + uv_mutex_unlock(&loop->wq_mutex); + + while (!QUEUE_EMPTY(&wq)) { + q = QUEUE_HEAD(&wq); + QUEUE_REMOVE(q); + + w = container_of(q, struct uv__work, wq); + err = (w->work == uv__cancelled) ? UV_ECANCELED : 0; + w->done(w, err); + } +} + + +static void uv__queue_work(struct uv__work* w) { + uv_work_t* req = container_of(w, uv_work_t, work_req); + + req->work_cb(req); +} + + +static void uv__queue_done(struct uv__work* w, int err) { + uv_work_t* req; + + req = container_of(w, uv_work_t, work_req); + uv__req_unregister(req->loop, req); + + if (req->after_work_cb == NULL) + return; + + req->after_work_cb(req, err); +} + + +int uv_queue_work(uv_loop_t* loop, + uv_work_t* req, + uv_work_cb work_cb, + uv_after_work_cb after_work_cb) { + if (work_cb == NULL) + return UV_EINVAL; + + uv__req_init(loop, req, UV_WORK); + req->loop = loop; + req->work_cb = work_cb; + req->after_work_cb = after_work_cb; + uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done); + return 0; +} + + +int uv_cancel(uv_req_t* req) { + struct uv__work* wreq; + uv_loop_t* loop; + + switch (req->type) { + case UV_FS: + loop = ((uv_fs_t*) req)->loop; + wreq = &((uv_fs_t*) req)->work_req; + break; + case UV_GETADDRINFO: + loop = ((uv_getaddrinfo_t*) req)->loop; + wreq = &((uv_getaddrinfo_t*) req)->work_req; + break; + case UV_GETNAMEINFO: + loop = ((uv_getnameinfo_t*) req)->loop; + wreq = &((uv_getnameinfo_t*) req)->work_req; + break; + case UV_WORK: + loop = ((uv_work_t*) req)->loop; + wreq = &((uv_work_t*) req)->work_req; + break; + default: + return UV_EINVAL; + } + + return uv__work_cancel(loop, req, wreq); +} diff --git a/src/unix/aix.c b/src/unix/aix.c new file mode 100644 index 0000000..652cd98 --- /dev/null +++ b/src/unix/aix.c @@ -0,0 +1,1154 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#ifdef HAVE_SYS_AHAFS_EVPRODS_H +#include +#endif + +#include +#include +#include +#include +#include + +#define RDWR_BUF_SIZE 4096 +#define EQ(a,b) (strcmp(a,b) == 0) + +int uv__platform_loop_init(uv_loop_t* loop) { + loop->fs_fd = -1; + + /* Passing maxfd of -1 should mean the limit is determined + * by the user's ulimit or the global limit as per the doc */ + loop->backend_fd = pollset_create(-1); + + if (loop->backend_fd == -1) + return -1; + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->fs_fd != -1) { + uv__close(loop->fs_fd); + loop->fs_fd = -1; + } + + if (loop->backend_fd != -1) { + pollset_destroy(loop->backend_fd); + loop->backend_fd = -1; + } +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct poll_ctl pc; + + pc.events = POLLIN; + pc.cmd = PS_MOD; /* Equivalent to PS_ADD if the fd is not in the pollset. */ + pc.fd = fd; + + if (pollset_ctl(loop->backend_fd, &pc, 1)) + return -errno; + + pc.cmd = PS_DELETE; + if (pollset_ctl(loop->backend_fd, &pc, 1)) + abort(); + + return 0; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + struct pollfd events[1024]; + struct pollfd pqry; + struct pollfd* pe; + struct poll_ctl pc; + QUEUE* q; + uv__io_t* w; + uint64_t base; + uint64_t diff; + int have_signals; + int nevents; + int count; + int nfds; + int i; + int rc; + int add_failed; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + assert(w->fd >= 0); + assert(w->fd < (int) loop->nwatchers); + + pc.events = w->pevents; + pc.fd = w->fd; + + add_failed = 0; + if (w->events == 0) { + pc.cmd = PS_ADD; + if (pollset_ctl(loop->backend_fd, &pc, 1)) { + if (errno != EINVAL) { + assert(0 && "Failed to add file descriptor (pc.fd) to pollset"); + abort(); + } + /* Check if the fd is already in the pollset */ + pqry.fd = pc.fd; + rc = pollset_query(loop->backend_fd, &pqry); + switch (rc) { + case -1: + assert(0 && "Failed to query pollset for file descriptor"); + abort(); + case 0: + assert(0 && "Pollset does not contain file descriptor"); + abort(); + } + /* If we got here then the pollset already contained the file descriptor even though + * we didn't think it should. This probably shouldn't happen, but we can continue. */ + add_failed = 1; + } + } + if (w->events != 0 || add_failed) { + /* Modify, potentially removing events -- need to delete then add. + * Could maybe mod if we knew for sure no events are removed, but + * content of w->events is handled above as not reliable (falls back) + * so may require a pollset_query() which would have to be pretty cheap + * compared to a PS_DELETE to be worth optimizing. Alternatively, could + * lazily remove events, squelching them in the mean time. */ + pc.cmd = PS_DELETE; + if (pollset_ctl(loop->backend_fd, &pc, 1)) { + assert(0 && "Failed to delete file descriptor (pc.fd) from pollset"); + abort(); + } + pc.cmd = PS_ADD; + if (pollset_ctl(loop->backend_fd, &pc, 1)) { + assert(0 && "Failed to add file descriptor (pc.fd) to pollset"); + abort(); + } + } + + w->events = w->pevents; + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + + for (;;) { + nfds = pollset_poll(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout); + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (nfds == 0) { + assert(timeout != -1); + return; + } + + if (nfds == -1) { + if (errno != EINTR) { + abort(); + } + + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + have_signals = 0; + nevents = 0; + + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + + for (i = 0; i < nfds; i++) { + pe = events + i; + pc.cmd = PS_DELETE; + pc.fd = pe->fd; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (pc.fd == -1) + continue; + + assert(pc.fd >= 0); + assert((unsigned) pc.fd < loop->nwatchers); + + w = loop->watchers[pc.fd]; + + if (w == NULL) { + /* File descriptor that we've stopped watching, disarm it. + * + * Ignore all errors because we may be racing with another thread + * when the file descriptor is closed. + */ + pollset_ctl(loop->backend_fd, &pc, 1); + continue; + } + + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->revents); + + nevents++; + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + diff = loop->time - base; + if (diff >= (uint64_t) timeout) + return; + + timeout -= diff; + } +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + uint64_t G = 1000000000; + timebasestruct_t t; + read_wall_time(&t, TIMEBASE_SZ); + time_base_to_time(&t, TIMEBASE_SZ); + return (uint64_t) t.tb_high * G + t.tb_low; +} + + +/* + * We could use a static buffer for the path manipulations that we need outside + * of the function, but this function could be called by multiple consumers and + * we don't want to potentially create a race condition in the use of snprintf. + * There is no direct way of getting the exe path in AIX - either through /procfs + * or through some libc APIs. The below approach is to parse the argv[0]'s pattern + * and use it in conjunction with PATH environment variable to craft one. + */ +int uv_exepath(char* buffer, size_t* size) { + int res; + char args[PATH_MAX]; + char abspath[PATH_MAX]; + size_t abspath_size; + struct procsinfo pi; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + pi.pi_pid = getpid(); + res = getargs(&pi, sizeof(pi), args, sizeof(args)); + if (res < 0) + return -EINVAL; + + /* + * Possibilities for args: + * i) an absolute path such as: /home/user/myprojects/nodejs/node + * ii) a relative path such as: ./node or ../myprojects/nodejs/node + * iii) a bare filename such as "node", after exporting PATH variable + * to its location. + */ + + /* Case i) and ii) absolute or relative paths */ + if (strchr(args, '/') != NULL) { + if (realpath(args, abspath) != abspath) + return -errno; + + abspath_size = strlen(abspath); + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + return 0; + } else { + /* Case iii). Search PATH environment variable */ + char trypath[PATH_MAX]; + char *clonedpath = NULL; + char *token = NULL; + char *path = getenv("PATH"); + + if (path == NULL) + return -EINVAL; + + clonedpath = uv__strdup(path); + if (clonedpath == NULL) + return -ENOMEM; + + token = strtok(clonedpath, ":"); + while (token != NULL) { + snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args); + if (realpath(trypath, abspath) == abspath) { + /* Check the match is executable */ + if (access(abspath, X_OK) == 0) { + abspath_size = strlen(abspath); + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + uv__free(clonedpath); + return 0; + } + } + token = strtok(NULL, ":"); + } + uv__free(clonedpath); + + /* Out of tokens (path entries), and no match found */ + return -EINVAL; + } +} + + +uint64_t uv_get_free_memory(void) { + perfstat_memory_total_t mem_total; + int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1); + if (result == -1) { + return 0; + } + return mem_total.real_free * 4096; +} + + +uint64_t uv_get_total_memory(void) { + perfstat_memory_total_t mem_total; + int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1); + if (result == -1) { + return 0; + } + return mem_total.real_total * 4096; +} + + +void uv_loadavg(double avg[3]) { + perfstat_cpu_total_t ps_total; + int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1); + if (result == -1) { + avg[0] = 0.; avg[1] = 0.; avg[2] = 0.; + return; + } + avg[0] = ps_total.loadavg[0] / (double)(1 << SBITS); + avg[1] = ps_total.loadavg[1] / (double)(1 << SBITS); + avg[2] = ps_total.loadavg[2] / (double)(1 << SBITS); +} + + +#ifdef HAVE_SYS_AHAFS_EVPRODS_H +static char *uv__rawname(char *cp) { + static char rawbuf[FILENAME_MAX+1]; + char *dp = rindex(cp, '/'); + + if (dp == 0) + return 0; + + *dp = 0; + strcpy(rawbuf, cp); + *dp = '/'; + strcat(rawbuf, "/r"); + strcat(rawbuf, dp+1); + return rawbuf; +} + + +/* + * Determine whether given pathname is a directory + * Returns 0 if the path is a directory, -1 if not + * + * Note: Opportunity here for more detailed error information but + * that requires changing callers of this function as well + */ +static int uv__path_is_a_directory(char* filename) { + struct stat statbuf; + + if (stat(filename, &statbuf) < 0) + return -1; /* failed: not a directory, assume it is a file */ + + if (statbuf.st_type == VDIR) + return 0; + + return -1; +} + + +/* + * Check whether AHAFS is mounted. + * Returns 0 if AHAFS is mounted, or an error code < 0 on failure + */ +static int uv__is_ahafs_mounted(void){ + int rv, i = 2; + struct vmount *p; + int size_multiplier = 10; + size_t siz = sizeof(struct vmount)*size_multiplier; + struct vmount *vmt; + const char *dev = "/aha"; + char *obj, *stub; + + p = uv__malloc(siz); + if (p == NULL) + return -errno; + + /* Retrieve all mounted filesystems */ + rv = mntctl(MCTL_QUERY, siz, (char*)p); + if (rv < 0) + return -errno; + if (rv == 0) { + /* buffer was not large enough, reallocate to correct size */ + siz = *(int*)p; + uv__free(p); + p = uv__malloc(siz); + if (p == NULL) + return -errno; + rv = mntctl(MCTL_QUERY, siz, (char*)p); + if (rv < 0) + return -errno; + } + + /* Look for dev in filesystems mount info */ + for(vmt = p, i = 0; i < rv; i++) { + obj = vmt2dataptr(vmt, VMT_OBJECT); /* device */ + stub = vmt2dataptr(vmt, VMT_STUB); /* mount point */ + + if (EQ(obj, dev) || EQ(uv__rawname(obj), dev) || EQ(stub, dev)) { + uv__free(p); /* Found a match */ + return 0; + } + vmt = (struct vmount *) ((char *) vmt + vmt->vmt_length); + } + + /* /aha is required for monitoring filesystem changes */ + return -1; +} + +/* + * Recursive call to mkdir() to create intermediate folders, if any + * Returns code from mkdir call + */ +static int uv__makedir_p(const char *dir) { + char tmp[256]; + char *p = NULL; + size_t len; + int err; + + snprintf(tmp, sizeof(tmp),"%s",dir); + len = strlen(tmp); + if (tmp[len - 1] == '/') + tmp[len - 1] = 0; + for (p = tmp + 1; *p; p++) { + if (*p == '/') { + *p = 0; + err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (err != 0 && errno != EEXIST) + return err; + *p = '/'; + } + } + return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +} + +/* + * Creates necessary subdirectories in the AIX Event Infrastructure + * file system for monitoring the object specified. + * Returns code from mkdir call + */ +static int uv__make_subdirs_p(const char *filename) { + char cmd[2048]; + char *p; + int rc = 0; + + /* Strip off the monitor file name */ + p = strrchr(filename, '/'); + + if (p == NULL) + return 0; + + if (uv__path_is_a_directory((char*)filename) == 0) { + sprintf(cmd, "/aha/fs/modDir.monFactory"); + } else { + sprintf(cmd, "/aha/fs/modFile.monFactory"); + } + + strncat(cmd, filename, (p - filename)); + rc = uv__makedir_p(cmd); + + if (rc == -1 && errno != EEXIST){ + return -errno; + } + + return rc; +} + + +/* + * Checks if /aha is mounted, then proceeds to set up the monitoring + * objects for the specified file. + * Returns 0 on success, or an error code < 0 on failure + */ +static int uv__setup_ahafs(const char* filename, int *fd) { + int rc = 0; + char mon_file_write_string[RDWR_BUF_SIZE]; + char mon_file[PATH_MAX]; + int file_is_directory = 0; /* -1 == NO, 0 == YES */ + + /* Create monitor file name for object */ + file_is_directory = uv__path_is_a_directory((char*)filename); + + if (file_is_directory == 0) + sprintf(mon_file, "/aha/fs/modDir.monFactory"); + else + sprintf(mon_file, "/aha/fs/modFile.monFactory"); + + if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX) + return -ENAMETOOLONG; + + /* Make the necessary subdirectories for the monitor file */ + rc = uv__make_subdirs_p(filename); + if (rc == -1 && errno != EEXIST) + return rc; + + strcat(mon_file, filename); + strcat(mon_file, ".mon"); + + *fd = 0; errno = 0; + + /* Open the monitor file, creating it if necessary */ + *fd = open(mon_file, O_CREAT|O_RDWR); + if (*fd < 0) + return -errno; + + /* Write out the monitoring specifications. + * In this case, we are monitoring for a state change event type + * CHANGED=YES + * We will be waiting in select call, rather than a read: + * WAIT_TYPE=WAIT_IN_SELECT + * We only want minimal information for files: + * INFO_LVL=1 + * For directories, we want more information to track what file + * caused the change + * INFO_LVL=2 + */ + + if (file_is_directory == 0) + sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=2"); + else + sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1"); + + rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1); + if (rc < 0) + return -errno; + + return 0; +} + +/* + * Skips a specified number of lines in the buffer passed in. + * Walks the buffer pointed to by p and attempts to skip n lines. + * Returns the total number of lines skipped + */ +static int uv__skip_lines(char **p, int n) { + int lines = 0; + + while(n > 0) { + *p = strchr(*p, '\n'); + if (!p) + return lines; + + (*p)++; + n--; + lines++; + } + return lines; +} + + +/* + * Parse the event occurrence data to figure out what event just occurred + * and take proper action. + * + * The buf is a pointer to the buffer containing the event occurrence data + * Returns 0 on success, -1 if unrecoverable error in parsing + * + */ +static int uv__parse_data(char *buf, int *events, uv_fs_event_t* handle) { + int evp_rc, i; + char *p; + char filename[PATH_MAX]; /* To be used when handling directories */ + + p = buf; + *events = 0; + + /* Clean the filename buffer*/ + for(i = 0; i < PATH_MAX; i++) { + filename[i] = 0; + } + i = 0; + + /* Check for BUF_WRAP */ + if (strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0) { + assert(0 && "Buffer wrap detected, Some event occurrences lost!"); + return 0; + } + + /* Since we are using the default buffer size (4K), and have specified + * INFO_LVL=1, we won't see any EVENT_OVERFLOW conditions. Applications + * should check for this keyword if they are using an INFO_LVL of 2 or + * higher, and have a buffer size of <= 4K + */ + + /* Skip to RC_FROM_EVPROD */ + if (uv__skip_lines(&p, 9) != 9) + return -1; + + if (sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1) { + if (uv__path_is_a_directory(handle->path) == 0) { /* Directory */ + if (evp_rc == AHAFS_MODDIR_UNMOUNT || evp_rc == AHAFS_MODDIR_REMOVE_SELF) { + /* The directory is no longer available for monitoring */ + *events = UV_RENAME; + handle->dir_filename = NULL; + } else { + /* A file was added/removed inside the directory */ + *events = UV_CHANGE; + + /* Get the EVPROD_INFO */ + if (uv__skip_lines(&p, 1) != 1) + return -1; + + /* Scan out the name of the file that triggered the event*/ + if (sscanf(p, "BEGIN_EVPROD_INFO\n%sEND_EVPROD_INFO", filename) == 1) { + handle->dir_filename = uv__strdup((const char*)&filename); + } else + return -1; + } + } else { /* Regular File */ + if (evp_rc == AHAFS_MODFILE_RENAME) + *events = UV_RENAME; + else + *events = UV_CHANGE; + } + } + else + return -1; + + return 0; +} + + +/* This is the internal callback */ +static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) { + char result_data[RDWR_BUF_SIZE]; + int bytes, rc = 0; + uv_fs_event_t* handle; + int events = 0; + char fname[PATH_MAX]; + char *p; + + handle = container_of(event_watch, uv_fs_event_t, event_watcher); + + /* At this point, we assume that polling has been done on the + * file descriptor, so we can just read the AHAFS event occurrence + * data and parse its results without having to block anything + */ + bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0); + + assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file"); + + /* Parse the data */ + if(bytes > 0) + rc = uv__parse_data(result_data, &events, handle); + + /* Unrecoverable error */ + if (rc == -1) + return; + + /* For directory changes, the name of the files that triggered the change + * are never absolute pathnames + */ + if (uv__path_is_a_directory(handle->path) == 0) { + p = handle->dir_filename; + } else { + p = strrchr(handle->path, '/'); + if (p == NULL) + p = handle->path; + else + p++; + } + strncpy(fname, p, sizeof(fname) - 1); + /* Just in case */ + fname[sizeof(fname) - 1] = '\0'; + + handle->cb(handle, fname, events, 0); +} +#endif + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { +#ifdef HAVE_SYS_AHAFS_EVPRODS_H + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + return 0; +#else + return -ENOSYS; +#endif +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* filename, + unsigned int flags) { +#ifdef HAVE_SYS_AHAFS_EVPRODS_H + int fd, rc, str_offset = 0; + char cwd[PATH_MAX]; + char absolute_path[PATH_MAX]; + char readlink_cwd[PATH_MAX]; + + + /* Figure out whether filename is absolute or not */ + if (filename[0] == '/') { + /* We have absolute pathname */ + snprintf(absolute_path, sizeof(absolute_path), "%s", filename); + } else { + /* We have a relative pathname, compose the absolute pathname */ + snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid()); + rc = readlink(cwd, readlink_cwd, sizeof(readlink_cwd) - 1); + if (rc < 0) + return rc; + /* readlink does not null terminate our string */ + readlink_cwd[rc] = '\0'; + + if (filename[0] == '.' && filename[1] == '/') + str_offset = 2; + + snprintf(absolute_path, sizeof(absolute_path), "%s%s", readlink_cwd, + filename + str_offset); + } + + if (uv__is_ahafs_mounted() < 0) /* /aha checks failed */ + return UV_ENOSYS; + + /* Setup ahafs */ + rc = uv__setup_ahafs((const char *)absolute_path, &fd); + if (rc != 0) + return rc; + + /* Setup/Initialize all the libuv routines */ + uv__handle_start(handle); + uv__io_init(&handle->event_watcher, uv__ahafs_event, fd); + handle->path = uv__strdup(filename); + handle->cb = cb; + + uv__io_start(handle->loop, &handle->event_watcher, POLLIN); + + return 0; +#else + return -ENOSYS; +#endif +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { +#ifdef HAVE_SYS_AHAFS_EVPRODS_H + if (!uv__is_active(handle)) + return 0; + + uv__io_close(handle->loop, &handle->event_watcher); + uv__handle_stop(handle); + + if (uv__path_is_a_directory(handle->path) == 0) { + uv__free(handle->dir_filename); + handle->dir_filename = NULL; + } + + uv__free(handle->path); + handle->path = NULL; + uv__close(handle->event_watcher.fd); + handle->event_watcher.fd = -1; + + return 0; +#else + return -ENOSYS; +#endif +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { +#ifdef HAVE_SYS_AHAFS_EVPRODS_H + uv_fs_event_stop(handle); +#else + UNREACHABLE(); +#endif +} + + +char** uv_setup_args(int argc, char** argv) { + return argv; +} + + +int uv_set_process_title(const char* title) { + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + if (buffer == NULL || size == 0) + return -EINVAL; + + buffer[0] = '\0'; + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + char pp[64]; + psinfo_t psinfo; + int err; + int fd; + + snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); + + fd = open(pp, O_RDONLY); + if (fd == -1) + return -errno; + + /* FIXME(bnoordhuis) Handle EINTR. */ + err = -EINVAL; + if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) { + *rss = (size_t)psinfo.pr_rssize * 1024; + err = 0; + } + uv__close(fd); + + return err; +} + + +int uv_uptime(double* uptime) { + struct utmp *utmp_buf; + size_t entries = 0; + time_t boot_time; + + utmpname(UTMP_FILE); + + setutent(); + + while ((utmp_buf = getutent()) != NULL) { + if (utmp_buf->ut_user[0] && utmp_buf->ut_type == USER_PROCESS) + ++entries; + if (utmp_buf->ut_type == BOOT_TIME) + boot_time = utmp_buf->ut_time; + } + + endutent(); + + if (boot_time == 0) + return -ENOSYS; + + *uptime = time(NULL) - boot_time; + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + uv_cpu_info_t* cpu_info; + perfstat_cpu_total_t ps_total; + perfstat_cpu_t* ps_cpus; + perfstat_id_t cpu_id; + int result, ncpus, idx = 0; + + result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1); + if (result == -1) { + return -ENOSYS; + } + + ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0); + if (result == -1) { + return -ENOSYS; + } + + ps_cpus = (perfstat_cpu_t*) uv__malloc(ncpus * sizeof(perfstat_cpu_t)); + if (!ps_cpus) { + return -ENOMEM; + } + + strcpy(cpu_id.name, FIRST_CPU); + result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus); + if (result == -1) { + uv__free(ps_cpus); + return -ENOSYS; + } + + *cpu_infos = (uv_cpu_info_t*) uv__malloc(ncpus * sizeof(uv_cpu_info_t)); + if (!*cpu_infos) { + uv__free(ps_cpus); + return -ENOMEM; + } + + *count = ncpus; + + cpu_info = *cpu_infos; + while (idx < ncpus) { + cpu_info->speed = (int)(ps_total.processorHZ / 1000000); + cpu_info->model = uv__strdup(ps_total.description); + cpu_info->cpu_times.user = ps_cpus[idx].user; + cpu_info->cpu_times.sys = ps_cpus[idx].sys; + cpu_info->cpu_times.idle = ps_cpus[idx].idle; + cpu_info->cpu_times.irq = ps_cpus[idx].wait; + cpu_info->cpu_times.nice = 0; + cpu_info++; + idx++; + } + + uv__free(ps_cpus); + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; ++i) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, + int* count) { + uv_interface_address_t* address; + int sockfd, size = 1; + struct ifconf ifc; + struct ifreq *ifr, *p, flg; + + *count = 0; + + if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) { + return -errno; + } + + if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) { + uv__close(sockfd); + return -errno; + } + + ifc.ifc_req = (struct ifreq*)uv__malloc(size); + ifc.ifc_len = size; + if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { + uv__close(sockfd); + return -errno; + } + +#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p)) + + /* Count all up and running ipv4/ipv6 addresses */ + ifr = ifc.ifc_req; + while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { + p = ifr; + ifr = (struct ifreq*) + ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); + + if (!(p->ifr_addr.sa_family == AF_INET6 || + p->ifr_addr.sa_family == AF_INET)) + continue; + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return -errno; + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + (*count)++; + } + + /* Alloc the return interface structs */ + *addresses = (uv_interface_address_t*) + uv__malloc(*count * sizeof(uv_interface_address_t)); + if (!(*addresses)) { + uv__close(sockfd); + return -ENOMEM; + } + address = *addresses; + + ifr = ifc.ifc_req; + while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { + p = ifr; + ifr = (struct ifreq*) + ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); + + if (!(p->ifr_addr.sa_family == AF_INET6 || + p->ifr_addr.sa_family == AF_INET)) + continue; + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return -ENOSYS; + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + /* All conditions above must match count loop */ + + address->name = uv__strdup(p->ifr_name); + + if (p->ifr_addr.sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); + } + + /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ + + address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; + + address++; + } + +#undef ADDR_SIZE + + uv__close(sockfd); + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; ++i) { + uv__free(addresses[i].name); + } + + uv__free(addresses); +} + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct pollfd* events; + uintptr_t i; + uintptr_t nfds; + struct poll_ctl pc; + + assert(loop->watchers != NULL); + + events = (struct pollfd*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + + if (events != NULL) + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].fd == fd) + events[i].fd = -1; + + /* Remove the file descriptor from the poll set */ + pc.events = 0; + pc.cmd = PS_DELETE; + pc.fd = fd; + if(loop->backend_fd >= 0) + pollset_ctl(loop->backend_fd, &pc, 1); +} diff --git a/src/unix/android-ifaddrs.c b/src/unix/android-ifaddrs.c new file mode 100644 index 0000000..30f681b --- /dev/null +++ b/src/unix/android-ifaddrs.c @@ -0,0 +1,703 @@ +/* +Copyright (c) 2013, Kenneth MacKay +Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016) +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. + +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. +*/ + +#include "android-ifaddrs.h" +#include "uv-common.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct NetlinkList +{ + struct NetlinkList *m_next; + struct nlmsghdr *m_data; + unsigned int m_size; +} NetlinkList; + +static int netlink_socket(void) +{ + struct sockaddr_nl l_addr; + + int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if(l_socket < 0) + { + return -1; + } + + memset(&l_addr, 0, sizeof(l_addr)); + l_addr.nl_family = AF_NETLINK; + if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0) + { + close(l_socket); + return -1; + } + + return l_socket; +} + +static int netlink_send(int p_socket, int p_request) +{ + char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))]; + + struct nlmsghdr *l_hdr; + struct rtgenmsg *l_msg; + struct sockaddr_nl l_addr; + + memset(l_buffer, 0, sizeof(l_buffer)); + + l_hdr = (struct nlmsghdr *)l_buffer; + l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr); + + l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg)); + l_hdr->nlmsg_type = p_request; + l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; + l_hdr->nlmsg_pid = 0; + l_hdr->nlmsg_seq = p_socket; + l_msg->rtgen_family = AF_UNSPEC; + + memset(&l_addr, 0, sizeof(l_addr)); + l_addr.nl_family = AF_NETLINK; + return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr))); +} + +static int netlink_recv(int p_socket, void *p_buffer, size_t p_len) +{ + struct sockaddr_nl l_addr; + struct msghdr l_msg; + + struct iovec l_iov; + l_iov.iov_base = p_buffer; + l_iov.iov_len = p_len; + + for(;;) + { + int l_result; + l_msg.msg_name = (void *)&l_addr; + l_msg.msg_namelen = sizeof(l_addr); + l_msg.msg_iov = &l_iov; + l_msg.msg_iovlen = 1; + l_msg.msg_control = NULL; + l_msg.msg_controllen = 0; + l_msg.msg_flags = 0; + l_result = recvmsg(p_socket, &l_msg, 0); + + if(l_result < 0) + { + if(errno == EINTR) + { + continue; + } + return -2; + } + + /* Buffer was too small */ + if(l_msg.msg_flags & MSG_TRUNC) + { + return -1; + } + return l_result; + } +} + +static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done) +{ + size_t l_size = 4096; + void *l_buffer = NULL; + + for(;;) + { + int l_read; + + uv__free(l_buffer); + l_buffer = uv__malloc(l_size); + if (l_buffer == NULL) + { + return NULL; + } + + l_read = netlink_recv(p_socket, l_buffer, l_size); + *p_size = l_read; + if(l_read == -2) + { + uv__free(l_buffer); + return NULL; + } + if(l_read >= 0) + { + pid_t l_pid = getpid(); + struct nlmsghdr *l_hdr; + for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read)) + { + if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + { + continue; + } + + if(l_hdr->nlmsg_type == NLMSG_DONE) + { + *p_done = 1; + break; + } + + if(l_hdr->nlmsg_type == NLMSG_ERROR) + { + uv__free(l_buffer); + return NULL; + } + } + return l_buffer; + } + + l_size *= 2; + } +} + +static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size) +{ + NetlinkList *l_item = uv__malloc(sizeof(NetlinkList)); + if (l_item == NULL) + { + return NULL; + } + + l_item->m_next = NULL; + l_item->m_data = p_data; + l_item->m_size = p_size; + return l_item; +} + +static void freeResultList(NetlinkList *p_list) +{ + NetlinkList *l_cur; + while(p_list) + { + l_cur = p_list; + p_list = p_list->m_next; + uv__free(l_cur->m_data); + uv__free(l_cur); + } +} + +static NetlinkList *getResultList(int p_socket, int p_request) +{ + int l_size; + int l_done; + NetlinkList *l_list; + NetlinkList *l_end; + + if(netlink_send(p_socket, p_request) < 0) + { + return NULL; + } + + l_list = NULL; + l_end = NULL; + + l_done = 0; + while(!l_done) + { + NetlinkList *l_item; + + struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); + /* Error */ + if(!l_hdr) + { + freeResultList(l_list); + return NULL; + } + + l_item = newListItem(l_hdr, l_size); + if (!l_item) + { + freeResultList(l_list); + return NULL; + } + if(!l_list) + { + l_list = l_item; + } + else + { + l_end->m_next = l_item; + } + l_end = l_item; + } + return l_list; +} + +static size_t maxSize(size_t a, size_t b) +{ + return (a > b ? a : b); +} + +static size_t calcAddrLen(sa_family_t p_family, int p_dataSize) +{ + switch(p_family) + { + case AF_INET: + return sizeof(struct sockaddr_in); + case AF_INET6: + return sizeof(struct sockaddr_in6); + case AF_PACKET: + return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize); + default: + return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize); + } +} + +static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size) +{ + switch(p_family) + { + case AF_INET: + memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size); + break; + case AF_INET6: + memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size); + break; + case AF_PACKET: + memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size); + ((struct sockaddr_ll*)p_dest)->sll_halen = p_size; + break; + default: + memcpy(p_dest->sa_data, p_data, p_size); + break; + } + p_dest->sa_family = p_family; +} + +static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry) +{ + if(!*p_resultList) + { + *p_resultList = p_entry; + } + else + { + struct ifaddrs *l_cur = *p_resultList; + while(l_cur->ifa_next) + { + l_cur = l_cur->ifa_next; + } + l_cur->ifa_next = p_entry; + } +} + +static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList) +{ + struct ifaddrs *l_entry; + + char *l_index; + char *l_name; + char *l_addr; + char *l_data; + + struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr); + + size_t l_nameSize = 0; + size_t l_addrSize = 0; + size_t l_dataSize = 0; + + size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); + struct rtattr *l_rta; + for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + switch(l_rta->rta_type) + { + case IFLA_ADDRESS: + case IFLA_BROADCAST: + l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize)); + break; + case IFLA_IFNAME: + l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); + break; + case IFLA_STATS: + l_dataSize += NLMSG_ALIGN(l_rtaSize); + break; + default: + break; + } + } + + l_entry = uv__malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize); + if (l_entry == NULL) + { + return -1; + } + memset(l_entry, 0, sizeof(struct ifaddrs)); + l_entry->ifa_name = ""; + + l_index = ((char *)l_entry) + sizeof(struct ifaddrs); + l_name = l_index + sizeof(int); + l_addr = l_name + l_nameSize; + l_data = l_addr + l_addrSize; + + /* Save the interface index so we can look it up when handling the + * addresses. + */ + memcpy(l_index, &l_info->ifi_index, sizeof(int)); + + l_entry->ifa_flags = l_info->ifi_flags; + + l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); + for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + void *l_rtaData = RTA_DATA(l_rta); + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + switch(l_rta->rta_type) + { + case IFLA_ADDRESS: + case IFLA_BROADCAST: + { + size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize); + makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); + ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index; + ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type; + if(l_rta->rta_type == IFLA_ADDRESS) + { + l_entry->ifa_addr = (struct sockaddr *)l_addr; + } + else + { + l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; + } + l_addr += NLMSG_ALIGN(l_addrLen); + break; + } + case IFLA_IFNAME: + strncpy(l_name, l_rtaData, l_rtaDataSize); + l_name[l_rtaDataSize] = '\0'; + l_entry->ifa_name = l_name; + break; + case IFLA_STATS: + memcpy(l_data, l_rtaData, l_rtaDataSize); + l_entry->ifa_data = l_data; + break; + default: + break; + } + } + + addToEnd(p_resultList, l_entry); + return 0; +} + +static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks) +{ + int l_num = 0; + struct ifaddrs *l_cur = *p_links; + while(l_cur && l_num < p_numLinks) + { + char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs); + int l_index; + memcpy(&l_index, l_indexPtr, sizeof(int)); + if(l_index == p_index) + { + return l_cur; + } + + l_cur = l_cur->ifa_next; + ++l_num; + } + return NULL; +} + +static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks) +{ + struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr); + struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks); + + size_t l_nameSize = 0; + size_t l_addrSize = 0; + + int l_addedNetmask = 0; + + size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); + struct rtattr *l_rta; + struct ifaddrs *l_entry; + + char *l_name; + char *l_addr; + + for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + if(l_info->ifa_family == AF_PACKET) + { + continue; + } + + switch(l_rta->rta_type) + { + case IFA_ADDRESS: + case IFA_LOCAL: + if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) + { + /* Make room for netmask */ + l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); + l_addedNetmask = 1; + } + case IFA_BROADCAST: + l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); + break; + case IFA_LABEL: + l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); + break; + default: + break; + } + } + + l_entry = uv__malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize); + if (l_entry == NULL) + { + return -1; + } + memset(l_entry, 0, sizeof(struct ifaddrs)); + l_entry->ifa_name = (l_interface ? l_interface->ifa_name : ""); + + l_name = ((char *)l_entry) + sizeof(struct ifaddrs); + l_addr = l_name + l_nameSize; + + l_entry->ifa_flags = l_info->ifa_flags; + if(l_interface) + { + l_entry->ifa_flags |= l_interface->ifa_flags; + } + + l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); + for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + void *l_rtaData = RTA_DATA(l_rta); + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + switch(l_rta->rta_type) + { + case IFA_ADDRESS: + case IFA_BROADCAST: + case IFA_LOCAL: + { + size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize); + makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); + if(l_info->ifa_family == AF_INET6) + { + if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) + { + ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index; + } + } + + /* Apparently in a point-to-point network IFA_ADDRESS contains + * the dest address and IFA_LOCAL contains the local address + */ + if(l_rta->rta_type == IFA_ADDRESS) + { + if(l_entry->ifa_addr) + { + l_entry->ifa_dstaddr = (struct sockaddr *)l_addr; + } + else + { + l_entry->ifa_addr = (struct sockaddr *)l_addr; + } + } + else if(l_rta->rta_type == IFA_LOCAL) + { + if(l_entry->ifa_addr) + { + l_entry->ifa_dstaddr = l_entry->ifa_addr; + } + l_entry->ifa_addr = (struct sockaddr *)l_addr; + } + else + { + l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; + } + l_addr += NLMSG_ALIGN(l_addrLen); + break; + } + case IFA_LABEL: + strncpy(l_name, l_rtaData, l_rtaDataSize); + l_name[l_rtaDataSize] = '\0'; + l_entry->ifa_name = l_name; + break; + default: + break; + } + } + + if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6)) + { + unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128); + unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen); + char l_mask[16] = {0}; + unsigned i; + for(i=0; i<(l_prefix/8); ++i) + { + l_mask[i] = 0xff; + } + if(l_prefix % 8) + { + l_mask[i] = 0xff << (8 - (l_prefix % 8)); + } + + makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8); + l_entry->ifa_netmask = (struct sockaddr *)l_addr; + } + + addToEnd(p_resultList, l_entry); + return 0; +} + +static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList) +{ + + int l_numLinks = 0; + pid_t l_pid = getpid(); + for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) + { + unsigned int l_nlsize = p_netlinkList->m_size; + struct nlmsghdr *l_hdr; + for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) + { + if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + { + continue; + } + + if(l_hdr->nlmsg_type == NLMSG_DONE) + { + break; + } + + if(l_hdr->nlmsg_type == RTM_NEWLINK) + { + if(interpretLink(l_hdr, p_resultList) == -1) + { + return -1; + } + ++l_numLinks; + } + } + } + return l_numLinks; +} + +static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks) +{ + pid_t l_pid = getpid(); + for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) + { + unsigned int l_nlsize = p_netlinkList->m_size; + struct nlmsghdr *l_hdr; + for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) + { + if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + { + continue; + } + + if(l_hdr->nlmsg_type == NLMSG_DONE) + { + break; + } + + if(l_hdr->nlmsg_type == RTM_NEWADDR) + { + if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1) + { + return -1; + } + } + } + } + return 0; +} + +int getifaddrs(struct ifaddrs **ifap) +{ + int l_socket; + int l_result; + int l_numLinks; + NetlinkList *l_linkResults; + NetlinkList *l_addrResults; + + if(!ifap) + { + return -1; + } + *ifap = NULL; + + l_socket = netlink_socket(); + if(l_socket < 0) + { + return -1; + } + + l_linkResults = getResultList(l_socket, RTM_GETLINK); + if(!l_linkResults) + { + close(l_socket); + return -1; + } + + l_addrResults = getResultList(l_socket, RTM_GETADDR); + if(!l_addrResults) + { + close(l_socket); + freeResultList(l_linkResults); + return -1; + } + + l_result = 0; + l_numLinks = interpretLinks(l_socket, l_linkResults, ifap); + if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1) + { + l_result = -1; + } + + freeResultList(l_linkResults); + freeResultList(l_addrResults); + close(l_socket); + return l_result; +} + +void freeifaddrs(struct ifaddrs *ifa) +{ + struct ifaddrs *l_cur; + while(ifa) + { + l_cur = ifa; + ifa = ifa->ifa_next; + uv__free(l_cur); + } +} diff --git a/src/unix/async.c b/src/unix/async.c new file mode 100644 index 0000000..393cdeb --- /dev/null +++ b/src/unix/async.c @@ -0,0 +1,290 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +/* This file contains both the uv__async internal infrastructure and the + * user-facing uv_async_t functions. + */ + +#include "uv.h" +#include "internal.h" +#include "atomic-ops.h" + +#include +#include /* snprintf() */ +#include +#include +#include +#include + +static void uv__async_event(uv_loop_t* loop, + struct uv__async* w, + unsigned int nevents); +static int uv__async_eventfd(void); + + +int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { + int err; + + err = uv__async_start(loop, &loop->async_watcher, uv__async_event); + if (err) + return err; + + uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC); + handle->async_cb = async_cb; + handle->pending = 0; + + QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue); + uv__handle_start(handle); + + return 0; +} + + +int uv_async_send(uv_async_t* handle) { + /* Do a cheap read first. */ + if (ACCESS_ONCE(int, handle->pending) != 0) + return 0; + + if (cmpxchgi(&handle->pending, 0, 1) == 0) + uv__async_send(&handle->loop->async_watcher); + + return 0; +} + + +void uv__async_close(uv_async_t* handle) { + QUEUE_REMOVE(&handle->queue); + uv__handle_stop(handle); +} + + +static void uv__async_event(uv_loop_t* loop, + struct uv__async* w, + unsigned int nevents) { + QUEUE queue; + QUEUE* q; + uv_async_t* h; + + QUEUE_MOVE(&loop->async_handles, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + h = QUEUE_DATA(q, uv_async_t, queue); + + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&loop->async_handles, q); + + if (cmpxchgi(&h->pending, 1, 0) == 0) + continue; + + if (h->async_cb == NULL) + continue; + h->async_cb(h); + } +} + + +static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + struct uv__async* wa; + char buf[1024]; + unsigned n; + ssize_t r; + + n = 0; + for (;;) { + r = read(w->fd, buf, sizeof(buf)); + + if (r > 0) + n += r; + + if (r == sizeof(buf)) + continue; + + if (r != -1) + break; + + if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + + if (errno == EINTR) + continue; + + abort(); + } + + wa = container_of(w, struct uv__async, io_watcher); + +#if defined(__linux__) + if (wa->wfd == -1) { + uint64_t val; + assert(n == sizeof(val)); + memcpy(&val, buf, sizeof(val)); /* Avoid alignment issues. */ + wa->cb(loop, wa, val); + return; + } +#endif + + wa->cb(loop, wa, n); +} + + +void uv__async_send(struct uv__async* wa) { + const void* buf; + ssize_t len; + int fd; + int r; + + buf = ""; + len = 1; + fd = wa->wfd; + +#if defined(__linux__) + if (fd == -1) { + static const uint64_t val = 1; + buf = &val; + len = sizeof(val); + fd = wa->io_watcher.fd; /* eventfd */ + } +#endif + + do + r = write(fd, buf, len); + while (r == -1 && errno == EINTR); + + if (r == len) + return; + + if (r == -1) + if (errno == EAGAIN || errno == EWOULDBLOCK) + return; + + abort(); +} + + +void uv__async_init(struct uv__async* wa) { + wa->io_watcher.fd = -1; + wa->wfd = -1; +} + + +int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) { + int pipefd[2]; + int err; + + if (wa->io_watcher.fd != -1) + return 0; + + err = uv__async_eventfd(); + if (err >= 0) { + pipefd[0] = err; + pipefd[1] = -1; + } + else if (err == -ENOSYS) { + err = uv__make_pipe(pipefd, UV__F_NONBLOCK); +#if defined(__linux__) + /* Save a file descriptor by opening one of the pipe descriptors as + * read/write through the procfs. That file descriptor can then + * function as both ends of the pipe. + */ + if (err == 0) { + char buf[32]; + int fd; + + snprintf(buf, sizeof(buf), "/proc/self/fd/%d", pipefd[0]); + fd = uv__open_cloexec(buf, O_RDWR); + if (fd >= 0) { + uv__close(pipefd[0]); + uv__close(pipefd[1]); + pipefd[0] = fd; + pipefd[1] = fd; + } + } +#endif + } + + if (err < 0) + return err; + + uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]); + uv__io_start(loop, &wa->io_watcher, POLLIN); + wa->wfd = pipefd[1]; + wa->cb = cb; + + return 0; +} + + +void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) { + if (wa->io_watcher.fd == -1) + return; + + if (wa->wfd != -1) { + if (wa->wfd != wa->io_watcher.fd) + uv__close(wa->wfd); + wa->wfd = -1; + } + + uv__io_stop(loop, &wa->io_watcher, POLLIN); + uv__close(wa->io_watcher.fd); + wa->io_watcher.fd = -1; +} + + +static int uv__async_eventfd() { +#if defined(__linux__) + static int no_eventfd2; + static int no_eventfd; + int fd; + + if (no_eventfd2) + goto skip_eventfd2; + + fd = uv__eventfd2(0, UV__EFD_CLOEXEC | UV__EFD_NONBLOCK); + if (fd != -1) + return fd; + + if (errno != ENOSYS) + return -errno; + + no_eventfd2 = 1; + +skip_eventfd2: + + if (no_eventfd) + goto skip_eventfd; + + fd = uv__eventfd(0); + if (fd != -1) { + uv__cloexec(fd, 1); + uv__nonblock(fd, 1); + return fd; + } + + if (errno != ENOSYS) + return -errno; + + no_eventfd = 1; + +skip_eventfd: + +#endif + + return -ENOSYS; +} diff --git a/src/unix/atomic-ops.h b/src/unix/atomic-ops.h new file mode 100644 index 0000000..815e355 --- /dev/null +++ b/src/unix/atomic-ops.h @@ -0,0 +1,88 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef UV_ATOMIC_OPS_H_ +#define UV_ATOMIC_OPS_H_ + +#include "internal.h" /* UV_UNUSED */ + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#include +#define __sync_val_compare_and_swap(p, o, n) atomic_cas_ptr(p, o, n) +#endif + +UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)); +UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)); +UV_UNUSED(static void cpu_relax(void)); + +/* Prefer hand-rolled assembly over the gcc builtins because the latter also + * issue full memory barriers. + */ +UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { +#if defined(__i386__) || defined(__x86_64__) + int out; + __asm__ __volatile__ ("lock; cmpxchg %2, %1;" + : "=a" (out), "+m" (*(volatile int*) ptr) + : "r" (newval), "0" (oldval) + : "memory"); + return out; +#elif defined(_AIX) && defined(__xlC__) + const int out = (*(volatile int*) ptr); + __compare_and_swap(ptr, &oldval, newval); + return out; +#elif defined(__MVS__) + return __plo_CS(ptr, (unsigned int*) ptr, + oldval, (unsigned int*) &newval); +#else + return __sync_val_compare_and_swap(ptr, oldval, newval); +#endif +} + +UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) { +#if defined(__i386__) || defined(__x86_64__) + long out; + __asm__ __volatile__ ("lock; cmpxchg %2, %1;" + : "=a" (out), "+m" (*(volatile long*) ptr) + : "r" (newval), "0" (oldval) + : "memory"); + return out; +#elif defined(_AIX) && defined(__xlC__) + const long out = (*(volatile int*) ptr); +# if defined(__64BIT__) + __compare_and_swaplp(ptr, &oldval, newval); +# else + __compare_and_swap(ptr, &oldval, newval); +# endif /* if defined(__64BIT__) */ + return out; +#elif defined (__MVS__) +# ifdef _LP64 + return __plo_CSGR(ptr, (unsigned long long*) ptr, + oldval, (unsigned long long*) &newval); +# else + return __plo_CS(ptr, (unsigned int*) ptr, + oldval, (unsigned int*) &newval); +# endif +#else + return __sync_val_compare_and_swap(ptr, oldval, newval); +#endif +} + +UV_UNUSED(static void cpu_relax(void)) { +#if defined(__i386__) || defined(__x86_64__) + __asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */ +#endif +} + +#endif /* UV_ATOMIC_OPS_H_ */ diff --git a/src/unix/core.c b/src/unix/core.c new file mode 100644 index 0000000..d88fc1d --- /dev/null +++ b/src/unix/core.c @@ -0,0 +1,1238 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include /* NULL */ +#include /* printf */ +#include +#include /* strerror */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* INT_MAX, PATH_MAX, IOV_MAX */ +#include /* writev */ +#include /* getrusage */ +#include + +#ifdef __sun +# include +# include +# include +#endif + +#ifdef __APPLE__ +# include /* _NSGetExecutablePath */ +# include +# if defined(O_CLOEXEC) +# define UV__O_CLOEXEC O_CLOEXEC +# endif +#endif + +#if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) +# include +# include +# include +# define UV__O_CLOEXEC O_CLOEXEC +# if defined(__FreeBSD__) && __FreeBSD__ >= 10 +# define uv__accept4 accept4 +# define UV__SOCK_NONBLOCK SOCK_NONBLOCK +# define UV__SOCK_CLOEXEC SOCK_CLOEXEC +# endif +# if !defined(F_DUP2FD_CLOEXEC) && defined(_F_DUP2FD_CLOEXEC) +# define F_DUP2FD_CLOEXEC _F_DUP2FD_CLOEXEC +# endif +#endif + +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 +# include /* for dlsym */ +#endif + +#if defined(__MVS__) +#include +#endif + +static int uv__run_pending(uv_loop_t* loop); + +/* Verify that uv_buf_t is ABI-compatible with struct iovec. */ +STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec)); +STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->base) == + sizeof(((struct iovec*) 0)->iov_base)); +STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->len) == + sizeof(((struct iovec*) 0)->iov_len)); +STATIC_ASSERT(offsetof(uv_buf_t, base) == offsetof(struct iovec, iov_base)); +STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len)); + + +uint64_t uv_hrtime(void) { + return uv__hrtime(UV_CLOCK_PRECISE); +} + + +void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + + handle->flags |= UV_CLOSING; + handle->close_cb = close_cb; + + switch (handle->type) { + case UV_NAMED_PIPE: + uv__pipe_close((uv_pipe_t*)handle); + break; + + case UV_TTY: + uv__stream_close((uv_stream_t*)handle); + break; + + case UV_TCP: + uv__tcp_close((uv_tcp_t*)handle); + break; + + case UV_UDP: + uv__udp_close((uv_udp_t*)handle); + break; + + case UV_PREPARE: + uv__prepare_close((uv_prepare_t*)handle); + break; + + case UV_CHECK: + uv__check_close((uv_check_t*)handle); + break; + + case UV_IDLE: + uv__idle_close((uv_idle_t*)handle); + break; + + case UV_ASYNC: + uv__async_close((uv_async_t*)handle); + break; + + case UV_TIMER: + uv__timer_close((uv_timer_t*)handle); + break; + + case UV_PROCESS: + uv__process_close((uv_process_t*)handle); + break; + + case UV_FS_EVENT: + uv__fs_event_close((uv_fs_event_t*)handle); + break; + + case UV_POLL: + uv__poll_close((uv_poll_t*)handle); + break; + + case UV_FS_POLL: + uv__fs_poll_close((uv_fs_poll_t*)handle); + break; + + case UV_SIGNAL: + uv__signal_close((uv_signal_t*) handle); + /* Signal handles may not be closed immediately. The signal code will */ + /* itself close uv__make_close_pending whenever appropriate. */ + return; + + default: + assert(0); + } + + uv__make_close_pending(handle); +} + +int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { + int r; + int fd; + socklen_t len; + + if (handle == NULL || value == NULL) + return -EINVAL; + + if (handle->type == UV_TCP || handle->type == UV_NAMED_PIPE) + fd = uv__stream_fd((uv_stream_t*) handle); + else if (handle->type == UV_UDP) + fd = ((uv_udp_t *) handle)->io_watcher.fd; + else + return -ENOTSUP; + + len = sizeof(*value); + + if (*value == 0) + r = getsockopt(fd, SOL_SOCKET, optname, value, &len); + else + r = setsockopt(fd, SOL_SOCKET, optname, (const void*) value, len); + + if (r < 0) + return -errno; + + return 0; +} + +void uv__make_close_pending(uv_handle_t* handle) { + assert(handle->flags & UV_CLOSING); + assert(!(handle->flags & UV_CLOSED)); + handle->next_closing = handle->loop->closing_handles; + handle->loop->closing_handles = handle; +} + +int uv__getiovmax(void) { +#if defined(IOV_MAX) + return IOV_MAX; +#elif defined(_SC_IOV_MAX) + static int iovmax = -1; + if (iovmax == -1) { + iovmax = sysconf(_SC_IOV_MAX); + /* On some embedded devices (arm-linux-uclibc based ip camera), + * sysconf(_SC_IOV_MAX) can not get the correct value. The return + * value is -1 and the errno is EINPROGRESS. Degrade the value to 1. + */ + if (iovmax == -1) iovmax = 1; + } + return iovmax; +#else + return 1024; +#endif +} + + +static void uv__finish_close(uv_handle_t* handle) { + /* Note: while the handle is in the UV_CLOSING state now, it's still possible + * for it to be active in the sense that uv__is_active() returns true. + * A good example is when the user calls uv_shutdown(), immediately followed + * by uv_close(). The handle is considered active at this point because the + * completion of the shutdown req is still pending. + */ + assert(handle->flags & UV_CLOSING); + assert(!(handle->flags & UV_CLOSED)); + handle->flags |= UV_CLOSED; + + switch (handle->type) { + case UV_PREPARE: + case UV_CHECK: + case UV_IDLE: + case UV_ASYNC: + case UV_TIMER: + case UV_PROCESS: + case UV_FS_EVENT: + case UV_FS_POLL: + case UV_POLL: + case UV_SIGNAL: + break; + + case UV_NAMED_PIPE: + case UV_TCP: + case UV_TTY: + uv__stream_destroy((uv_stream_t*)handle); + break; + + case UV_UDP: + uv__udp_finish_close((uv_udp_t*)handle); + break; + + default: + assert(0); + break; + } + + uv__handle_unref(handle); + QUEUE_REMOVE(&handle->handle_queue); + + if (handle->close_cb) { + handle->close_cb(handle); + } +} + + +static void uv__run_closing_handles(uv_loop_t* loop) { + uv_handle_t* p; + uv_handle_t* q; + + p = loop->closing_handles; + loop->closing_handles = NULL; + + while (p) { + q = p->next_closing; + uv__finish_close(p); + p = q; + } +} + + +int uv_is_closing(const uv_handle_t* handle) { + return uv__is_closing(handle); +} + + +int uv_backend_fd(const uv_loop_t* loop) { + return loop->backend_fd; +} + + +int uv_backend_timeout(const uv_loop_t* loop) { + if (loop->stop_flag != 0) + return 0; + + if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop)) + return 0; + + if (!QUEUE_EMPTY(&loop->idle_handles)) + return 0; + + if (!QUEUE_EMPTY(&loop->pending_queue)) + return 0; + + if (loop->closing_handles) + return 0; + + return uv__next_timeout(loop); +} + + +static int uv__loop_alive(const uv_loop_t* loop) { + return uv__has_active_handles(loop) || + uv__has_active_reqs(loop) || + loop->closing_handles != NULL; +} + + +int uv_loop_alive(const uv_loop_t* loop) { + return uv__loop_alive(loop); +} + + +int uv_run(uv_loop_t* loop, uv_run_mode mode) { + int timeout; + int r; + int ran_pending; + + r = uv__loop_alive(loop); + if (!r) + uv__update_time(loop); + + while (r != 0 && loop->stop_flag == 0) { + uv__update_time(loop); + uv__run_timers(loop); + ran_pending = uv__run_pending(loop); + uv__run_idle(loop); + uv__run_prepare(loop); + + timeout = 0; + if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) + timeout = uv_backend_timeout(loop); + + uv__io_poll(loop, timeout); + uv__run_check(loop); + uv__run_closing_handles(loop); + + if (mode == UV_RUN_ONCE) { + /* UV_RUN_ONCE implies forward progress: at least one callback must have + * been invoked when it returns. uv__io_poll() can return without doing + * I/O (meaning: no callbacks) when its timeout expires - which means we + * have pending timers that satisfy the forward progress constraint. + * + * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from + * the check. + */ + uv__update_time(loop); + uv__run_timers(loop); + } + + r = uv__loop_alive(loop); + if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT) + break; + } + + /* The if statement lets gcc compile it to a conditional store. Avoids + * dirtying a cache line. + */ + if (loop->stop_flag != 0) + loop->stop_flag = 0; + + return r; +} + + +void uv_update_time(uv_loop_t* loop) { + uv__update_time(loop); +} + + +int uv_is_active(const uv_handle_t* handle) { + return uv__is_active(handle); +} + + +/* Open a socket in non-blocking close-on-exec mode, atomically if possible. */ +int uv__socket(int domain, int type, int protocol) { + int sockfd; + int err; + +#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC) + sockfd = socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); + if (sockfd != -1) + return sockfd; + + if (errno != EINVAL) + return -errno; +#endif + + sockfd = socket(domain, type, protocol); + if (sockfd == -1) + return -errno; + + err = uv__nonblock(sockfd, 1); + if (err == 0) + err = uv__cloexec(sockfd, 1); + + if (err) { + uv__close(sockfd); + return err; + } + +#if defined(SO_NOSIGPIPE) + { + int on = 1; + setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on)); + } +#endif + + return sockfd; +} + +/* get a file pointer to a file in read-only and close-on-exec mode */ +FILE* uv__open_file(const char* path) { + int fd; + FILE* fp; + + fd = uv__open_cloexec(path, O_RDONLY); + if (fd < 0) + return NULL; + + fp = fdopen(fd, "r"); + if (fp == NULL) + uv__close(fd); + + return fp; +} + + +int uv__accept(int sockfd) { + int peerfd; + int err; + + assert(sockfd >= 0); + + while (1) { +#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) + static int no_accept4; + + if (no_accept4) + goto skip; + + peerfd = uv__accept4(sockfd, + NULL, + NULL, + UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC); + if (peerfd != -1) + return peerfd; + + if (errno == EINTR) + continue; + + if (errno != ENOSYS) + return -errno; + + no_accept4 = 1; +skip: +#endif + + peerfd = accept(sockfd, NULL, NULL); + if (peerfd == -1) { + if (errno == EINTR) + continue; + return -errno; + } + + err = uv__cloexec(peerfd, 1); + if (err == 0) + err = uv__nonblock(peerfd, 1); + + if (err) { + uv__close(peerfd); + return err; + } + + return peerfd; + } +} + + +int uv__close_nocheckstdio(int fd) { + int saved_errno; + int rc; + + assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */ + + saved_errno = errno; + rc = close(fd); + if (rc == -1) { + rc = -errno; + if (rc == -EINTR || rc == -EINPROGRESS) + rc = 0; /* The close is in progress, not an error. */ + errno = saved_errno; + } + + return rc; +} + + +int uv__close(int fd) { + assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ + return uv__close_nocheckstdio(fd); +} + + +int uv__nonblock_ioctl(int fd, int set) { + int r; + + do + r = ioctl(fd, FIONBIO, &set); + while (r == -1 && errno == EINTR); + + if (r) + return -errno; + + return 0; +} + + +int uv__cloexec_ioctl(int fd, int set) { + int r; + + do + r = ioctl(fd, set ? FIOCLEX : FIONCLEX); + while (r == -1 && errno == EINTR); + + if (r) + return -errno; + + return 0; +} + + +int uv__nonblock_fcntl(int fd, int set) { + int flags; + int r; + + do + r = fcntl(fd, F_GETFL); + while (r == -1 && errno == EINTR); + + if (r == -1) + return -errno; + + /* Bail out now if already set/clear. */ + if (!!(r & O_NONBLOCK) == !!set) + return 0; + + if (set) + flags = r | O_NONBLOCK; + else + flags = r & ~O_NONBLOCK; + + do + r = fcntl(fd, F_SETFL, flags); + while (r == -1 && errno == EINTR); + + if (r) + return -errno; + + return 0; +} + + +int uv__cloexec_fcntl(int fd, int set) { + int flags; + int r; + + do + r = fcntl(fd, F_GETFD); + while (r == -1 && errno == EINTR); + + if (r == -1) + return -errno; + + /* Bail out now if already set/clear. */ + if (!!(r & FD_CLOEXEC) == !!set) + return 0; + + if (set) + flags = r | FD_CLOEXEC; + else + flags = r & ~FD_CLOEXEC; + + do + r = fcntl(fd, F_SETFD, flags); + while (r == -1 && errno == EINTR); + + if (r) + return -errno; + + return 0; +} + + +/* This function is not execve-safe, there is a race window + * between the call to dup() and fcntl(FD_CLOEXEC). + */ +int uv__dup(int fd) { + int err; + + fd = dup(fd); + + if (fd == -1) + return -errno; + + err = uv__cloexec(fd, 1); + if (err) { + uv__close(fd); + return err; + } + + return fd; +} + + +ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { + struct cmsghdr* cmsg; + ssize_t rc; + int* pfd; + int* end; +#if defined(__linux__) + static int no_msg_cmsg_cloexec; + if (no_msg_cmsg_cloexec == 0) { + rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */ + if (rc != -1) + return rc; + if (errno != EINVAL) + return -errno; + rc = recvmsg(fd, msg, flags); + if (rc == -1) + return -errno; + no_msg_cmsg_cloexec = 1; + } else { + rc = recvmsg(fd, msg, flags); + } +#else + rc = recvmsg(fd, msg, flags); +#endif + if (rc == -1) + return -errno; + if (msg->msg_controllen == 0) + return rc; + for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) + if (cmsg->cmsg_type == SCM_RIGHTS) + for (pfd = (int*) CMSG_DATA(cmsg), + end = (int*) ((char*) cmsg + cmsg->cmsg_len); + pfd < end; + pfd += 1) + uv__cloexec(*pfd, 1); + return rc; +} + + +int uv_cwd(char* buffer, size_t* size) { + if (buffer == NULL || size == NULL) + return -EINVAL; + + if (getcwd(buffer, *size) == NULL) + return -errno; + + *size = strlen(buffer); + if (*size > 1 && buffer[*size - 1] == '/') { + buffer[*size-1] = '\0'; + (*size)--; + } + + return 0; +} + + +int uv_chdir(const char* dir) { + if (chdir(dir)) + return -errno; + + return 0; +} + + +void uv_disable_stdio_inheritance(void) { + int fd; + + /* Set the CLOEXEC flag on all open descriptors. Unconditionally try the + * first 16 file descriptors. After that, bail out after the first error. + */ + for (fd = 0; ; fd++) + if (uv__cloexec(fd, 1) && fd > 15) + break; +} + + +int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) { + int fd_out; + + switch (handle->type) { + case UV_TCP: + case UV_NAMED_PIPE: + case UV_TTY: + fd_out = uv__stream_fd((uv_stream_t*) handle); + break; + + case UV_UDP: + fd_out = ((uv_udp_t *) handle)->io_watcher.fd; + break; + + case UV_POLL: + fd_out = ((uv_poll_t *) handle)->io_watcher.fd; + break; + + default: + return -EINVAL; + } + + if (uv__is_closing(handle) || fd_out == -1) + return -EBADF; + + *fd = fd_out; + return 0; +} + + +static int uv__run_pending(uv_loop_t* loop) { + QUEUE* q; + QUEUE pq; + uv__io_t* w; + + if (QUEUE_EMPTY(&loop->pending_queue)) + return 0; + + QUEUE_MOVE(&loop->pending_queue, &pq); + + while (!QUEUE_EMPTY(&pq)) { + q = QUEUE_HEAD(&pq); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + w = QUEUE_DATA(q, uv__io_t, pending_queue); + w->cb(loop, w, POLLOUT); + } + + return 1; +} + + +static unsigned int next_power_of_two(unsigned int val) { + val -= 1; + val |= val >> 1; + val |= val >> 2; + val |= val >> 4; + val |= val >> 8; + val |= val >> 16; + val += 1; + return val; +} + +static void maybe_resize(uv_loop_t* loop, unsigned int len) { + uv__io_t** watchers; + void* fake_watcher_list; + void* fake_watcher_count; + unsigned int nwatchers; + unsigned int i; + + if (len <= loop->nwatchers) + return; + + /* Preserve fake watcher list and count at the end of the watchers */ + if (loop->watchers != NULL) { + fake_watcher_list = loop->watchers[loop->nwatchers]; + fake_watcher_count = loop->watchers[loop->nwatchers + 1]; + } else { + fake_watcher_list = NULL; + fake_watcher_count = NULL; + } + + nwatchers = next_power_of_two(len + 2) - 2; + watchers = uv__realloc(loop->watchers, + (nwatchers + 2) * sizeof(loop->watchers[0])); + + if (watchers == NULL) + abort(); + for (i = loop->nwatchers; i < nwatchers; i++) + watchers[i] = NULL; + watchers[nwatchers] = fake_watcher_list; + watchers[nwatchers + 1] = fake_watcher_count; + + loop->watchers = watchers; + loop->nwatchers = nwatchers; +} + + +void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { + assert(cb != NULL); + assert(fd >= -1); + QUEUE_INIT(&w->pending_queue); + QUEUE_INIT(&w->watcher_queue); + w->cb = cb; + w->fd = fd; + w->events = 0; + w->pevents = 0; + +#if defined(UV_HAVE_KQUEUE) + w->rcount = 0; + w->wcount = 0; +#endif /* defined(UV_HAVE_KQUEUE) */ +} + + +void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); + assert(0 != events); + assert(w->fd >= 0); + assert(w->fd < INT_MAX); + + w->pevents |= events; + maybe_resize(loop, w->fd + 1); + +#if !defined(__sun) + /* The event ports backend needs to rearm all file descriptors on each and + * every tick of the event loop but the other backends allow us to + * short-circuit here if the event mask is unchanged. + */ + if (w->events == w->pevents) { + if (w->events == 0 && !QUEUE_EMPTY(&w->watcher_queue)) { + QUEUE_REMOVE(&w->watcher_queue); + QUEUE_INIT(&w->watcher_queue); + } + return; + } +#endif + + if (QUEUE_EMPTY(&w->watcher_queue)) + QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); + + if (loop->watchers[w->fd] == NULL) { + loop->watchers[w->fd] = w; + loop->nfds++; + } +} + + +void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); + assert(0 != events); + + if (w->fd == -1) + return; + + assert(w->fd >= 0); + + /* Happens when uv__io_stop() is called on a handle that was never started. */ + if ((unsigned) w->fd >= loop->nwatchers) + return; + + w->pevents &= ~events; + + if (w->pevents == 0) { + QUEUE_REMOVE(&w->watcher_queue); + QUEUE_INIT(&w->watcher_queue); + + if (loop->watchers[w->fd] != NULL) { + assert(loop->watchers[w->fd] == w); + assert(loop->nfds > 0); + loop->watchers[w->fd] = NULL; + loop->nfds--; + w->events = 0; + } + } + else if (QUEUE_EMPTY(&w->watcher_queue)) + QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); +} + + +void uv__io_close(uv_loop_t* loop, uv__io_t* w) { + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); + QUEUE_REMOVE(&w->pending_queue); + + /* Remove stale events for this file descriptor */ + uv__platform_invalidate_fd(loop, w->fd); +} + + +void uv__io_feed(uv_loop_t* loop, uv__io_t* w) { + if (QUEUE_EMPTY(&w->pending_queue)) + QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue); +} + + +int uv__io_active(const uv__io_t* w, unsigned int events) { + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); + assert(0 != events); + return 0 != (w->pevents & events); +} + + +int uv_getrusage(uv_rusage_t* rusage) { + struct rusage usage; + + if (getrusage(RUSAGE_SELF, &usage)) + return -errno; + + rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec; + rusage->ru_utime.tv_usec = usage.ru_utime.tv_usec; + + rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec; + rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec; + +#if !defined(__MVS__) + rusage->ru_maxrss = usage.ru_maxrss; + rusage->ru_ixrss = usage.ru_ixrss; + rusage->ru_idrss = usage.ru_idrss; + rusage->ru_isrss = usage.ru_isrss; + rusage->ru_minflt = usage.ru_minflt; + rusage->ru_majflt = usage.ru_majflt; + rusage->ru_nswap = usage.ru_nswap; + rusage->ru_inblock = usage.ru_inblock; + rusage->ru_oublock = usage.ru_oublock; + rusage->ru_msgsnd = usage.ru_msgsnd; + rusage->ru_msgrcv = usage.ru_msgrcv; + rusage->ru_nsignals = usage.ru_nsignals; + rusage->ru_nvcsw = usage.ru_nvcsw; + rusage->ru_nivcsw = usage.ru_nivcsw; +#endif + + return 0; +} + + +int uv__open_cloexec(const char* path, int flags) { + int err; + int fd; + +#if defined(UV__O_CLOEXEC) + static int no_cloexec; + + if (!no_cloexec) { + fd = open(path, flags | UV__O_CLOEXEC); + if (fd != -1) + return fd; + + if (errno != EINVAL) + return -errno; + + /* O_CLOEXEC not supported. */ + no_cloexec = 1; + } +#endif + + fd = open(path, flags); + if (fd == -1) + return -errno; + + err = uv__cloexec(fd, 1); + if (err) { + uv__close(fd); + return err; + } + + return fd; +} + + +int uv__dup2_cloexec(int oldfd, int newfd) { + int r; +#if defined(__FreeBSD__) && __FreeBSD__ >= 10 + r = dup3(oldfd, newfd, O_CLOEXEC); + if (r == -1) + return -errno; + return r; +#elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC) + r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd); + if (r != -1) + return r; + if (errno != EINVAL) + return -errno; + /* Fall through. */ +#elif defined(__linux__) + static int no_dup3; + if (!no_dup3) { + do + r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC); + while (r == -1 && errno == EBUSY); + if (r != -1) + return r; + if (errno != ENOSYS) + return -errno; + /* Fall through. */ + no_dup3 = 1; + } +#endif + { + int err; + do + r = dup2(oldfd, newfd); +#if defined(__linux__) + while (r == -1 && errno == EBUSY); +#else + while (0); /* Never retry. */ +#endif + + if (r == -1) + return -errno; + + err = uv__cloexec(newfd, 1); + if (err) { + uv__close(newfd); + return err; + } + + return r; + } +} + + +int uv_os_homedir(char* buffer, size_t* size) { + uv_passwd_t pwd; + char* buf; + size_t len; + int r; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + /* Check if the HOME environment variable is set first */ + buf = getenv("HOME"); + + if (buf != NULL) { + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return -ENOBUFS; + } + + memcpy(buffer, buf, len + 1); + *size = len; + + return 0; + } + + /* HOME is not set, so call uv__getpwuid_r() */ + r = uv__getpwuid_r(&pwd); + + if (r != 0) { + return r; + } + + len = strlen(pwd.homedir); + + if (len >= *size) { + *size = len + 1; + uv_os_free_passwd(&pwd); + return -ENOBUFS; + } + + memcpy(buffer, pwd.homedir, len + 1); + *size = len; + uv_os_free_passwd(&pwd); + + return 0; +} + + +int uv_os_tmpdir(char* buffer, size_t* size) { + const char* buf; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + +#define CHECK_ENV_VAR(name) \ + do { \ + buf = getenv(name); \ + if (buf != NULL) \ + goto return_buffer; \ + } \ + while (0) + + /* Check the TMPDIR, TMP, TEMP, and TEMPDIR environment variables in order */ + CHECK_ENV_VAR("TMPDIR"); + CHECK_ENV_VAR("TMP"); + CHECK_ENV_VAR("TEMP"); + CHECK_ENV_VAR("TEMPDIR"); + +#undef CHECK_ENV_VAR + + /* No temp environment variables defined */ + #if defined(__ANDROID__) + buf = "/data/local/tmp"; + #else + buf = "/tmp"; + #endif + +return_buffer: + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return -ENOBUFS; + } + + /* The returned directory should not have a trailing slash. */ + if (len > 1 && buf[len - 1] == '/') { + len--; + } + + memcpy(buffer, buf, len + 1); + buffer[len] = '\0'; + *size = len; + + return 0; +} + + +int uv__getpwuid_r(uv_passwd_t* pwd) { + struct passwd pw; + struct passwd* result; + char* buf; + uid_t uid; + size_t bufsize; + size_t name_size; + size_t homedir_size; + size_t shell_size; + long initsize; + int r; +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); + + getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); + if (getpwuid_r == NULL) + return -ENOSYS; +#endif + + if (pwd == NULL) + return -EINVAL; + + initsize = sysconf(_SC_GETPW_R_SIZE_MAX); + + if (initsize <= 0) + bufsize = 4096; + else + bufsize = (size_t) initsize; + + uid = geteuid(); + buf = NULL; + + for (;;) { + uv__free(buf); + buf = uv__malloc(bufsize); + + if (buf == NULL) + return -ENOMEM; + + r = getpwuid_r(uid, &pw, buf, bufsize, &result); + + if (r != ERANGE) + break; + + bufsize *= 2; + } + + if (r != 0) { + uv__free(buf); + return -r; + } + + if (result == NULL) { + uv__free(buf); + return -ENOENT; + } + + /* Allocate memory for the username, shell, and home directory */ + name_size = strlen(pw.pw_name) + 1; + homedir_size = strlen(pw.pw_dir) + 1; + shell_size = strlen(pw.pw_shell) + 1; + pwd->username = uv__malloc(name_size + homedir_size + shell_size); + + if (pwd->username == NULL) { + uv__free(buf); + return -ENOMEM; + } + + /* Copy the username */ + memcpy(pwd->username, pw.pw_name, name_size); + + /* Copy the home directory */ + pwd->homedir = pwd->username + name_size; + memcpy(pwd->homedir, pw.pw_dir, homedir_size); + + /* Copy the shell */ + pwd->shell = pwd->homedir + homedir_size; + memcpy(pwd->shell, pw.pw_shell, shell_size); + + /* Copy the uid and gid */ + pwd->uid = pw.pw_uid; + pwd->gid = pw.pw_gid; + + uv__free(buf); + + return 0; +} + + +void uv_os_free_passwd(uv_passwd_t* pwd) { + if (pwd == NULL) + return; + + /* + The memory for name, shell, and homedir are allocated in a single + uv__malloc() call. The base of the pointer is stored in pwd->username, so + that is the field that needs to be freed. + */ + uv__free(pwd->username); + pwd->username = NULL; + pwd->shell = NULL; + pwd->homedir = NULL; +} + + +int uv_os_get_passwd(uv_passwd_t* pwd) { + return uv__getpwuid_r(pwd); +} diff --git a/src/unix/darwin-proctitle.c b/src/unix/darwin-proctitle.c new file mode 100644 index 0000000..1142311 --- /dev/null +++ b/src/unix/darwin-proctitle.c @@ -0,0 +1,206 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include +#include +#include +#include + +#include + +#if !TARGET_OS_IPHONE +# include +# include +#endif + + +static int uv__pthread_setname_np(const char* name) { + int (*dynamic_pthread_setname_np)(const char* name); + char namebuf[64]; /* MAXTHREADNAMESIZE */ + int err; + + /* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */ + *(void **)(&dynamic_pthread_setname_np) = + dlsym(RTLD_DEFAULT, "pthread_setname_np"); + + if (dynamic_pthread_setname_np == NULL) + return -ENOSYS; + + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + + err = dynamic_pthread_setname_np(namebuf); + if (err) + return -err; + + return 0; +} + + +int uv__set_process_title(const char* title) { +#if TARGET_OS_IPHONE + return uv__pthread_setname_np(title); +#else + CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef, + const char*, + CFStringEncoding); + CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef); + void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef); + void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef); + CFTypeRef (*pLSGetCurrentApplicationASN)(void); + OSStatus (*pLSSetApplicationInformationItem)(int, + CFTypeRef, + CFStringRef, + CFStringRef, + CFDictionaryRef*); + void* application_services_handle; + void* core_foundation_handle; + CFBundleRef launch_services_bundle; + CFStringRef* display_name_key; + CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef); + CFBundleRef (*pCFBundleGetMainBundle)(void); + CFBundleRef hi_services_bundle; + OSStatus (*pSetApplicationIsDaemon)(int); + CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef); + void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t, + void*); + CFTypeRef asn; + int err; + + err = -ENOENT; + application_services_handle = dlopen("/System/Library/Frameworks/" + "ApplicationServices.framework/" + "Versions/A/ApplicationServices", + RTLD_LAZY | RTLD_LOCAL); + core_foundation_handle = dlopen("/System/Library/Frameworks/" + "CoreFoundation.framework/" + "Versions/A/CoreFoundation", + RTLD_LAZY | RTLD_LOCAL); + + if (application_services_handle == NULL || core_foundation_handle == NULL) + goto out; + + *(void **)(&pCFStringCreateWithCString) = + dlsym(core_foundation_handle, "CFStringCreateWithCString"); + *(void **)(&pCFBundleGetBundleWithIdentifier) = + dlsym(core_foundation_handle, "CFBundleGetBundleWithIdentifier"); + *(void **)(&pCFBundleGetDataPointerForName) = + dlsym(core_foundation_handle, "CFBundleGetDataPointerForName"); + *(void **)(&pCFBundleGetFunctionPointerForName) = + dlsym(core_foundation_handle, "CFBundleGetFunctionPointerForName"); + + if (pCFStringCreateWithCString == NULL || + pCFBundleGetBundleWithIdentifier == NULL || + pCFBundleGetDataPointerForName == NULL || + pCFBundleGetFunctionPointerForName == NULL) { + goto out; + } + +#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8) + + launch_services_bundle = + pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices")); + + if (launch_services_bundle == NULL) + goto out; + + *(void **)(&pLSGetCurrentApplicationASN) = + pCFBundleGetFunctionPointerForName(launch_services_bundle, + S("_LSGetCurrentApplicationASN")); + + if (pLSGetCurrentApplicationASN == NULL) + goto out; + + *(void **)(&pLSSetApplicationInformationItem) = + pCFBundleGetFunctionPointerForName(launch_services_bundle, + S("_LSSetApplicationInformationItem")); + + if (pLSSetApplicationInformationItem == NULL) + goto out; + + display_name_key = pCFBundleGetDataPointerForName(launch_services_bundle, + S("_kLSDisplayNameKey")); + + if (display_name_key == NULL || *display_name_key == NULL) + goto out; + + *(void **)(&pCFBundleGetInfoDictionary) = dlsym(core_foundation_handle, + "CFBundleGetInfoDictionary"); + *(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle, + "CFBundleGetMainBundle"); + if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL) + goto out; + + /* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */ + hi_services_bundle = + pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices")); + err = -ENOENT; + if (hi_services_bundle == NULL) + goto out; + + *(void **)(&pSetApplicationIsDaemon) = pCFBundleGetFunctionPointerForName( + hi_services_bundle, + S("SetApplicationIsDaemon")); + *(void **)(&pLSApplicationCheckIn) = pCFBundleGetFunctionPointerForName( + launch_services_bundle, + S("_LSApplicationCheckIn")); + *(void **)(&pLSSetApplicationLaunchServicesServerConnectionStatus) = + pCFBundleGetFunctionPointerForName( + launch_services_bundle, + S("_LSSetApplicationLaunchServicesServerConnectionStatus")); + if (pSetApplicationIsDaemon == NULL || + pLSApplicationCheckIn == NULL || + pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) { + goto out; + } + + if (pSetApplicationIsDaemon(1) != noErr) + goto out; + + pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL); + + /* Check into process manager?! */ + pLSApplicationCheckIn(-2, + pCFBundleGetInfoDictionary(pCFBundleGetMainBundle())); + + asn = pLSGetCurrentApplicationASN(); + + err = -EINVAL; + if (pLSSetApplicationInformationItem(-2, /* Magic value. */ + asn, + *display_name_key, + S(title), + NULL) != noErr) { + goto out; + } + + uv__pthread_setname_np(title); /* Don't care if it fails. */ + err = 0; + +out: + if (core_foundation_handle != NULL) + dlclose(core_foundation_handle); + + if (application_services_handle != NULL) + dlclose(application_services_handle); + + return err; +#endif /* !TARGET_OS_IPHONE */ +} diff --git a/src/unix/darwin.c b/src/unix/darwin.c new file mode 100644 index 0000000..cf95da2 --- /dev/null +++ b/src/unix/darwin.c @@ -0,0 +1,335 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include /* _NSGetExecutablePath */ +#include +#include +#include /* sysconf */ + + +int uv__platform_loop_init(uv_loop_t* loop) { + loop->cf_state = NULL; + + if (uv__kqueue_init(loop)) + return -errno; + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + uv__fsevents_loop_delete(loop); +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + static mach_timebase_info_data_t info; + + if ((ACCESS_ONCE(uint32_t, info.numer) == 0 || + ACCESS_ONCE(uint32_t, info.denom) == 0) && + mach_timebase_info(&info) != KERN_SUCCESS) + abort(); + + return mach_absolute_time() * info.numer / info.denom; +} + + +int uv_exepath(char* buffer, size_t* size) { + /* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */ + char abspath[PATH_MAX * 2 + 1]; + char exepath[PATH_MAX + 1]; + uint32_t exepath_size; + size_t abspath_size; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + exepath_size = sizeof(exepath); + if (_NSGetExecutablePath(exepath, &exepath_size)) + return -EIO; + + if (realpath(exepath, abspath) != abspath) + return -errno; + + abspath_size = strlen(abspath); + if (abspath_size == 0) + return -EIO; + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + return 0; +} + + +uint64_t uv_get_free_memory(void) { + vm_statistics_data_t info; + mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t); + + if (host_statistics(mach_host_self(), HOST_VM_INFO, + (host_info_t)&info, &count) != KERN_SUCCESS) { + return -EINVAL; /* FIXME(bnoordhuis) Translate error. */ + } + + return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE); +} + + +uint64_t uv_get_total_memory(void) { + uint64_t info; + int which[] = {CTL_HW, HW_MEMSIZE}; + size_t size = sizeof(info); + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info; +} + + +void uv_loadavg(double avg[3]) { + struct loadavg info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_LOADAVG}; + + if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return; + + avg[0] = (double) info.ldavg[0] / info.fscale; + avg[1] = (double) info.ldavg[1] / info.fscale; + avg[2] = (double) info.ldavg[2] / info.fscale; +} + + +int uv_resident_set_memory(size_t* rss) { + mach_msg_type_number_t count; + task_basic_info_data_t info; + kern_return_t err; + + count = TASK_BASIC_INFO_COUNT; + err = task_info(mach_task_self(), + TASK_BASIC_INFO, + (task_info_t) &info, + &count); + (void) &err; + /* task_info(TASK_BASIC_INFO) cannot really fail. Anything other than + * KERN_SUCCESS implies a libuv bug. + */ + assert(err == KERN_SUCCESS); + *rss = info.resident_size; + + return 0; +} + + +int uv_uptime(double* uptime) { + time_t now; + struct timeval info; + size_t size = sizeof(info); + static int which[] = {CTL_KERN, KERN_BOOTTIME}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + now = time(NULL); + *uptime = now - info.tv_sec; + + return 0; +} + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), + multiplier = ((uint64_t)1000L / ticks); + char model[512]; + uint64_t cpuspeed; + size_t size; + unsigned int i; + natural_t numcpus; + mach_msg_type_number_t msg_type; + processor_cpu_load_info_data_t *info; + uv_cpu_info_t* cpu_info; + + size = sizeof(model); + if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) && + sysctlbyname("hw.model", &model, &size, NULL, 0)) { + return -errno; + } + + size = sizeof(cpuspeed); + if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0)) + return -errno; + + if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus, + (processor_info_array_t*)&info, + &msg_type) != KERN_SUCCESS) { + return -EINVAL; /* FIXME(bnoordhuis) Translate error. */ + } + + *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) { + vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type); + return -ENOMEM; + } + + *count = numcpus; + + for (i = 0; i < numcpus; i++) { + cpu_info = &(*cpu_infos)[i]; + + cpu_info->cpu_times.user = (uint64_t)(info[i].cpu_ticks[0]) * multiplier; + cpu_info->cpu_times.nice = (uint64_t)(info[i].cpu_ticks[3]) * multiplier; + cpu_info->cpu_times.sys = (uint64_t)(info[i].cpu_ticks[1]) * multiplier; + cpu_info->cpu_times.idle = (uint64_t)(info[i].cpu_ticks[2]) * multiplier; + cpu_info->cpu_times.irq = 0; + + cpu_info->model = uv__strdup(model); + cpu_info->speed = cpuspeed/1000000; + } + vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type); + + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family == AF_LINK)) { + continue; + } + + (*count)++; + } + + *addresses = uv__malloc(*count * sizeof(**addresses)); + if (!(*addresses)) { + freeifaddrs(addrs); + return -ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + /* + * On Mac OS X getifaddrs returns information related to Mac Addresses for + * various devices, such as firewire, etc. These are not relevant here. + */ + if (ent->ifa_addr->sa_family == AF_LINK) + continue; + + address->name = uv__strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(addresses[i].name); + } + + uv__free(addresses); +} diff --git a/src/unix/dl.c b/src/unix/dl.c new file mode 100644 index 0000000..fc1c052 --- /dev/null +++ b/src/unix/dl.c @@ -0,0 +1,80 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include + +static int uv__dlerror(uv_lib_t* lib); + + +int uv_dlopen(const char* filename, uv_lib_t* lib) { + dlerror(); /* Reset error status. */ + lib->errmsg = NULL; + lib->handle = dlopen(filename, RTLD_LAZY); + return lib->handle ? 0 : uv__dlerror(lib); +} + + +void uv_dlclose(uv_lib_t* lib) { + uv__free(lib->errmsg); + lib->errmsg = NULL; + + if (lib->handle) { + /* Ignore errors. No good way to signal them without leaking memory. */ + dlclose(lib->handle); + lib->handle = NULL; + } +} + + +int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) { + dlerror(); /* Reset error status. */ + *ptr = dlsym(lib->handle, name); + return uv__dlerror(lib); +} + + +const char* uv_dlerror(const uv_lib_t* lib) { + return lib->errmsg ? lib->errmsg : "no error"; +} + + +static int uv__dlerror(uv_lib_t* lib) { + const char* errmsg; + + uv__free(lib->errmsg); + + errmsg = dlerror(); + + if (errmsg) { + lib->errmsg = uv__strdup(errmsg); + return -1; + } + else { + lib->errmsg = NULL; + return 0; + } +} diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c new file mode 100644 index 0000000..cba44a3 --- /dev/null +++ b/src/unix/freebsd.c @@ -0,0 +1,460 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include /* VM_LOADAVG */ +#include +#include +#include /* sysconf */ +#include + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + +#ifndef CPUSTATES +# define CPUSTATES 5U +#endif +#ifndef CP_USER +# define CP_USER 0 +# define CP_NICE 1 +# define CP_SYS 2 +# define CP_IDLE 3 +# define CP_INTR 4 +#endif + +static char *process_title; + + +int uv__platform_loop_init(uv_loop_t* loop) { + return uv__kqueue_init(loop); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); +} + + +#ifdef __DragonFly__ +int uv_exepath(char* buffer, size_t* size) { + char abspath[PATH_MAX * 2 + 1]; + ssize_t abspath_size; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath)); + if (abspath_size < 0) + return -errno; + + assert(abspath_size > 0); + *size -= 1; + + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + return 0; +} +#else +int uv_exepath(char* buffer, size_t* size) { + char abspath[PATH_MAX * 2 + 1]; + int mib[4]; + size_t abspath_size; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + + abspath_size = sizeof abspath; + if (sysctl(mib, 4, abspath, &abspath_size, NULL, 0)) + return -errno; + + assert(abspath_size > 0); + abspath_size -= 1; + *size -= 1; + + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + return 0; +} +#endif + +uint64_t uv_get_free_memory(void) { + int freecount; + size_t size = sizeof(freecount); + + if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0)) + return -errno; + + return (uint64_t) freecount * sysconf(_SC_PAGESIZE); + +} + + +uint64_t uv_get_total_memory(void) { + unsigned long info; + int which[] = {CTL_HW, HW_PHYSMEM}; + + size_t size = sizeof(info); + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info; +} + + +void uv_loadavg(double avg[3]) { + struct loadavg info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_LOADAVG}; + + if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return; + + avg[0] = (double) info.ldavg[0] / info.fscale; + avg[1] = (double) info.ldavg[1] / info.fscale; + avg[2] = (double) info.ldavg[2] / info.fscale; +} + + +char** uv_setup_args(int argc, char** argv) { + process_title = argc ? uv__strdup(argv[0]) : NULL; + return argv; +} + + +int uv_set_process_title(const char* title) { + int oid[4]; + + uv__free(process_title); + process_title = uv__strdup(title); + + oid[0] = CTL_KERN; + oid[1] = KERN_PROC; + oid[2] = KERN_PROC_ARGS; + oid[3] = getpid(); + + sysctl(oid, + ARRAY_SIZE(oid), + NULL, + NULL, + process_title, + strlen(process_title) + 1); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return -EINVAL; + + if (process_title) { + len = strlen(process_title) + 1; + + if (size < len) + return -ENOBUFS; + + memcpy(buffer, process_title, len); + } else { + len = 0; + } + + buffer[len] = '\0'; + + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + kvm_t *kd = NULL; + struct kinfo_proc *kinfo = NULL; + pid_t pid; + int nprocs; + size_t page_size = getpagesize(); + + pid = getpid(); + + kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); + if (kd == NULL) goto error; + + kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs); + if (kinfo == NULL) goto error; + +#ifdef __DragonFly__ + *rss = kinfo->kp_vm_rssize * page_size; +#else + *rss = kinfo->ki_rssize * page_size; +#endif + + kvm_close(kd); + + return 0; + +error: + if (kd) kvm_close(kd); + return -EPERM; +} + + +int uv_uptime(double* uptime) { + int r; + struct timespec sp; + r = clock_gettime(CLOCK_MONOTONIC, &sp); + if (r) + return -errno; + + *uptime = sp.tv_sec; + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), + multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus, + cur = 0; + uv_cpu_info_t* cpu_info; + const char* maxcpus_key; + const char* cptimes_key; + char model[512]; + long* cp_times; + int numcpus; + size_t size; + int i; + +#if defined(__DragonFly__) + /* This is not quite correct but DragonFlyBSD doesn't seem to have anything + * comparable to kern.smp.maxcpus or kern.cp_times (kern.cp_time is a total, + * not per CPU). At least this stops uv_cpu_info() from failing completely. + */ + maxcpus_key = "hw.ncpu"; + cptimes_key = "kern.cp_time"; +#else + maxcpus_key = "kern.smp.maxcpus"; + cptimes_key = "kern.cp_times"; +#endif + + size = sizeof(model); + if (sysctlbyname("hw.model", &model, &size, NULL, 0)) + return -errno; + + size = sizeof(numcpus); + if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) + return -errno; + + *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) + return -ENOMEM; + + *count = numcpus; + + size = sizeof(cpuspeed); + if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) { + uv__free(*cpu_infos); + return -errno; + } + + /* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of + * ncpu. + */ + size = sizeof(maxcpus); + if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) { + uv__free(*cpu_infos); + return -errno; + } + + size = maxcpus * CPUSTATES * sizeof(long); + + cp_times = uv__malloc(size); + if (cp_times == NULL) { + uv__free(*cpu_infos); + return -ENOMEM; + } + + if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) { + uv__free(cp_times); + uv__free(*cpu_infos); + return -errno; + } + + for (i = 0; i < numcpus; i++) { + cpu_info = &(*cpu_infos)[i]; + + cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier; + cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier; + cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier; + cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier; + cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier; + + cpu_info->model = uv__strdup(model); + cpu_info->speed = cpuspeed; + + cur+=CPUSTATES; + } + + uv__free(cp_times); + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family == AF_LINK)) { + continue; + } + + (*count)++; + } + + *addresses = uv__malloc(*count * sizeof(**addresses)); + if (!(*addresses)) { + freeifaddrs(addrs); + return -ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + /* + * On FreeBSD getifaddrs returns information related to the raw underlying + * devices. We're not interested in this information yet. + */ + if (ent->ifa_addr->sa_family == AF_LINK) + continue; + + address->name = uv__strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(addresses[i].name); + } + + uv__free(addresses); +} diff --git a/src/unix/fs.c b/src/unix/fs.c new file mode 100644 index 0000000..216ef97 --- /dev/null +++ b/src/unix/fs.c @@ -0,0 +1,1355 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +/* Caveat emptor: this file deviates from the libuv convention of returning + * negated errno codes. Most uv_fs_*() functions map directly to the system + * call of the same name. For more complex wrappers, it's easier to just + * return -1 with errno set. The dispatcher in uv__fs_work() takes care of + * getting the errno to the right place (req->result or as the return value.) + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include /* PATH_MAX */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel_) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# define HAVE_PREADV 1 +#else +# define HAVE_PREADV 0 +#endif + +#if defined(__linux__) || defined(__sun) +# include +#endif + +#define INIT(subtype) \ + do { \ + req->type = UV_FS; \ + if (cb != NULL) \ + uv__req_init(loop, req, UV_FS); \ + req->fs_type = UV_FS_ ## subtype; \ + req->result = 0; \ + req->ptr = NULL; \ + req->loop = loop; \ + req->path = NULL; \ + req->new_path = NULL; \ + req->cb = cb; \ + } \ + while (0) + +#define PATH \ + do { \ + assert(path != NULL); \ + if (cb == NULL) { \ + req->path = path; \ + } else { \ + req->path = uv__strdup(path); \ + if (req->path == NULL) { \ + uv__req_unregister(loop, req); \ + return -ENOMEM; \ + } \ + } \ + } \ + while (0) + +#define PATH2 \ + do { \ + if (cb == NULL) { \ + req->path = path; \ + req->new_path = new_path; \ + } else { \ + size_t path_len; \ + size_t new_path_len; \ + path_len = strlen(path) + 1; \ + new_path_len = strlen(new_path) + 1; \ + req->path = uv__malloc(path_len + new_path_len); \ + if (req->path == NULL) { \ + uv__req_unregister(loop, req); \ + return -ENOMEM; \ + } \ + req->new_path = req->path + path_len; \ + memcpy((void*) req->path, path, path_len); \ + memcpy((void*) req->new_path, new_path, new_path_len); \ + } \ + } \ + while (0) + +#define POST \ + do { \ + if (cb != NULL) { \ + uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \ + return 0; \ + } \ + else { \ + uv__fs_work(&req->work_req); \ + return req->result; \ + } \ + } \ + while (0) + + +static ssize_t uv__fs_fdatasync(uv_fs_t* req) { +#if defined(__linux__) || defined(__sun) || defined(__NetBSD__) + return fdatasync(req->file); +#elif defined(__APPLE__) && defined(SYS_fdatasync) + return syscall(SYS_fdatasync, req->file); +#else + return fsync(req->file); +#endif +} + + +static ssize_t uv__fs_futime(uv_fs_t* req) { +#if defined(__linux__) + /* utimesat() has nanosecond resolution but we stick to microseconds + * for the sake of consistency with other platforms. + */ + static int no_utimesat; + struct timespec ts[2]; + struct timeval tv[2]; + char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)]; + int r; + + if (no_utimesat) + goto skip; + + ts[0].tv_sec = req->atime; + ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; + ts[1].tv_sec = req->mtime; + ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; + + r = uv__utimesat(req->file, NULL, ts, 0); + if (r == 0) + return r; + + if (errno != ENOSYS) + return r; + + no_utimesat = 1; + +skip: + + tv[0].tv_sec = req->atime; + tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; + tv[1].tv_sec = req->mtime; + tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; + snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file); + + r = utimes(path, tv); + if (r == 0) + return r; + + switch (errno) { + case ENOENT: + if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF) + break; + /* Fall through. */ + + case EACCES: + case ENOTDIR: + errno = ENOSYS; + break; + } + + return r; + +#elif defined(__APPLE__) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__FreeBSD_kernel__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__sun) + struct timeval tv[2]; + tv[0].tv_sec = req->atime; + tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; + tv[1].tv_sec = req->mtime; + tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; +# if defined(__sun) + return futimesat(req->file, NULL, tv); +# else + return futimes(req->file, tv); +# endif +#elif defined(_AIX71) + struct timespec ts[2]; + ts[0].tv_sec = req->atime; + ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; + ts[1].tv_sec = req->mtime; + ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; + return futimens(req->file, ts); +#elif defined(__MVS__) + attrib_t atr; + memset(&atr, 0, sizeof(atr)); + atr.att_mtimechg = 1; + atr.att_atimechg = 1; + atr.att_mtime = req->mtime; + atr.att_atime = req->atime; + return __fchattr(req->file, &atr, sizeof(atr)); +#else + errno = ENOSYS; + return -1; +#endif +} + + +static ssize_t uv__fs_mkdtemp(uv_fs_t* req) { + return mkdtemp((char*) req->path) ? 0 : -1; +} + + +static ssize_t uv__fs_open(uv_fs_t* req) { + static int no_cloexec_support; + int r; + + /* Try O_CLOEXEC before entering locks */ + if (no_cloexec_support == 0) { +#ifdef O_CLOEXEC + r = open(req->path, req->flags | O_CLOEXEC, req->mode); + if (r >= 0) + return r; + if (errno != EINVAL) + return r; + no_cloexec_support = 1; +#endif /* O_CLOEXEC */ + } + + if (req->cb != NULL) + uv_rwlock_rdlock(&req->loop->cloexec_lock); + + r = open(req->path, req->flags, req->mode); + + /* In case of failure `uv__cloexec` will leave error in `errno`, + * so it is enough to just set `r` to `-1`. + */ + if (r >= 0 && uv__cloexec(r, 1) != 0) { + r = uv__close(r); + if (r != 0) + abort(); + r = -1; + } + + if (req->cb != NULL) + uv_rwlock_rdunlock(&req->loop->cloexec_lock); + + return r; +} + + +static ssize_t uv__fs_read(uv_fs_t* req) { +#if defined(__linux__) + static int no_preadv; +#endif + ssize_t result; + +#if defined(_AIX) + struct stat buf; + if(fstat(req->file, &buf)) + return -1; + if(S_ISDIR(buf.st_mode)) { + errno = EISDIR; + return -1; + } +#endif /* defined(_AIX) */ + if (req->off < 0) { + if (req->nbufs == 1) + result = read(req->file, req->bufs[0].base, req->bufs[0].len); + else + result = readv(req->file, (struct iovec*) req->bufs, req->nbufs); + } else { + if (req->nbufs == 1) { + result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off); + goto done; + } + +#if HAVE_PREADV + result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); +#else +# if defined(__linux__) + if (no_preadv) retry: +# endif + { + off_t nread; + size_t index; + + nread = 0; + index = 0; + result = 1; + do { + if (req->bufs[index].len > 0) { + result = pread(req->file, + req->bufs[index].base, + req->bufs[index].len, + req->off + nread); + if (result > 0) + nread += result; + } + index++; + } while (index < req->nbufs && result > 0); + if (nread > 0) + result = nread; + } +# if defined(__linux__) + else { + result = uv__preadv(req->file, + (struct iovec*)req->bufs, + req->nbufs, + req->off); + if (result == -1 && errno == ENOSYS) { + no_preadv = 1; + goto retry; + } + } +# endif +#endif + } + +done: + return result; +} + + +#if defined(__OpenBSD__) || (defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8)) +static int uv__fs_scandir_filter(uv__dirent_t* dent) { +#else +static int uv__fs_scandir_filter(const uv__dirent_t* dent) { +#endif + return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0; +} + + +static ssize_t uv__fs_scandir(uv_fs_t* req) { + uv__dirent_t **dents; + int saved_errno; + int n; + + dents = NULL; + n = scandir(req->path, &dents, uv__fs_scandir_filter, alphasort); + + /* NOTE: We will use nbufs as an index field */ + req->nbufs = 0; + + if (n == 0) + goto out; /* osx still needs to deallocate some memory */ + else if (n == -1) + return n; + + req->ptr = dents; + + return n; + +out: + saved_errno = errno; + if (dents != NULL) { + int i; + + /* Memory was allocated using the system allocator, so use free() here. */ + for (i = 0; i < n; i++) + free(dents[i]); + free(dents); + } + errno = saved_errno; + + req->ptr = NULL; + + return n; +} + + +static ssize_t uv__fs_pathmax_size(const char* path) { + ssize_t pathmax; + + pathmax = pathconf(path, _PC_PATH_MAX); + + if (pathmax == -1) { +#if defined(PATH_MAX) + return PATH_MAX; +#else +#error "PATH_MAX undefined in the current platform" +#endif + } + + return pathmax; +} + +static ssize_t uv__fs_readlink(uv_fs_t* req) { + ssize_t len; + char* buf; + + len = uv__fs_pathmax_size(req->path); + buf = uv__malloc(len + 1); + + if (buf == NULL) { + errno = ENOMEM; + return -1; + } + + len = readlink(req->path, buf, len); + + if (len == -1) { + uv__free(buf); + return -1; + } + + buf[len] = '\0'; + req->ptr = buf; + + return 0; +} + +static ssize_t uv__fs_realpath(uv_fs_t* req) { + ssize_t len; + char* buf; + + len = uv__fs_pathmax_size(req->path); + buf = uv__malloc(len + 1); + + if (buf == NULL) { + errno = ENOMEM; + return -1; + } + + if (realpath(req->path, buf) == NULL) { + uv__free(buf); + return -1; + } + + req->ptr = buf; + + return 0; +} + +static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) { + struct pollfd pfd; + int use_pread; + off_t offset; + ssize_t nsent; + ssize_t nread; + ssize_t nwritten; + size_t buflen; + size_t len; + ssize_t n; + int in_fd; + int out_fd; + char buf[8192]; + + len = req->bufsml[0].len; + in_fd = req->flags; + out_fd = req->file; + offset = req->off; + use_pread = 1; + + /* Here are the rules regarding errors: + * + * 1. Read errors are reported only if nsent==0, otherwise we return nsent. + * The user needs to know that some data has already been sent, to stop + * them from sending it twice. + * + * 2. Write errors are always reported. Write errors are bad because they + * mean data loss: we've read data but now we can't write it out. + * + * We try to use pread() and fall back to regular read() if the source fd + * doesn't support positional reads, for example when it's a pipe fd. + * + * If we get EAGAIN when writing to the target fd, we poll() on it until + * it becomes writable again. + * + * FIXME: If we get a write error when use_pread==1, it should be safe to + * return the number of sent bytes instead of an error because pread() + * is, in theory, idempotent. However, special files in /dev or /proc + * may support pread() but not necessarily return the same data on + * successive reads. + * + * FIXME: There is no way now to signal that we managed to send *some* data + * before a write error. + */ + for (nsent = 0; (size_t) nsent < len; ) { + buflen = len - nsent; + + if (buflen > sizeof(buf)) + buflen = sizeof(buf); + + do + if (use_pread) + nread = pread(in_fd, buf, buflen, offset); + else + nread = read(in_fd, buf, buflen); + while (nread == -1 && errno == EINTR); + + if (nread == 0) + goto out; + + if (nread == -1) { + if (use_pread && nsent == 0 && (errno == EIO || errno == ESPIPE)) { + use_pread = 0; + continue; + } + + if (nsent == 0) + nsent = -1; + + goto out; + } + + for (nwritten = 0; nwritten < nread; ) { + do + n = write(out_fd, buf + nwritten, nread - nwritten); + while (n == -1 && errno == EINTR); + + if (n != -1) { + nwritten += n; + continue; + } + + if (errno != EAGAIN && errno != EWOULDBLOCK) { + nsent = -1; + goto out; + } + + pfd.fd = out_fd; + pfd.events = POLLOUT; + pfd.revents = 0; + + do + n = poll(&pfd, 1, -1); + while (n == -1 && errno == EINTR); + + if (n == -1 || (pfd.revents & ~POLLOUT) != 0) { + errno = EIO; + nsent = -1; + goto out; + } + } + + offset += nread; + nsent += nread; + } + +out: + if (nsent != -1) + req->off = offset; + + return nsent; +} + + +static ssize_t uv__fs_sendfile(uv_fs_t* req) { + int in_fd; + int out_fd; + + in_fd = req->flags; + out_fd = req->file; + +#if defined(__linux__) || defined(__sun) + { + off_t off; + ssize_t r; + + off = req->off; + r = sendfile(out_fd, in_fd, &off, req->bufsml[0].len); + + /* sendfile() on SunOS returns EINVAL if the target fd is not a socket but + * it still writes out data. Fortunately, we can detect it by checking if + * the offset has been updated. + */ + if (r != -1 || off > req->off) { + r = off - req->off; + req->off = off; + return r; + } + + if (errno == EINVAL || + errno == EIO || + errno == ENOTSOCK || + errno == EXDEV) { + errno = 0; + return uv__fs_sendfile_emul(req); + } + + return -1; + } +#elif defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) + { + off_t len; + ssize_t r; + + /* sendfile() on FreeBSD and Darwin returns EAGAIN if the target fd is in + * non-blocking mode and not all data could be written. If a non-zero + * number of bytes have been sent, we don't consider it an error. + */ + +#if defined(__FreeBSD__) || defined(__DragonFly__) + len = 0; + r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0); +#elif defined(__FreeBSD_kernel__) + len = 0; + r = bsd_sendfile(in_fd, + out_fd, + req->off, + req->bufsml[0].len, + NULL, + &len, + 0); +#else + /* The darwin sendfile takes len as an input for the length to send, + * so make sure to initialize it with the caller's value. */ + len = req->bufsml[0].len; + r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0); +#endif + + /* + * The man page for sendfile(2) on DragonFly states that `len` contains + * a meaningful value ONLY in case of EAGAIN and EINTR. + * Nothing is said about it's value in case of other errors, so better + * not depend on the potential wrong assumption that is was not modified + * by the syscall. + */ + if (r == 0 || ((errno == EAGAIN || errno == EINTR) && len != 0)) { + req->off += len; + return (ssize_t) len; + } + + if (errno == EINVAL || + errno == EIO || + errno == ENOTSOCK || + errno == EXDEV) { + errno = 0; + return uv__fs_sendfile_emul(req); + } + + return -1; + } +#else + /* Squelch compiler warnings. */ + (void) &in_fd; + (void) &out_fd; + + return uv__fs_sendfile_emul(req); +#endif +} + + +static ssize_t uv__fs_utime(uv_fs_t* req) { + struct utimbuf buf; + buf.actime = req->atime; + buf.modtime = req->mtime; + return utime(req->path, &buf); /* TODO use utimes() where available */ +} + + +static ssize_t uv__fs_write(uv_fs_t* req) { +#if defined(__linux__) + static int no_pwritev; +#endif + ssize_t r; + + /* Serialize writes on OS X, concurrent write() and pwrite() calls result in + * data loss. We can't use a per-file descriptor lock, the descriptor may be + * a dup(). + */ +#if defined(__APPLE__) + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + + if (pthread_mutex_lock(&lock)) + abort(); +#endif + + if (req->off < 0) { + if (req->nbufs == 1) + r = write(req->file, req->bufs[0].base, req->bufs[0].len); + else + r = writev(req->file, (struct iovec*) req->bufs, req->nbufs); + } else { + if (req->nbufs == 1) { + r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off); + goto done; + } +#if HAVE_PREADV + r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); +#else +# if defined(__linux__) + if (no_pwritev) retry: +# endif + { + off_t written; + size_t index; + + written = 0; + index = 0; + r = 0; + do { + if (req->bufs[index].len > 0) { + r = pwrite(req->file, + req->bufs[index].base, + req->bufs[index].len, + req->off + written); + if (r > 0) + written += r; + } + index++; + } while (index < req->nbufs && r >= 0); + if (written > 0) + r = written; + } +# if defined(__linux__) + else { + r = uv__pwritev(req->file, + (struct iovec*) req->bufs, + req->nbufs, + req->off); + if (r == -1 && errno == ENOSYS) { + no_pwritev = 1; + goto retry; + } + } +# endif +#endif + } + +done: +#if defined(__APPLE__) + if (pthread_mutex_unlock(&lock)) + abort(); +#endif + + return r; +} + +static void uv__to_stat(struct stat* src, uv_stat_t* dst) { + dst->st_dev = src->st_dev; + dst->st_mode = src->st_mode; + dst->st_nlink = src->st_nlink; + dst->st_uid = src->st_uid; + dst->st_gid = src->st_gid; + dst->st_rdev = src->st_rdev; + dst->st_ino = src->st_ino; + dst->st_size = src->st_size; + dst->st_blksize = src->st_blksize; + dst->st_blocks = src->st_blocks; + +#if defined(__APPLE__) + dst->st_atim.tv_sec = src->st_atimespec.tv_sec; + dst->st_atim.tv_nsec = src->st_atimespec.tv_nsec; + dst->st_mtim.tv_sec = src->st_mtimespec.tv_sec; + dst->st_mtim.tv_nsec = src->st_mtimespec.tv_nsec; + dst->st_ctim.tv_sec = src->st_ctimespec.tv_sec; + dst->st_ctim.tv_nsec = src->st_ctimespec.tv_nsec; + dst->st_birthtim.tv_sec = src->st_birthtimespec.tv_sec; + dst->st_birthtim.tv_nsec = src->st_birthtimespec.tv_nsec; + dst->st_flags = src->st_flags; + dst->st_gen = src->st_gen; +#elif defined(__ANDROID__) + dst->st_atim.tv_sec = src->st_atime; + dst->st_atim.tv_nsec = src->st_atimensec; + dst->st_mtim.tv_sec = src->st_mtime; + dst->st_mtim.tv_nsec = src->st_mtimensec; + dst->st_ctim.tv_sec = src->st_ctime; + dst->st_ctim.tv_nsec = src->st_ctimensec; + dst->st_birthtim.tv_sec = src->st_ctime; + dst->st_birthtim.tv_nsec = src->st_ctimensec; + dst->st_flags = 0; + dst->st_gen = 0; +#elif !defined(_AIX) && ( \ + defined(_BSD_SOURCE) || \ + defined(_SVID_SOURCE) || \ + defined(_XOPEN_SOURCE) || \ + defined(_DEFAULT_SOURCE)) + dst->st_atim.tv_sec = src->st_atim.tv_sec; + dst->st_atim.tv_nsec = src->st_atim.tv_nsec; + dst->st_mtim.tv_sec = src->st_mtim.tv_sec; + dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec; + dst->st_ctim.tv_sec = src->st_ctim.tv_sec; + dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec; +# if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) + dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec; + dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec; + dst->st_flags = src->st_flags; + dst->st_gen = src->st_gen; +# else + dst->st_birthtim.tv_sec = src->st_ctim.tv_sec; + dst->st_birthtim.tv_nsec = src->st_ctim.tv_nsec; + dst->st_flags = 0; + dst->st_gen = 0; +# endif +#else + dst->st_atim.tv_sec = src->st_atime; + dst->st_atim.tv_nsec = 0; + dst->st_mtim.tv_sec = src->st_mtime; + dst->st_mtim.tv_nsec = 0; + dst->st_ctim.tv_sec = src->st_ctime; + dst->st_ctim.tv_nsec = 0; + dst->st_birthtim.tv_sec = src->st_ctime; + dst->st_birthtim.tv_nsec = 0; + dst->st_flags = 0; + dst->st_gen = 0; +#endif +} + + +static int uv__fs_stat(const char *path, uv_stat_t *buf) { + struct stat pbuf; + int ret; + + ret = stat(path, &pbuf); + if (ret == 0) + uv__to_stat(&pbuf, buf); + + return ret; +} + + +static int uv__fs_lstat(const char *path, uv_stat_t *buf) { + struct stat pbuf; + int ret; + + ret = lstat(path, &pbuf); + if (ret == 0) + uv__to_stat(&pbuf, buf); + + return ret; +} + + +static int uv__fs_fstat(int fd, uv_stat_t *buf) { + struct stat pbuf; + int ret; + + ret = fstat(fd, &pbuf); + if (ret == 0) + uv__to_stat(&pbuf, buf); + + return ret; +} + + +typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req); +static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) { + unsigned int iovmax; + unsigned int nbufs; + uv_buf_t* bufs; + ssize_t total; + ssize_t result; + + iovmax = uv__getiovmax(); + nbufs = req->nbufs; + bufs = req->bufs; + total = 0; + + while (nbufs > 0) { + req->nbufs = nbufs; + if (req->nbufs > iovmax) + req->nbufs = iovmax; + + result = process(req); + if (result <= 0) { + if (total == 0) + total = result; + break; + } + + if (req->off >= 0) + req->off += result; + + req->bufs += req->nbufs; + nbufs -= req->nbufs; + total += result; + } + + if (errno == EINTR && total == -1) + return total; + + if (bufs != req->bufsml) + uv__free(bufs); + + req->bufs = NULL; + req->nbufs = 0; + + return total; +} + + +static void uv__fs_work(struct uv__work* w) { + int retry_on_eintr; + uv_fs_t* req; + ssize_t r; + + req = container_of(w, uv_fs_t, work_req); + retry_on_eintr = !(req->fs_type == UV_FS_CLOSE); + + do { + errno = 0; + +#define X(type, action) \ + case UV_FS_ ## type: \ + r = action; \ + break; + + switch (req->fs_type) { + X(ACCESS, access(req->path, req->flags)); + X(CHMOD, chmod(req->path, req->mode)); + X(CHOWN, chown(req->path, req->uid, req->gid)); + X(CLOSE, close(req->file)); + X(FCHMOD, fchmod(req->file, req->mode)); + X(FCHOWN, fchown(req->file, req->uid, req->gid)); + X(FDATASYNC, uv__fs_fdatasync(req)); + X(FSTAT, uv__fs_fstat(req->file, &req->statbuf)); + X(FSYNC, fsync(req->file)); + X(FTRUNCATE, ftruncate(req->file, req->off)); + X(FUTIME, uv__fs_futime(req)); + X(LSTAT, uv__fs_lstat(req->path, &req->statbuf)); + X(LINK, link(req->path, req->new_path)); + X(MKDIR, mkdir(req->path, req->mode)); + X(MKDTEMP, uv__fs_mkdtemp(req)); + X(OPEN, uv__fs_open(req)); + X(READ, uv__fs_buf_iter(req, uv__fs_read)); + X(SCANDIR, uv__fs_scandir(req)); + X(READLINK, uv__fs_readlink(req)); + X(REALPATH, uv__fs_realpath(req)); + X(RENAME, rename(req->path, req->new_path)); + X(RMDIR, rmdir(req->path)); + X(SENDFILE, uv__fs_sendfile(req)); + X(STAT, uv__fs_stat(req->path, &req->statbuf)); + X(SYMLINK, symlink(req->path, req->new_path)); + X(UNLINK, unlink(req->path)); + X(UTIME, uv__fs_utime(req)); + X(WRITE, uv__fs_buf_iter(req, uv__fs_write)); + default: abort(); + } +#undef X + } while (r == -1 && errno == EINTR && retry_on_eintr); + + if (r == -1) + req->result = -errno; + else + req->result = r; + + if (r == 0 && (req->fs_type == UV_FS_STAT || + req->fs_type == UV_FS_FSTAT || + req->fs_type == UV_FS_LSTAT)) { + req->ptr = &req->statbuf; + } +} + + +static void uv__fs_done(struct uv__work* w, int status) { + uv_fs_t* req; + + req = container_of(w, uv_fs_t, work_req); + uv__req_unregister(req->loop, req); + + if (status == -ECANCELED) { + assert(req->result == 0); + req->result = -ECANCELED; + } + + req->cb(req); +} + + +int uv_fs_access(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + uv_fs_cb cb) { + INIT(ACCESS); + PATH; + req->flags = flags; + POST; +} + + +int uv_fs_chmod(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int mode, + uv_fs_cb cb) { + INIT(CHMOD); + PATH; + req->mode = mode; + POST; +} + + +int uv_fs_chown(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb) { + INIT(CHOWN); + PATH; + req->uid = uid; + req->gid = gid; + POST; +} + + +int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { + INIT(CLOSE); + req->file = file; + POST; +} + + +int uv_fs_fchmod(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + int mode, + uv_fs_cb cb) { + INIT(FCHMOD); + req->file = file; + req->mode = mode; + POST; +} + + +int uv_fs_fchown(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb) { + INIT(FCHOWN); + req->file = file; + req->uid = uid; + req->gid = gid; + POST; +} + + +int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { + INIT(FDATASYNC); + req->file = file; + POST; +} + + +int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { + INIT(FSTAT); + req->file = file; + POST; +} + + +int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { + INIT(FSYNC); + req->file = file; + POST; +} + + +int uv_fs_ftruncate(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + int64_t off, + uv_fs_cb cb) { + INIT(FTRUNCATE); + req->file = file; + req->off = off; + POST; +} + + +int uv_fs_futime(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + double atime, + double mtime, + uv_fs_cb cb) { + INIT(FUTIME); + req->file = file; + req->atime = atime; + req->mtime = mtime; + POST; +} + + +int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + INIT(LSTAT); + PATH; + POST; +} + + +int uv_fs_link(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + uv_fs_cb cb) { + INIT(LINK); + PATH2; + POST; +} + + +int uv_fs_mkdir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int mode, + uv_fs_cb cb) { + INIT(MKDIR); + PATH; + req->mode = mode; + POST; +} + + +int uv_fs_mkdtemp(uv_loop_t* loop, + uv_fs_t* req, + const char* tpl, + uv_fs_cb cb) { + INIT(MKDTEMP); + req->path = uv__strdup(tpl); + if (req->path == NULL) { + if (cb != NULL) + uv__req_unregister(loop, req); + return -ENOMEM; + } + POST; +} + + +int uv_fs_open(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + int mode, + uv_fs_cb cb) { + INIT(OPEN); + PATH; + req->flags = flags; + req->mode = mode; + POST; +} + + +int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, + uv_file file, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t off, + uv_fs_cb cb) { + if (bufs == NULL || nbufs == 0) + return -EINVAL; + + INIT(READ); + req->file = file; + + req->nbufs = nbufs; + req->bufs = req->bufsml; + if (nbufs > ARRAY_SIZE(req->bufsml)) + req->bufs = uv__malloc(nbufs * sizeof(*bufs)); + + if (req->bufs == NULL) { + if (cb != NULL) + uv__req_unregister(loop, req); + return -ENOMEM; + } + + memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); + + req->off = off; + POST; +} + + +int uv_fs_scandir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + uv_fs_cb cb) { + INIT(SCANDIR); + PATH; + req->flags = flags; + POST; +} + + +int uv_fs_readlink(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb) { + INIT(READLINK); + PATH; + POST; +} + + +int uv_fs_realpath(uv_loop_t* loop, + uv_fs_t* req, + const char * path, + uv_fs_cb cb) { + INIT(REALPATH); + PATH; + POST; +} + + +int uv_fs_rename(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + uv_fs_cb cb) { + INIT(RENAME); + PATH2; + POST; +} + + +int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + INIT(RMDIR); + PATH; + POST; +} + + +int uv_fs_sendfile(uv_loop_t* loop, + uv_fs_t* req, + uv_file out_fd, + uv_file in_fd, + int64_t off, + size_t len, + uv_fs_cb cb) { + INIT(SENDFILE); + req->flags = in_fd; /* hack */ + req->file = out_fd; + req->off = off; + req->bufsml[0].len = len; + POST; +} + + +int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + INIT(STAT); + PATH; + POST; +} + + +int uv_fs_symlink(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + int flags, + uv_fs_cb cb) { + INIT(SYMLINK); + PATH2; + req->flags = flags; + POST; +} + + +int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + INIT(UNLINK); + PATH; + POST; +} + + +int uv_fs_utime(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + double atime, + double mtime, + uv_fs_cb cb) { + INIT(UTIME); + PATH; + req->atime = atime; + req->mtime = mtime; + POST; +} + + +int uv_fs_write(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t off, + uv_fs_cb cb) { + if (bufs == NULL || nbufs == 0) + return -EINVAL; + + INIT(WRITE); + req->file = file; + + req->nbufs = nbufs; + req->bufs = req->bufsml; + if (nbufs > ARRAY_SIZE(req->bufsml)) + req->bufs = uv__malloc(nbufs * sizeof(*bufs)); + + if (req->bufs == NULL) { + if (cb != NULL) + uv__req_unregister(loop, req); + return -ENOMEM; + } + + memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); + + req->off = off; + POST; +} + + +void uv_fs_req_cleanup(uv_fs_t* req) { + /* Only necessary for asychronous requests, i.e., requests with a callback. + * Synchronous ones don't copy their arguments and have req->path and + * req->new_path pointing to user-owned memory. UV_FS_MKDTEMP is the + * exception to the rule, it always allocates memory. + */ + if (req->path != NULL && (req->cb != NULL || req->fs_type == UV_FS_MKDTEMP)) + uv__free((void*) req->path); /* Memory is shared with req->new_path. */ + + req->path = NULL; + req->new_path = NULL; + + if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL) + uv__fs_scandir_cleanup(req); + + if (req->ptr != &req->statbuf) + uv__free(req->ptr); + req->ptr = NULL; +} diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c new file mode 100644 index 0000000..d331a13 --- /dev/null +++ b/src/unix/fsevents.c @@ -0,0 +1,904 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#if TARGET_OS_IPHONE + +/* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */ + +int uv__fsevents_init(uv_fs_event_t* handle) { + return 0; +} + + +int uv__fsevents_close(uv_fs_event_t* handle) { + return 0; +} + + +void uv__fsevents_loop_delete(uv_loop_t* loop) { +} + +#else /* TARGET_OS_IPHONE */ + +#include +#include +#include +#include + +#include +#include + +/* These are macros to avoid "initializer element is not constant" errors + * with old versions of gcc. + */ +#define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod | \ + kFSEventStreamEventFlagItemModified | \ + kFSEventStreamEventFlagItemInodeMetaMod | \ + kFSEventStreamEventFlagItemChangeOwner | \ + kFSEventStreamEventFlagItemXattrMod) + +#define kFSEventsRenamed (kFSEventStreamEventFlagItemCreated | \ + kFSEventStreamEventFlagItemRemoved | \ + kFSEventStreamEventFlagItemRenamed) + +#define kFSEventsSystem (kFSEventStreamEventFlagUserDropped | \ + kFSEventStreamEventFlagKernelDropped | \ + kFSEventStreamEventFlagEventIdsWrapped | \ + kFSEventStreamEventFlagHistoryDone | \ + kFSEventStreamEventFlagMount | \ + kFSEventStreamEventFlagUnmount | \ + kFSEventStreamEventFlagRootChanged) + +typedef struct uv__fsevents_event_s uv__fsevents_event_t; +typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t; +typedef struct uv__cf_loop_state_s uv__cf_loop_state_t; + +enum uv__cf_loop_signal_type_e { + kUVCFLoopSignalRegular, + kUVCFLoopSignalClosing +}; +typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t; + +struct uv__cf_loop_signal_s { + QUEUE member; + uv_fs_event_t* handle; + uv__cf_loop_signal_type_t type; +}; + +struct uv__fsevents_event_s { + QUEUE member; + int events; + char path[1]; +}; + +struct uv__cf_loop_state_s { + CFRunLoopRef loop; + CFRunLoopSourceRef signal_source; + int fsevent_need_reschedule; + FSEventStreamRef fsevent_stream; + uv_sem_t fsevent_sem; + uv_mutex_t fsevent_mutex; + void* fsevent_handles[2]; + unsigned int fsevent_handle_count; +}; + +/* Forward declarations */ +static void uv__cf_loop_cb(void* arg); +static void* uv__cf_loop_runner(void* arg); +static int uv__cf_loop_signal(uv_loop_t* loop, + uv_fs_event_t* handle, + uv__cf_loop_signal_type_t type); + +/* Lazy-loaded by uv__fsevents_global_init(). */ +static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef, + const void**, + CFIndex, + const CFArrayCallBacks*); +static void (*pCFRelease)(CFTypeRef); +static void (*pCFRunLoopAddSource)(CFRunLoopRef, + CFRunLoopSourceRef, + CFStringRef); +static CFRunLoopRef (*pCFRunLoopGetCurrent)(void); +static void (*pCFRunLoopRemoveSource)(CFRunLoopRef, + CFRunLoopSourceRef, + CFStringRef); +static void (*pCFRunLoopRun)(void); +static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef, + CFIndex, + CFRunLoopSourceContext*); +static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef); +static void (*pCFRunLoopStop)(CFRunLoopRef); +static void (*pCFRunLoopWakeUp)(CFRunLoopRef); +static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)( + CFAllocatorRef, + const char*); +static CFStringEncoding (*pCFStringGetSystemEncoding)(void); +static CFStringRef (*pkCFRunLoopDefaultMode); +static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef, + FSEventStreamCallback, + FSEventStreamContext*, + CFArrayRef, + FSEventStreamEventId, + CFTimeInterval, + FSEventStreamCreateFlags); +static void (*pFSEventStreamFlushSync)(FSEventStreamRef); +static void (*pFSEventStreamInvalidate)(FSEventStreamRef); +static void (*pFSEventStreamRelease)(FSEventStreamRef); +static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef, + CFRunLoopRef, + CFStringRef); +static Boolean (*pFSEventStreamStart)(FSEventStreamRef); +static void (*pFSEventStreamStop)(FSEventStreamRef); + +#define UV__FSEVENTS_PROCESS(handle, block) \ + do { \ + QUEUE events; \ + QUEUE* q; \ + uv__fsevents_event_t* event; \ + int err; \ + uv_mutex_lock(&(handle)->cf_mutex); \ + /* Split-off all events and empty original queue */ \ + QUEUE_MOVE(&(handle)->cf_events, &events); \ + /* Get error (if any) and zero original one */ \ + err = (handle)->cf_error; \ + (handle)->cf_error = 0; \ + uv_mutex_unlock(&(handle)->cf_mutex); \ + /* Loop through events, deallocating each after processing */ \ + while (!QUEUE_EMPTY(&events)) { \ + q = QUEUE_HEAD(&events); \ + event = QUEUE_DATA(q, uv__fsevents_event_t, member); \ + QUEUE_REMOVE(q); \ + /* NOTE: Checking uv__is_active() is required here, because handle \ + * callback may close handle and invoking it after it will lead to \ + * incorrect behaviour */ \ + if (!uv__is_closing((handle)) && uv__is_active((handle))) \ + block \ + /* Free allocated data */ \ + uv__free(event); \ + } \ + if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle))) \ + (handle)->cb((handle), NULL, 0, err); \ + } while (0) + + +/* Runs in UV loop's thread, when there're events to report to handle */ +static void uv__fsevents_cb(uv_async_t* cb) { + uv_fs_event_t* handle; + + handle = cb->data; + + UV__FSEVENTS_PROCESS(handle, { + handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0); + }); +} + + +/* Runs in CF thread, pushed event into handle's event list */ +static void uv__fsevents_push_event(uv_fs_event_t* handle, + QUEUE* events, + int err) { + assert(events != NULL || err != 0); + uv_mutex_lock(&handle->cf_mutex); + + /* Concatenate two queues */ + if (events != NULL) + QUEUE_ADD(&handle->cf_events, events); + + /* Propagate error */ + if (err != 0) + handle->cf_error = err; + uv_mutex_unlock(&handle->cf_mutex); + + uv_async_send(handle->cf_cb); +} + + +/* Runs in CF thread, when there're events in FSEventStream */ +static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, + void* info, + size_t numEvents, + void* eventPaths, + const FSEventStreamEventFlags eventFlags[], + const FSEventStreamEventId eventIds[]) { + size_t i; + int len; + char** paths; + char* path; + char* pos; + uv_fs_event_t* handle; + QUEUE* q; + uv_loop_t* loop; + uv__cf_loop_state_t* state; + uv__fsevents_event_t* event; + QUEUE head; + + loop = info; + state = loop->cf_state; + assert(state != NULL); + paths = eventPaths; + + /* For each handle */ + uv_mutex_lock(&state->fsevent_mutex); + QUEUE_FOREACH(q, &state->fsevent_handles) { + handle = QUEUE_DATA(q, uv_fs_event_t, cf_member); + QUEUE_INIT(&head); + + /* Process and filter out events */ + for (i = 0; i < numEvents; i++) { + /* Ignore system events */ + if (eventFlags[i] & kFSEventsSystem) + continue; + + path = paths[i]; + len = strlen(path); + + /* Filter out paths that are outside handle's request */ + if (strncmp(path, handle->realpath, handle->realpath_len) != 0) + continue; + + if (handle->realpath_len > 1 || *handle->realpath != '/') { + path += handle->realpath_len; + len -= handle->realpath_len; + + /* Skip forward slash */ + if (*path != '\0') { + path++; + len--; + } + } + +#ifdef MAC_OS_X_VERSION_10_7 + /* Ignore events with path equal to directory itself */ + if (len == 0) + continue; +#endif /* MAC_OS_X_VERSION_10_7 */ + + /* Do not emit events from subdirectories (without option set) */ + if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != 0) { + pos = strchr(path + 1, '/'); + if (pos != NULL) + continue; + } + +#ifndef MAC_OS_X_VERSION_10_7 + path = ""; + len = 0; +#endif /* MAC_OS_X_VERSION_10_7 */ + + event = uv__malloc(sizeof(*event) + len); + if (event == NULL) + break; + + memset(event, 0, sizeof(*event)); + memcpy(event->path, path, len + 1); + + if ((eventFlags[i] & kFSEventsModified) != 0 && + (eventFlags[i] & kFSEventsRenamed) == 0) + event->events = UV_CHANGE; + else + event->events = UV_RENAME; + + QUEUE_INSERT_TAIL(&head, &event->member); + } + + if (!QUEUE_EMPTY(&head)) + uv__fsevents_push_event(handle, &head, 0); + } + uv_mutex_unlock(&state->fsevent_mutex); +} + + +/* Runs in CF thread */ +static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) { + uv__cf_loop_state_t* state; + FSEventStreamContext ctx; + FSEventStreamRef ref; + CFAbsoluteTime latency; + FSEventStreamCreateFlags flags; + + /* Initialize context */ + ctx.version = 0; + ctx.info = loop; + ctx.retain = NULL; + ctx.release = NULL; + ctx.copyDescription = NULL; + + latency = 0.05; + + /* Explanation of selected flags: + * 1. NoDefer - without this flag, events that are happening continuously + * (i.e. each event is happening after time interval less than `latency`, + * counted from previous event), will be deferred and passed to callback + * once they'll either fill whole OS buffer, or when this continuous stream + * will stop (i.e. there'll be delay between events, bigger than + * `latency`). + * Specifying this flag will invoke callback after `latency` time passed + * since event. + * 2. FileEvents - fire callback for file changes too (by default it is firing + * it only for directory changes). + */ + flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents; + + /* + * NOTE: It might sound like a good idea to remember last seen StreamEventId, + * but in reality one dir might have last StreamEventId less than, the other, + * that is being watched now. Which will cause FSEventStream API to report + * changes to files from the past. + */ + ref = pFSEventStreamCreate(NULL, + &uv__fsevents_event_cb, + &ctx, + paths, + kFSEventStreamEventIdSinceNow, + latency, + flags); + assert(ref != NULL); + + state = loop->cf_state; + pFSEventStreamScheduleWithRunLoop(ref, + state->loop, + *pkCFRunLoopDefaultMode); + if (!pFSEventStreamStart(ref)) { + pFSEventStreamInvalidate(ref); + pFSEventStreamRelease(ref); + return -EMFILE; + } + + state->fsevent_stream = ref; + return 0; +} + + +/* Runs in CF thread */ +static void uv__fsevents_destroy_stream(uv_loop_t* loop) { + uv__cf_loop_state_t* state; + + state = loop->cf_state; + + if (state->fsevent_stream == NULL) + return; + + /* Flush all accumulated events */ + pFSEventStreamFlushSync(state->fsevent_stream); + + /* Stop emitting events */ + pFSEventStreamStop(state->fsevent_stream); + + /* Release stream */ + pFSEventStreamInvalidate(state->fsevent_stream); + pFSEventStreamRelease(state->fsevent_stream); + state->fsevent_stream = NULL; +} + + +/* Runs in CF thread, when there're new fsevent handles to add to stream */ +static void uv__fsevents_reschedule(uv_fs_event_t* handle, + uv__cf_loop_signal_type_t type) { + uv__cf_loop_state_t* state; + QUEUE* q; + uv_fs_event_t* curr; + CFArrayRef cf_paths; + CFStringRef* paths; + unsigned int i; + int err; + unsigned int path_count; + + state = handle->loop->cf_state; + paths = NULL; + cf_paths = NULL; + err = 0; + /* NOTE: `i` is used in deallocation loop below */ + i = 0; + + /* Optimization to prevent O(n^2) time spent when starting to watch + * many files simultaneously + */ + uv_mutex_lock(&state->fsevent_mutex); + if (state->fsevent_need_reschedule == 0) { + uv_mutex_unlock(&state->fsevent_mutex); + goto final; + } + state->fsevent_need_reschedule = 0; + uv_mutex_unlock(&state->fsevent_mutex); + + /* Destroy previous FSEventStream */ + uv__fsevents_destroy_stream(handle->loop); + + /* Any failure below will be a memory failure */ + err = -ENOMEM; + + /* Create list of all watched paths */ + uv_mutex_lock(&state->fsevent_mutex); + path_count = state->fsevent_handle_count; + if (path_count != 0) { + paths = uv__malloc(sizeof(*paths) * path_count); + if (paths == NULL) { + uv_mutex_unlock(&state->fsevent_mutex); + goto final; + } + + q = &state->fsevent_handles; + for (; i < path_count; i++) { + q = QUEUE_NEXT(q); + assert(q != &state->fsevent_handles); + curr = QUEUE_DATA(q, uv_fs_event_t, cf_member); + + assert(curr->realpath != NULL); + paths[i] = + pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath); + if (paths[i] == NULL) { + uv_mutex_unlock(&state->fsevent_mutex); + goto final; + } + } + } + uv_mutex_unlock(&state->fsevent_mutex); + err = 0; + + if (path_count != 0) { + /* Create new FSEventStream */ + cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL); + if (cf_paths == NULL) { + err = -ENOMEM; + goto final; + } + err = uv__fsevents_create_stream(handle->loop, cf_paths); + } + +final: + /* Deallocate all paths in case of failure */ + if (err != 0) { + if (cf_paths == NULL) { + while (i != 0) + pCFRelease(paths[--i]); + uv__free(paths); + } else { + /* CFArray takes ownership of both strings and original C-array */ + pCFRelease(cf_paths); + } + + /* Broadcast error to all handles */ + uv_mutex_lock(&state->fsevent_mutex); + QUEUE_FOREACH(q, &state->fsevent_handles) { + curr = QUEUE_DATA(q, uv_fs_event_t, cf_member); + uv__fsevents_push_event(curr, NULL, err); + } + uv_mutex_unlock(&state->fsevent_mutex); + } + + /* + * Main thread will block until the removal of handle from the list, + * we must tell it when we're ready. + * + * NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close` + */ + if (type == kUVCFLoopSignalClosing) + uv_sem_post(&state->fsevent_sem); +} + + +static int uv__fsevents_global_init(void) { + static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER; + static void* core_foundation_handle; + static void* core_services_handle; + int err; + + err = 0; + pthread_mutex_lock(&global_init_mutex); + if (core_foundation_handle != NULL) + goto out; + + /* The libraries are never unloaded because we currently don't have a good + * mechanism for keeping a reference count. It's unlikely to be an issue + * but if it ever becomes one, we can turn the dynamic library handles into + * per-event loop properties and have the dynamic linker keep track for us. + */ + err = -ENOSYS; + core_foundation_handle = dlopen("/System/Library/Frameworks/" + "CoreFoundation.framework/" + "Versions/A/CoreFoundation", + RTLD_LAZY | RTLD_LOCAL); + if (core_foundation_handle == NULL) + goto out; + + core_services_handle = dlopen("/System/Library/Frameworks/" + "CoreServices.framework/" + "Versions/A/CoreServices", + RTLD_LAZY | RTLD_LOCAL); + if (core_services_handle == NULL) + goto out; + + err = -ENOENT; +#define V(handle, symbol) \ + do { \ + *(void **)(&p ## symbol) = dlsym((handle), #symbol); \ + if (p ## symbol == NULL) \ + goto out; \ + } \ + while (0) + V(core_foundation_handle, CFArrayCreate); + V(core_foundation_handle, CFRelease); + V(core_foundation_handle, CFRunLoopAddSource); + V(core_foundation_handle, CFRunLoopGetCurrent); + V(core_foundation_handle, CFRunLoopRemoveSource); + V(core_foundation_handle, CFRunLoopRun); + V(core_foundation_handle, CFRunLoopSourceCreate); + V(core_foundation_handle, CFRunLoopSourceSignal); + V(core_foundation_handle, CFRunLoopStop); + V(core_foundation_handle, CFRunLoopWakeUp); + V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation); + V(core_foundation_handle, CFStringGetSystemEncoding); + V(core_foundation_handle, kCFRunLoopDefaultMode); + V(core_services_handle, FSEventStreamCreate); + V(core_services_handle, FSEventStreamFlushSync); + V(core_services_handle, FSEventStreamInvalidate); + V(core_services_handle, FSEventStreamRelease); + V(core_services_handle, FSEventStreamScheduleWithRunLoop); + V(core_services_handle, FSEventStreamStart); + V(core_services_handle, FSEventStreamStop); +#undef V + err = 0; + +out: + if (err && core_services_handle != NULL) { + dlclose(core_services_handle); + core_services_handle = NULL; + } + + if (err && core_foundation_handle != NULL) { + dlclose(core_foundation_handle); + core_foundation_handle = NULL; + } + + pthread_mutex_unlock(&global_init_mutex); + return err; +} + + +/* Runs in UV loop */ +static int uv__fsevents_loop_init(uv_loop_t* loop) { + CFRunLoopSourceContext ctx; + uv__cf_loop_state_t* state; + pthread_attr_t attr_storage; + pthread_attr_t* attr; + int err; + + if (loop->cf_state != NULL) + return 0; + + err = uv__fsevents_global_init(); + if (err) + return err; + + state = uv__calloc(1, sizeof(*state)); + if (state == NULL) + return -ENOMEM; + + err = uv_mutex_init(&loop->cf_mutex); + if (err) + goto fail_mutex_init; + + err = uv_sem_init(&loop->cf_sem, 0); + if (err) + goto fail_sem_init; + + QUEUE_INIT(&loop->cf_signals); + + err = uv_sem_init(&state->fsevent_sem, 0); + if (err) + goto fail_fsevent_sem_init; + + err = uv_mutex_init(&state->fsevent_mutex); + if (err) + goto fail_fsevent_mutex_init; + + QUEUE_INIT(&state->fsevent_handles); + state->fsevent_need_reschedule = 0; + state->fsevent_handle_count = 0; + + memset(&ctx, 0, sizeof(ctx)); + ctx.info = loop; + ctx.perform = uv__cf_loop_cb; + state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx); + if (state->signal_source == NULL) { + err = -ENOMEM; + goto fail_signal_source_create; + } + + /* In the unlikely event that pthread_attr_init() fails, create the thread + * with the default stack size. We'll use a little more address space but + * that in itself is not a fatal error. + */ + attr = &attr_storage; + if (pthread_attr_init(attr)) + attr = NULL; + + if (attr != NULL) + if (pthread_attr_setstacksize(attr, 4 * PTHREAD_STACK_MIN)) + abort(); + + loop->cf_state = state; + + /* uv_thread_t is an alias for pthread_t. */ + err = -pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop); + + if (attr != NULL) + pthread_attr_destroy(attr); + + if (err) + goto fail_thread_create; + + /* Synchronize threads */ + uv_sem_wait(&loop->cf_sem); + return 0; + +fail_thread_create: + loop->cf_state = NULL; + +fail_signal_source_create: + uv_mutex_destroy(&state->fsevent_mutex); + +fail_fsevent_mutex_init: + uv_sem_destroy(&state->fsevent_sem); + +fail_fsevent_sem_init: + uv_sem_destroy(&loop->cf_sem); + +fail_sem_init: + uv_mutex_destroy(&loop->cf_mutex); + +fail_mutex_init: + uv__free(state); + return err; +} + + +/* Runs in UV loop */ +void uv__fsevents_loop_delete(uv_loop_t* loop) { + uv__cf_loop_signal_t* s; + uv__cf_loop_state_t* state; + QUEUE* q; + + if (loop->cf_state == NULL) + return; + + if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0) + abort(); + + uv_thread_join(&loop->cf_thread); + uv_sem_destroy(&loop->cf_sem); + uv_mutex_destroy(&loop->cf_mutex); + + /* Free any remaining data */ + while (!QUEUE_EMPTY(&loop->cf_signals)) { + q = QUEUE_HEAD(&loop->cf_signals); + s = QUEUE_DATA(q, uv__cf_loop_signal_t, member); + QUEUE_REMOVE(q); + uv__free(s); + } + + /* Destroy state */ + state = loop->cf_state; + uv_sem_destroy(&state->fsevent_sem); + uv_mutex_destroy(&state->fsevent_mutex); + pCFRelease(state->signal_source); + uv__free(state); + loop->cf_state = NULL; +} + + +/* Runs in CF thread. This is the CF loop's body */ +static void* uv__cf_loop_runner(void* arg) { + uv_loop_t* loop; + uv__cf_loop_state_t* state; + + loop = arg; + state = loop->cf_state; + state->loop = pCFRunLoopGetCurrent(); + + pCFRunLoopAddSource(state->loop, + state->signal_source, + *pkCFRunLoopDefaultMode); + + uv_sem_post(&loop->cf_sem); + + pCFRunLoopRun(); + pCFRunLoopRemoveSource(state->loop, + state->signal_source, + *pkCFRunLoopDefaultMode); + + return NULL; +} + + +/* Runs in CF thread, executed after `uv__cf_loop_signal()` */ +static void uv__cf_loop_cb(void* arg) { + uv_loop_t* loop; + uv__cf_loop_state_t* state; + QUEUE* item; + QUEUE split_head; + uv__cf_loop_signal_t* s; + + loop = arg; + state = loop->cf_state; + + uv_mutex_lock(&loop->cf_mutex); + QUEUE_MOVE(&loop->cf_signals, &split_head); + uv_mutex_unlock(&loop->cf_mutex); + + while (!QUEUE_EMPTY(&split_head)) { + item = QUEUE_HEAD(&split_head); + QUEUE_REMOVE(item); + + s = QUEUE_DATA(item, uv__cf_loop_signal_t, member); + + /* This was a termination signal */ + if (s->handle == NULL) + pCFRunLoopStop(state->loop); + else + uv__fsevents_reschedule(s->handle, s->type); + + uv__free(s); + } +} + + +/* Runs in UV loop to notify CF thread */ +int uv__cf_loop_signal(uv_loop_t* loop, + uv_fs_event_t* handle, + uv__cf_loop_signal_type_t type) { + uv__cf_loop_signal_t* item; + uv__cf_loop_state_t* state; + + item = uv__malloc(sizeof(*item)); + if (item == NULL) + return -ENOMEM; + + item->handle = handle; + item->type = type; + + uv_mutex_lock(&loop->cf_mutex); + QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member); + uv_mutex_unlock(&loop->cf_mutex); + + state = loop->cf_state; + assert(state != NULL); + pCFRunLoopSourceSignal(state->signal_source); + pCFRunLoopWakeUp(state->loop); + + return 0; +} + + +/* Runs in UV loop to initialize handle */ +int uv__fsevents_init(uv_fs_event_t* handle) { + int err; + uv__cf_loop_state_t* state; + + err = uv__fsevents_loop_init(handle->loop); + if (err) + return err; + + /* Get absolute path to file */ + handle->realpath = realpath(handle->path, NULL); + if (handle->realpath == NULL) + return -errno; + handle->realpath_len = strlen(handle->realpath); + + /* Initialize event queue */ + QUEUE_INIT(&handle->cf_events); + handle->cf_error = 0; + + /* + * Events will occur in other thread. + * Initialize callback for getting them back into event loop's thread + */ + handle->cf_cb = uv__malloc(sizeof(*handle->cf_cb)); + if (handle->cf_cb == NULL) { + err = -ENOMEM; + goto fail_cf_cb_malloc; + } + + handle->cf_cb->data = handle; + uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb); + handle->cf_cb->flags |= UV__HANDLE_INTERNAL; + uv_unref((uv_handle_t*) handle->cf_cb); + + err = uv_mutex_init(&handle->cf_mutex); + if (err) + goto fail_cf_mutex_init; + + /* Insert handle into the list */ + state = handle->loop->cf_state; + uv_mutex_lock(&state->fsevent_mutex); + QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member); + state->fsevent_handle_count++; + state->fsevent_need_reschedule = 1; + uv_mutex_unlock(&state->fsevent_mutex); + + /* Reschedule FSEventStream */ + assert(handle != NULL); + err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular); + if (err) + goto fail_loop_signal; + + return 0; + +fail_loop_signal: + uv_mutex_destroy(&handle->cf_mutex); + +fail_cf_mutex_init: + uv__free(handle->cf_cb); + handle->cf_cb = NULL; + +fail_cf_cb_malloc: + uv__free(handle->realpath); + handle->realpath = NULL; + handle->realpath_len = 0; + + return err; +} + + +/* Runs in UV loop to de-initialize handle */ +int uv__fsevents_close(uv_fs_event_t* handle) { + int err; + uv__cf_loop_state_t* state; + + if (handle->cf_cb == NULL) + return -EINVAL; + + /* Remove handle from the list */ + state = handle->loop->cf_state; + uv_mutex_lock(&state->fsevent_mutex); + QUEUE_REMOVE(&handle->cf_member); + state->fsevent_handle_count--; + state->fsevent_need_reschedule = 1; + uv_mutex_unlock(&state->fsevent_mutex); + + /* Reschedule FSEventStream */ + assert(handle != NULL); + err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing); + if (err) + return -err; + + /* Wait for deinitialization */ + uv_sem_wait(&state->fsevent_sem); + + uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) uv__free); + handle->cf_cb = NULL; + + /* Free data in queue */ + UV__FSEVENTS_PROCESS(handle, { + /* NOP */ + }); + + uv_mutex_destroy(&handle->cf_mutex); + uv__free(handle->realpath); + handle->realpath = NULL; + handle->realpath_len = 0; + + return 0; +} + +#endif /* TARGET_OS_IPHONE */ diff --git a/src/unix/getaddrinfo.c b/src/unix/getaddrinfo.c new file mode 100644 index 0000000..2049aea --- /dev/null +++ b/src/unix/getaddrinfo.c @@ -0,0 +1,202 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +/* Expose glibc-specific EAI_* error codes. Needs to be defined before we + * include any headers. + */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include "uv.h" +#include "internal.h" + +#include +#include /* NULL */ +#include +#include + +/* EAI_* constants. */ +#include + + +int uv__getaddrinfo_translate_error(int sys_err) { + switch (sys_err) { + case 0: return 0; +#if defined(EAI_ADDRFAMILY) + case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY; +#endif +#if defined(EAI_AGAIN) + case EAI_AGAIN: return UV_EAI_AGAIN; +#endif +#if defined(EAI_BADFLAGS) + case EAI_BADFLAGS: return UV_EAI_BADFLAGS; +#endif +#if defined(EAI_BADHINTS) + case EAI_BADHINTS: return UV_EAI_BADHINTS; +#endif +#if defined(EAI_CANCELED) + case EAI_CANCELED: return UV_EAI_CANCELED; +#endif +#if defined(EAI_FAIL) + case EAI_FAIL: return UV_EAI_FAIL; +#endif +#if defined(EAI_FAMILY) + case EAI_FAMILY: return UV_EAI_FAMILY; +#endif +#if defined(EAI_MEMORY) + case EAI_MEMORY: return UV_EAI_MEMORY; +#endif +#if defined(EAI_NODATA) + case EAI_NODATA: return UV_EAI_NODATA; +#endif +#if defined(EAI_NONAME) +# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME + case EAI_NONAME: return UV_EAI_NONAME; +# endif +#endif +#if defined(EAI_OVERFLOW) + case EAI_OVERFLOW: return UV_EAI_OVERFLOW; +#endif +#if defined(EAI_PROTOCOL) + case EAI_PROTOCOL: return UV_EAI_PROTOCOL; +#endif +#if defined(EAI_SERVICE) + case EAI_SERVICE: return UV_EAI_SERVICE; +#endif +#if defined(EAI_SOCKTYPE) + case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE; +#endif +#if defined(EAI_SYSTEM) + case EAI_SYSTEM: return -errno; +#endif + } + assert(!"unknown EAI_* error code"); + abort(); + return 0; /* Pacify compiler. */ +} + + +static void uv__getaddrinfo_work(struct uv__work* w) { + uv_getaddrinfo_t* req; + int err; + + req = container_of(w, uv_getaddrinfo_t, work_req); + err = getaddrinfo(req->hostname, req->service, req->hints, &req->addrinfo); + req->retcode = uv__getaddrinfo_translate_error(err); +} + + +static void uv__getaddrinfo_done(struct uv__work* w, int status) { + uv_getaddrinfo_t* req; + + req = container_of(w, uv_getaddrinfo_t, work_req); + uv__req_unregister(req->loop, req); + + /* See initialization in uv_getaddrinfo(). */ + if (req->hints) + uv__free(req->hints); + else if (req->service) + uv__free(req->service); + else if (req->hostname) + uv__free(req->hostname); + else + assert(0); + + req->hints = NULL; + req->service = NULL; + req->hostname = NULL; + + if (status == -ECANCELED) { + assert(req->retcode == 0); + req->retcode = UV_EAI_CANCELED; + } + + if (req->cb) + req->cb(req, req->retcode, req->addrinfo); +} + + +int uv_getaddrinfo(uv_loop_t* loop, + uv_getaddrinfo_t* req, + uv_getaddrinfo_cb cb, + const char* hostname, + const char* service, + const struct addrinfo* hints) { + size_t hostname_len; + size_t service_len; + size_t hints_len; + size_t len; + char* buf; + + if (req == NULL || (hostname == NULL && service == NULL)) + return -EINVAL; + + hostname_len = hostname ? strlen(hostname) + 1 : 0; + service_len = service ? strlen(service) + 1 : 0; + hints_len = hints ? sizeof(*hints) : 0; + buf = uv__malloc(hostname_len + service_len + hints_len); + + if (buf == NULL) + return -ENOMEM; + + uv__req_init(loop, req, UV_GETADDRINFO); + req->loop = loop; + req->cb = cb; + req->addrinfo = NULL; + req->hints = NULL; + req->service = NULL; + req->hostname = NULL; + req->retcode = 0; + + /* order matters, see uv_getaddrinfo_done() */ + len = 0; + + if (hints) { + req->hints = memcpy(buf + len, hints, sizeof(*hints)); + len += sizeof(*hints); + } + + if (service) { + req->service = memcpy(buf + len, service, service_len); + len += service_len; + } + + if (hostname) + req->hostname = memcpy(buf + len, hostname, hostname_len); + + if (cb) { + uv__work_submit(loop, + &req->work_req, + uv__getaddrinfo_work, + uv__getaddrinfo_done); + return 0; + } else { + uv__getaddrinfo_work(&req->work_req); + uv__getaddrinfo_done(&req->work_req, 0); + return req->retcode; + } +} + + +void uv_freeaddrinfo(struct addrinfo* ai) { + if (ai) + freeaddrinfo(ai); +} diff --git a/src/unix/getnameinfo.c b/src/unix/getnameinfo.c new file mode 100644 index 0000000..daa798a --- /dev/null +++ b/src/unix/getnameinfo.c @@ -0,0 +1,120 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. +* +* 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. +*/ + +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" + + +static void uv__getnameinfo_work(struct uv__work* w) { + uv_getnameinfo_t* req; + int err; + socklen_t salen; + + req = container_of(w, uv_getnameinfo_t, work_req); + + if (req->storage.ss_family == AF_INET) + salen = sizeof(struct sockaddr_in); + else if (req->storage.ss_family == AF_INET6) + salen = sizeof(struct sockaddr_in6); + else + abort(); + + err = getnameinfo((struct sockaddr*) &req->storage, + salen, + req->host, + sizeof(req->host), + req->service, + sizeof(req->service), + req->flags); + req->retcode = uv__getaddrinfo_translate_error(err); +} + +static void uv__getnameinfo_done(struct uv__work* w, int status) { + uv_getnameinfo_t* req; + char* host; + char* service; + + req = container_of(w, uv_getnameinfo_t, work_req); + uv__req_unregister(req->loop, req); + host = service = NULL; + + if (status == -ECANCELED) { + assert(req->retcode == 0); + req->retcode = UV_EAI_CANCELED; + } else if (req->retcode == 0) { + host = req->host; + service = req->service; + } + + if (req->getnameinfo_cb) + req->getnameinfo_cb(req, req->retcode, host, service); +} + +/* +* Entry point for getnameinfo +* return 0 if a callback will be made +* return error code if validation fails +*/ +int uv_getnameinfo(uv_loop_t* loop, + uv_getnameinfo_t* req, + uv_getnameinfo_cb getnameinfo_cb, + const struct sockaddr* addr, + int flags) { + if (req == NULL || addr == NULL) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) { + memcpy(&req->storage, + addr, + sizeof(struct sockaddr_in)); + } else if (addr->sa_family == AF_INET6) { + memcpy(&req->storage, + addr, + sizeof(struct sockaddr_in6)); + } else { + return UV_EINVAL; + } + + uv__req_init(loop, (uv_req_t*)req, UV_GETNAMEINFO); + + req->getnameinfo_cb = getnameinfo_cb; + req->flags = flags; + req->type = UV_GETNAMEINFO; + req->loop = loop; + req->retcode = 0; + + if (getnameinfo_cb) { + uv__work_submit(loop, + &req->work_req, + uv__getnameinfo_work, + uv__getnameinfo_done); + return 0; + } else { + uv__getnameinfo_work(&req->work_req); + uv__getnameinfo_done(&req->work_req, 0); + return req->retcode; + } +} diff --git a/src/unix/internal.h b/src/unix/internal.h new file mode 100644 index 0000000..c7b6019 --- /dev/null +++ b/src/unix/internal.h @@ -0,0 +1,325 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_UNIX_INTERNAL_H_ +#define UV_UNIX_INTERNAL_H_ + +#include "uv-common.h" + +#include +#include /* abort */ +#include /* strrchr */ +#include /* O_CLOEXEC, may be */ +#include + +#if defined(__STRICT_ANSI__) +# define inline __inline +#endif + +#if defined(__linux__) +# include "linux-syscalls.h" +#endif /* __linux__ */ + +#if defined(__sun) +# include +# include +#endif /* __sun */ + +#if defined(_AIX) +# define reqevents events +# define rtnevents revents +# include +#else +# include +#endif /* _AIX */ + +#if defined(__APPLE__) && !TARGET_OS_IPHONE +# include +#endif + +#if defined(__ANDROID__) +int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); +# ifdef pthread_sigmask +# undef pthread_sigmask +# endif +# define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset) +#endif + +#define ACCESS_ONCE(type, var) \ + (*(volatile type*) &(var)) + +#define ROUND_UP(a, b) \ + ((a) % (b) ? ((a) + (b)) - ((a) % (b)) : (a)) + +#define UNREACHABLE() \ + do { \ + assert(0 && "unreachable code"); \ + abort(); \ + } \ + while (0) + +#define SAVE_ERRNO(block) \ + do { \ + int _saved_errno = errno; \ + do { block; } while (0); \ + errno = _saved_errno; \ + } \ + while (0) + +/* The __clang__ and __INTEL_COMPILER checks are superfluous because they + * define __GNUC__. They are here to convey to you, dear reader, that these + * macros are enabled when compiling with clang or icc. + */ +#if defined(__clang__) || \ + defined(__GNUC__) || \ + defined(__INTEL_COMPILER) || \ + defined(__SUNPRO_C) +# define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration +# define UV_UNUSED(declaration) __attribute__((unused)) declaration +#else +# define UV_DESTRUCTOR(declaration) declaration +# define UV_UNUSED(declaration) declaration +#endif + +/* Leans on the fact that, on Linux, POLLRDHUP == EPOLLRDHUP. */ +#ifdef POLLRDHUP +# define UV__POLLRDHUP POLLRDHUP +#else +# define UV__POLLRDHUP 0x2000 +#endif + +#if !defined(O_CLOEXEC) && defined(__FreeBSD__) +/* + * It may be that we are just missing `__POSIX_VISIBLE >= 200809`. + * Try using fixed value const and give up, if it doesn't work + */ +# define O_CLOEXEC 0x00100000 +#endif + +typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t; + +/* handle flags */ +enum { + UV_CLOSING = 0x01, /* uv_close() called but not finished. */ + UV_CLOSED = 0x02, /* close(2) finished. */ + UV_STREAM_READING = 0x04, /* uv_read_start() called. */ + UV_STREAM_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */ + UV_STREAM_SHUT = 0x10, /* Write side closed. */ + UV_STREAM_READABLE = 0x20, /* The stream is readable */ + UV_STREAM_WRITABLE = 0x40, /* The stream is writable */ + UV_STREAM_BLOCKING = 0x80, /* Synchronous writes. */ + UV_STREAM_READ_PARTIAL = 0x100, /* read(2) read less than requested. */ + UV_STREAM_READ_EOF = 0x200, /* read(2) read EOF. */ + UV_TCP_NODELAY = 0x400, /* Disable Nagle. */ + UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */ + UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */ + UV_HANDLE_IPV6 = 0x10000, /* Handle is bound to a IPv6 socket. */ + UV_UDP_PROCESSING = 0x20000, /* Handle is running the send callback queue. */ + UV_HANDLE_BOUND = 0x40000 /* Handle is bound to an address and port */ +}; + +/* loop flags */ +enum { + UV_LOOP_BLOCK_SIGPROF = 1 +}; + +typedef enum { + UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */ + UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */ +} uv_clocktype_t; + +struct uv__stream_queued_fds_s { + unsigned int size; + unsigned int offset; + int fds[1]; +}; + + +#if defined(_AIX) || \ + defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__linux__) +#define uv__cloexec uv__cloexec_ioctl +#define uv__nonblock uv__nonblock_ioctl +#else +#define uv__cloexec uv__cloexec_fcntl +#define uv__nonblock uv__nonblock_fcntl +#endif + +/* core */ +int uv__cloexec_ioctl(int fd, int set); +int uv__cloexec_fcntl(int fd, int set); +int uv__nonblock_ioctl(int fd, int set); +int uv__nonblock_fcntl(int fd, int set); +int uv__close(int fd); +int uv__close_nocheckstdio(int fd); +int uv__socket(int domain, int type, int protocol); +int uv__dup(int fd); +ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags); +void uv__make_close_pending(uv_handle_t* handle); +int uv__getiovmax(void); + +void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd); +void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__io_close(uv_loop_t* loop, uv__io_t* w); +void uv__io_feed(uv_loop_t* loop, uv__io_t* w); +int uv__io_active(const uv__io_t* w, unsigned int events); +int uv__io_check_fd(uv_loop_t* loop, int fd); +void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */ + +/* async */ +void uv__async_send(struct uv__async* wa); +void uv__async_init(struct uv__async* wa); +int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb); +void uv__async_stop(uv_loop_t* loop, struct uv__async* wa); + +/* loop */ +void uv__run_idle(uv_loop_t* loop); +void uv__run_check(uv_loop_t* loop); +void uv__run_prepare(uv_loop_t* loop); + +/* stream */ +void uv__stream_init(uv_loop_t* loop, uv_stream_t* stream, + uv_handle_type type); +int uv__stream_open(uv_stream_t*, int fd, int flags); +void uv__stream_destroy(uv_stream_t* stream); +#if defined(__APPLE__) +int uv__stream_try_select(uv_stream_t* stream, int* fd); +#endif /* defined(__APPLE__) */ +void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); +int uv__accept(int sockfd); +int uv__dup2_cloexec(int oldfd, int newfd); +int uv__open_cloexec(const char* path, int flags); + +/* tcp */ +int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb); +int uv__tcp_nodelay(int fd, int on); +int uv__tcp_keepalive(int fd, int on, unsigned int delay); + +/* pipe */ +int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); + +/* timer */ +void uv__run_timers(uv_loop_t* loop); +int uv__next_timeout(const uv_loop_t* loop); + +/* signal */ +void uv__signal_close(uv_signal_t* handle); +void uv__signal_global_once_init(void); +void uv__signal_loop_cleanup(uv_loop_t* loop); + +/* platform specific */ +uint64_t uv__hrtime(uv_clocktype_t type); +int uv__kqueue_init(uv_loop_t* loop); +int uv__platform_loop_init(uv_loop_t* loop); +void uv__platform_loop_delete(uv_loop_t* loop); +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd); + +/* various */ +void uv__async_close(uv_async_t* handle); +void uv__check_close(uv_check_t* handle); +void uv__fs_event_close(uv_fs_event_t* handle); +void uv__idle_close(uv_idle_t* handle); +void uv__pipe_close(uv_pipe_t* handle); +void uv__poll_close(uv_poll_t* handle); +void uv__prepare_close(uv_prepare_t* handle); +void uv__process_close(uv_process_t* handle); +void uv__stream_close(uv_stream_t* handle); +void uv__tcp_close(uv_tcp_t* handle); +void uv__timer_close(uv_timer_t* handle); +void uv__udp_close(uv_udp_t* handle); +void uv__udp_finish_close(uv_udp_t* handle); +uv_handle_type uv__handle_type(int fd); +FILE* uv__open_file(const char* path); +int uv__getpwuid_r(uv_passwd_t* pwd); + + +#if defined(__APPLE__) +int uv___stream_fd(const uv_stream_t* handle); +#define uv__stream_fd(handle) (uv___stream_fd((const uv_stream_t*) (handle))) +#else +#define uv__stream_fd(handle) ((handle)->io_watcher.fd) +#endif /* defined(__APPLE__) */ + +#ifdef UV__O_NONBLOCK +# define UV__F_NONBLOCK UV__O_NONBLOCK +#else +# define UV__F_NONBLOCK 1 +#endif + +int uv__make_socketpair(int fds[2], int flags); +int uv__make_pipe(int fds[2], int flags); + +#if defined(__APPLE__) + +int uv__fsevents_init(uv_fs_event_t* handle); +int uv__fsevents_close(uv_fs_event_t* handle); +void uv__fsevents_loop_delete(uv_loop_t* loop); + +/* OSX < 10.7 has no file events, polyfill them */ +#ifndef MAC_OS_X_VERSION_10_7 + +static const int kFSEventStreamCreateFlagFileEvents = 0x00000010; +static const int kFSEventStreamEventFlagItemCreated = 0x00000100; +static const int kFSEventStreamEventFlagItemRemoved = 0x00000200; +static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400; +static const int kFSEventStreamEventFlagItemRenamed = 0x00000800; +static const int kFSEventStreamEventFlagItemModified = 0x00001000; +static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000; +static const int kFSEventStreamEventFlagItemChangeOwner = 0x00004000; +static const int kFSEventStreamEventFlagItemXattrMod = 0x00008000; +static const int kFSEventStreamEventFlagItemIsFile = 0x00010000; +static const int kFSEventStreamEventFlagItemIsDir = 0x00020000; +static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000; + +#endif /* __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 */ + +#endif /* defined(__APPLE__) */ + +UV_UNUSED(static void uv__req_init(uv_loop_t* loop, + uv_req_t* req, + uv_req_type type)) { + req->type = type; + uv__req_register(loop, req); +} +#define uv__req_init(loop, req, type) \ + uv__req_init((loop), (uv_req_t*)(req), (type)) + +UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) { + /* Use a fast time source if available. We only need millisecond precision. + */ + loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000; +} + +UV_UNUSED(static char* uv__basename_r(const char* path)) { + char* s; + + s = strrchr(path, '/'); + if (s == NULL) + return (char*) path; + + return s + 1; +} + +#endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c new file mode 100644 index 0000000..fffd462 --- /dev/null +++ b/src/unix/kqueue.c @@ -0,0 +1,463 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags); + + +int uv__kqueue_init(uv_loop_t* loop) { + loop->backend_fd = kqueue(); + if (loop->backend_fd == -1) + return -errno; + + uv__cloexec(loop->backend_fd, 1); + + return 0; +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct kevent ev; + int rc; + + rc = 0; + EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + rc = -errno; + + EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); + if (rc == 0) + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + abort(); + + return rc; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + struct kevent events[1024]; + struct kevent* ev; + struct timespec spec; + unsigned int nevents; + unsigned int revents; + QUEUE* q; + uv__io_t* w; + sigset_t* pset; + sigset_t set; + uint64_t base; + uint64_t diff; + int have_signals; + int filter; + int fflags; + int count; + int nfds; + int fd; + int op; + int i; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + nevents = 0; + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + assert(w->fd >= 0); + assert(w->fd < (int) loop->nwatchers); + + if ((w->events & POLLIN) == 0 && (w->pevents & POLLIN) != 0) { + filter = EVFILT_READ; + fflags = 0; + op = EV_ADD; + + if (w->cb == uv__fs_event) { + filter = EVFILT_VNODE; + fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME + | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE; + op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */ + } + + EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0); + + if (++nevents == ARRAY_SIZE(events)) { + if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) + abort(); + nevents = 0; + } + } + + if ((w->events & POLLOUT) == 0 && (w->pevents & POLLOUT) != 0) { + EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); + + if (++nevents == ARRAY_SIZE(events)) { + if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) + abort(); + nevents = 0; + } + } + + w->events = w->pevents; + } + + pset = NULL; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + pset = &set; + sigemptyset(pset); + sigaddset(pset, SIGPROF); + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + + for (;; nevents = 0) { + if (timeout != -1) { + spec.tv_sec = timeout / 1000; + spec.tv_nsec = (timeout % 1000) * 1000000; + } + + if (pset != NULL) + pthread_sigmask(SIG_BLOCK, pset, NULL); + + nfds = kevent(loop->backend_fd, + events, + nevents, + events, + ARRAY_SIZE(events), + timeout == -1 ? NULL : &spec); + + if (pset != NULL) + pthread_sigmask(SIG_UNBLOCK, pset, NULL); + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (nfds == 0) { + assert(timeout != -1); + return; + } + + if (nfds == -1) { + if (errno != EINTR) + abort(); + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + have_signals = 0; + nevents = 0; + + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + for (i = 0; i < nfds; i++) { + ev = events + i; + fd = ev->ident; + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (fd == -1) + continue; + w = loop->watchers[fd]; + + if (w == NULL) { + /* File descriptor that we've stopped watching, disarm it. */ + /* TODO batch up */ + struct kevent events[1]; + + EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); + if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) + if (errno != EBADF && errno != ENOENT) + abort(); + + continue; + } + + if (ev->filter == EVFILT_VNODE) { + assert(w->events == POLLIN); + assert(w->pevents == POLLIN); + w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */ + nevents++; + continue; + } + + revents = 0; + + if (ev->filter == EVFILT_READ) { + if (w->pevents & POLLIN) { + revents |= POLLIN; + w->rcount = ev->data; + } else { + /* TODO batch up */ + struct kevent events[1]; + EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); + if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) + if (errno != ENOENT) + abort(); + } + } + + if (ev->filter == EVFILT_WRITE) { + if (w->pevents & POLLOUT) { + revents |= POLLOUT; + w->wcount = ev->data; + } else { + /* TODO batch up */ + struct kevent events[1]; + EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); + if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) + if (errno != ENOENT) + abort(); + } + } + + if (ev->flags & EV_ERROR) + revents |= POLLERR; + + if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP)) + revents |= UV__POLLRDHUP; + + if (revents == 0) + continue; + + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, revents); + + nevents++; + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + diff = loop->time - base; + if (diff >= (uint64_t) timeout) + return; + + timeout -= diff; + } +} + + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct kevent* events; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + + events = (struct kevent*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + if (events == NULL) + return; + + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].ident == fd) + events[i].ident = -1; +} + + +static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) { + uv_fs_event_t* handle; + struct kevent ev; + int events; + const char* path; +#if defined(F_GETPATH) + /* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */ + char pathbuf[MAXPATHLEN]; +#endif + + handle = container_of(w, uv_fs_event_t, event_watcher); + + if (fflags & (NOTE_ATTRIB | NOTE_EXTEND)) + events = UV_CHANGE; + else + events = UV_RENAME; + + path = NULL; +#if defined(F_GETPATH) + /* Also works when the file has been unlinked from the file system. Passing + * in the path when the file has been deleted is arguably a little strange + * but it's consistent with what the inotify backend does. + */ + if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0) + path = uv__basename_r(pathbuf); +#endif + handle->cb(handle, path, events, 0); + + if (handle->event_watcher.fd == -1) + return; + + /* Watcher operates in one-shot mode, re-arm it. */ + fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME + | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE; + + EV_SET(&ev, w->fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, fflags, 0, 0); + + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + abort(); +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + return 0; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* path, + unsigned int flags) { +#if defined(__APPLE__) + struct stat statbuf; +#endif /* defined(__APPLE__) */ + int fd; + + if (uv__is_active(handle)) + return -EINVAL; + + /* TODO open asynchronously - but how do we report back errors? */ + fd = open(path, O_RDONLY); + if (fd == -1) + return -errno; + + uv__handle_start(handle); + uv__io_init(&handle->event_watcher, uv__fs_event, fd); + handle->path = uv__strdup(path); + handle->cb = cb; + +#if defined(__APPLE__) + /* Nullify field to perform checks later */ + handle->cf_cb = NULL; + handle->realpath = NULL; + handle->realpath_len = 0; + handle->cf_flags = flags; + + if (fstat(fd, &statbuf)) + goto fallback; + /* FSEvents works only with directories */ + if (!(statbuf.st_mode & S_IFDIR)) + goto fallback; + + /* The fallback fd is no longer needed */ + uv__close(fd); + handle->event_watcher.fd = -1; + + return uv__fsevents_init(handle); + +fallback: +#endif /* defined(__APPLE__) */ + + uv__io_start(handle->loop, &handle->event_watcher, POLLIN); + + return 0; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + if (!uv__is_active(handle)) + return 0; + + uv__handle_stop(handle); + +#if defined(__APPLE__) + if (uv__fsevents_close(handle)) +#endif /* defined(__APPLE__) */ + { + uv__io_close(handle->loop, &handle->event_watcher); + } + + uv__free(handle->path); + handle->path = NULL; + + if (handle->event_watcher.fd != -1) { + /* When FSEvents is used, we don't use the event_watcher's fd under certain + * confitions. (see uv_fs_event_start) */ + uv__close(handle->event_watcher.fd); + handle->event_watcher.fd = -1; + } + + return 0; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + uv_fs_event_stop(handle); +} diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c new file mode 100644 index 0000000..58dd813 --- /dev/null +++ b/src/unix/linux-core.c @@ -0,0 +1,985 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their + * EPOLL* counterparts. We use the POLL* variants in this file because that + * is what libuv uses elsewhere and it avoids a dependency on . + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define HAVE_IFADDRS_H 1 + +#ifdef __UCLIBC__ +# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32 +# undef HAVE_IFADDRS_H +# endif +#endif + +#ifdef HAVE_IFADDRS_H +# if defined(__ANDROID__) +# include "android-ifaddrs.h" +# else +# include +# endif +# include +# include +# include +#endif /* HAVE_IFADDRS_H */ + +/* Available from 2.6.32 onwards. */ +#ifndef CLOCK_MONOTONIC_COARSE +# define CLOCK_MONOTONIC_COARSE 6 +#endif + +/* This is rather annoying: CLOCK_BOOTTIME lives in but we can't + * include that file because it conflicts with . We'll just have to + * define it ourselves. + */ +#ifndef CLOCK_BOOTTIME +# define CLOCK_BOOTTIME 7 +#endif + +static int read_models(unsigned int numcpus, uv_cpu_info_t* ci); +static int read_times(FILE* statfile_fp, + unsigned int numcpus, + uv_cpu_info_t* ci); +static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); +static unsigned long read_cpufreq(unsigned int cpunum); + + +int uv__platform_loop_init(uv_loop_t* loop) { + int fd; + + fd = uv__epoll_create1(UV__EPOLL_CLOEXEC); + + /* epoll_create1() can fail either because it's not implemented (old kernel) + * or because it doesn't understand the EPOLL_CLOEXEC flag. + */ + if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) { + fd = uv__epoll_create(256); + + if (fd != -1) + uv__cloexec(fd, 1); + } + + loop->backend_fd = fd; + loop->inotify_fd = -1; + loop->inotify_watchers = NULL; + + if (fd == -1) + return -errno; + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->inotify_fd == -1) return; + uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN); + uv__close(loop->inotify_fd); + loop->inotify_fd = -1; +} + + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct uv__epoll_event* events; + struct uv__epoll_event dummy; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + + events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + if (events != NULL) + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].data == fd) + events[i].data = -1; + + /* Remove the file descriptor from the epoll. + * This avoids a problem where the same file description remains open + * in another process, causing repeated junk epoll events. + * + * We pass in a dummy epoll_event, to work around a bug in old kernels. + */ + if (loop->backend_fd >= 0) { + /* Work around a bug in kernels 3.10 to 3.19 where passing a struct that + * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings. + */ + memset(&dummy, 0, sizeof(dummy)); + uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy); + } +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct uv__epoll_event e; + int rc; + + e.events = POLLIN; + e.data = -1; + + rc = 0; + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e)) + if (errno != EEXIST) + rc = -errno; + + if (rc == 0) + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e)) + abort(); + + return rc; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes + * effectively infinite on 32 bits architectures. To avoid blocking + * indefinitely, we cap the timeout and poll again if necessary. + * + * Note that "30 minutes" is a simplification because it depends on + * the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200, + * that being the largest value I have seen in the wild (and only once.) + */ + static const int max_safe_timeout = 1789569; + static int no_epoll_pwait; + static int no_epoll_wait; + struct uv__epoll_event events[1024]; + struct uv__epoll_event* pe; + struct uv__epoll_event e; + int real_timeout; + QUEUE* q; + uv__io_t* w; + sigset_t sigset; + uint64_t sigmask; + uint64_t base; + int have_signals; + int nevents; + int count; + int nfds; + int fd; + int op; + int i; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + assert(w->fd >= 0); + assert(w->fd < (int) loop->nwatchers); + + e.events = w->pevents; + e.data = w->fd; + + if (w->events == 0) + op = UV__EPOLL_CTL_ADD; + else + op = UV__EPOLL_CTL_MOD; + + /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching + * events, skip the syscall and squelch the events after epoll_wait(). + */ + if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) { + if (errno != EEXIST) + abort(); + + assert(op == UV__EPOLL_CTL_ADD); + + /* We've reactivated a file descriptor that's been watched before. */ + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e)) + abort(); + } + + w->events = w->pevents; + } + + sigmask = 0; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + sigemptyset(&sigset); + sigaddset(&sigset, SIGPROF); + sigmask |= 1 << (SIGPROF - 1); + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + real_timeout = timeout; + + for (;;) { + /* See the comment for max_safe_timeout for an explanation of why + * this is necessary. Executive summary: kernel bug workaround. + */ + if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) + timeout = max_safe_timeout; + + if (sigmask != 0 && no_epoll_pwait != 0) + if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) + abort(); + + if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) { + nfds = uv__epoll_pwait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout, + sigmask); + if (nfds == -1 && errno == ENOSYS) + no_epoll_pwait = 1; + } else { + nfds = uv__epoll_wait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout); + if (nfds == -1 && errno == ENOSYS) + no_epoll_wait = 1; + } + + if (sigmask != 0 && no_epoll_pwait != 0) + if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL)) + abort(); + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (nfds == 0) { + assert(timeout != -1); + + if (timeout == 0) + return; + + /* We may have been inside the system call for longer than |timeout| + * milliseconds so we need to update the timestamp to avoid drift. + */ + goto update_timeout; + } + + if (nfds == -1) { + if (errno == ENOSYS) { + /* epoll_wait() or epoll_pwait() failed, try the other system call. */ + assert(no_epoll_wait == 0 || no_epoll_pwait == 0); + continue; + } + + if (errno != EINTR) + abort(); + + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + have_signals = 0; + nevents = 0; + + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + for (i = 0; i < nfds; i++) { + pe = events + i; + fd = pe->data; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (fd == -1) + continue; + + assert(fd >= 0); + assert((unsigned) fd < loop->nwatchers); + + w = loop->watchers[fd]; + + if (w == NULL) { + /* File descriptor that we've stopped watching, disarm it. + * + * Ignore all errors because we may be racing with another thread + * when the file descriptor is closed. + */ + uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe); + continue; + } + + /* Give users only events they're interested in. Prevents spurious + * callbacks when previous callback invocation in this loop has stopped + * the current watcher. Also, filters out events that users has not + * requested us to watch. + */ + pe->events &= w->pevents | POLLERR | POLLHUP; + + /* Work around an epoll quirk where it sometimes reports just the + * EPOLLERR or EPOLLHUP event. In order to force the event loop to + * move forward, we merge in the read/write events that the watcher + * is interested in; uv__read() and uv__write() will then deal with + * the error or hangup in the usual fashion. + * + * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user + * reads the available data, calls uv_read_stop(), then sometime later + * calls uv_read_start() again. By then, libuv has forgotten about the + * hangup and the kernel won't report EPOLLIN again because there's + * nothing left to read. If anything, libuv is to blame here. The + * current hack is just a quick bandaid; to properly fix it, libuv + * needs to remember the error/hangup event. We should get that for + * free when we switch over to edge-triggered I/O. + */ + if (pe->events == POLLERR || pe->events == POLLHUP) + pe->events |= w->pevents & (POLLIN | POLLOUT); + + if (pe->events != 0) { + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->events); + + nevents++; + } + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + real_timeout -= (loop->time - base); + if (real_timeout <= 0) + return; + + timeout = real_timeout; + } +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + static clock_t fast_clock_id = -1; + struct timespec t; + clock_t clock_id; + + /* Prefer CLOCK_MONOTONIC_COARSE if available but only when it has + * millisecond granularity or better. CLOCK_MONOTONIC_COARSE is + * serviced entirely from the vDSO, whereas CLOCK_MONOTONIC may + * decide to make a costly system call. + */ + /* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE + * when it has microsecond granularity or better (unlikely). + */ + if (type == UV_CLOCK_FAST && fast_clock_id == -1) { + if (clock_getres(CLOCK_MONOTONIC_COARSE, &t) == 0 && + t.tv_nsec <= 1 * 1000 * 1000) { + fast_clock_id = CLOCK_MONOTONIC_COARSE; + } else { + fast_clock_id = CLOCK_MONOTONIC; + } + } + + clock_id = CLOCK_MONOTONIC; + if (type == UV_CLOCK_FAST) + clock_id = fast_clock_id; + + if (clock_gettime(clock_id, &t)) + return 0; /* Not really possible. */ + + return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec; +} + + +void uv_loadavg(double avg[3]) { + struct sysinfo info; + + if (sysinfo(&info) < 0) return; + + avg[0] = (double) info.loads[0] / 65536.0; + avg[1] = (double) info.loads[1] / 65536.0; + avg[2] = (double) info.loads[2] / 65536.0; +} + + +int uv_exepath(char* buffer, size_t* size) { + ssize_t n; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + n = *size - 1; + if (n > 0) + n = readlink("/proc/self/exe", buffer, n); + + if (n == -1) + return -errno; + + buffer[n] = '\0'; + *size = n; + + return 0; +} + + +uint64_t uv_get_free_memory(void) { + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.freeram * info.mem_unit; + return 0; +} + + +uint64_t uv_get_total_memory(void) { + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.totalram * info.mem_unit; + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + char buf[1024]; + const char* s; + ssize_t n; + long val; + int fd; + int i; + + do + fd = open("/proc/self/stat", O_RDONLY); + while (fd == -1 && errno == EINTR); + + if (fd == -1) + return -errno; + + do + n = read(fd, buf, sizeof(buf) - 1); + while (n == -1 && errno == EINTR); + + uv__close(fd); + if (n == -1) + return -errno; + buf[n] = '\0'; + + s = strchr(buf, ' '); + if (s == NULL) + goto err; + + s += 1; + if (*s != '(') + goto err; + + s = strchr(s, ')'); + if (s == NULL) + goto err; + + for (i = 1; i <= 22; i++) { + s = strchr(s + 1, ' '); + if (s == NULL) + goto err; + } + + errno = 0; + val = strtol(s, NULL, 10); + if (errno != 0) + goto err; + if (val < 0) + goto err; + + *rss = val * getpagesize(); + return 0; + +err: + return -EINVAL; +} + + +int uv_uptime(double* uptime) { + static volatile int no_clock_boottime; + struct timespec now; + int r; + + /* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available + * (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system + * is suspended. + */ + if (no_clock_boottime) { + retry: r = clock_gettime(CLOCK_MONOTONIC, &now); + } + else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) { + no_clock_boottime = 1; + goto retry; + } + + if (r) + return -errno; + + *uptime = now.tv_sec; + return 0; +} + + +static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { + unsigned int num; + char buf[1024]; + + if (!fgets(buf, sizeof(buf), statfile_fp)) + return -EIO; + + num = 0; + while (fgets(buf, sizeof(buf), statfile_fp)) { + if (strncmp(buf, "cpu", 3)) + break; + num++; + } + + if (num == 0) + return -EIO; + + *numcpus = num; + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int numcpus; + uv_cpu_info_t* ci; + int err; + FILE* statfile_fp; + + *cpu_infos = NULL; + *count = 0; + + statfile_fp = uv__open_file("/proc/stat"); + if (statfile_fp == NULL) + return -errno; + + err = uv__cpu_num(statfile_fp, &numcpus); + if (err < 0) + goto out; + + err = -ENOMEM; + ci = uv__calloc(numcpus, sizeof(*ci)); + if (ci == NULL) + goto out; + + err = read_models(numcpus, ci); + if (err == 0) + err = read_times(statfile_fp, numcpus, ci); + + if (err) { + uv_free_cpu_info(ci, numcpus); + goto out; + } + + /* read_models() on x86 also reads the CPU speed from /proc/cpuinfo. + * We don't check for errors here. Worst case, the field is left zero. + */ + if (ci[0].speed == 0) + read_speeds(numcpus, ci); + + *cpu_infos = ci; + *count = numcpus; + err = 0; + +out: + + if (fclose(statfile_fp)) + if (errno != EINTR && errno != EINPROGRESS) + abort(); + + return err; +} + + +static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) { + unsigned int num; + + for (num = 0; num < numcpus; num++) + ci[num].speed = read_cpufreq(num) / 1000; +} + + +/* Also reads the CPU frequency on x86. The other architectures only have + * a BogoMIPS field, which may not be very accurate. + * + * Note: Simply returns on error, uv_cpu_info() takes care of the cleanup. + */ +static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { + static const char model_marker[] = "model name\t: "; + static const char speed_marker[] = "cpu MHz\t\t: "; + const char* inferred_model; + unsigned int model_idx; + unsigned int speed_idx; + char buf[1024]; + char* model; + FILE* fp; + + /* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */ + (void) &model_marker; + (void) &speed_marker; + (void) &speed_idx; + (void) &model; + (void) &buf; + (void) &fp; + + model_idx = 0; + speed_idx = 0; + +#if defined(__arm__) || \ + defined(__i386__) || \ + defined(__mips__) || \ + defined(__x86_64__) + fp = uv__open_file("/proc/cpuinfo"); + if (fp == NULL) + return -errno; + + while (fgets(buf, sizeof(buf), fp)) { + if (model_idx < numcpus) { + if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) { + model = buf + sizeof(model_marker) - 1; + model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */ + if (model == NULL) { + fclose(fp); + return -ENOMEM; + } + ci[model_idx++].model = model; + continue; + } + } +#if defined(__arm__) || defined(__mips__) + if (model_idx < numcpus) { +#if defined(__arm__) + /* Fallback for pre-3.8 kernels. */ + static const char model_marker[] = "Processor\t: "; +#else /* defined(__mips__) */ + static const char model_marker[] = "cpu model\t\t: "; +#endif + if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) { + model = buf + sizeof(model_marker) - 1; + model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */ + if (model == NULL) { + fclose(fp); + return -ENOMEM; + } + ci[model_idx++].model = model; + continue; + } + } +#else /* !__arm__ && !__mips__ */ + if (speed_idx < numcpus) { + if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) { + ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1); + continue; + } + } +#endif /* __arm__ || __mips__ */ + } + + fclose(fp); +#endif /* __arm__ || __i386__ || __mips__ || __x86_64__ */ + + /* Now we want to make sure that all the models contain *something* because + * it's not safe to leave them as null. Copy the last entry unless there + * isn't one, in that case we simply put "unknown" into everything. + */ + inferred_model = "unknown"; + if (model_idx > 0) + inferred_model = ci[model_idx - 1].model; + + while (model_idx < numcpus) { + model = uv__strndup(inferred_model, strlen(inferred_model)); + if (model == NULL) + return -ENOMEM; + ci[model_idx++].model = model; + } + + return 0; +} + + +static int read_times(FILE* statfile_fp, + unsigned int numcpus, + uv_cpu_info_t* ci) { + unsigned long clock_ticks; + struct uv_cpu_times_s ts; + unsigned long user; + unsigned long nice; + unsigned long sys; + unsigned long idle; + unsigned long dummy; + unsigned long irq; + unsigned int num; + unsigned int len; + char buf[1024]; + + clock_ticks = sysconf(_SC_CLK_TCK); + assert(clock_ticks != (unsigned long) -1); + assert(clock_ticks != 0); + + rewind(statfile_fp); + + if (!fgets(buf, sizeof(buf), statfile_fp)) + abort(); + + num = 0; + + while (fgets(buf, sizeof(buf), statfile_fp)) { + if (num >= numcpus) + break; + + if (strncmp(buf, "cpu", 3)) + break; + + /* skip "cpu " marker */ + { + unsigned int n; + int r = sscanf(buf, "cpu%u ", &n); + assert(r == 1); + (void) r; /* silence build warning */ + for (len = sizeof("cpu0"); n /= 10; len++); + } + + /* Line contains user, nice, system, idle, iowait, irq, softirq, steal, + * guest, guest_nice but we're only interested in the first four + irq. + * + * Don't use %*s to skip fields or %ll to read straight into the uint64_t + * fields, they're not allowed in C89 mode. + */ + if (6 != sscanf(buf + len, + "%lu %lu %lu %lu %lu %lu", + &user, + &nice, + &sys, + &idle, + &dummy, + &irq)) + abort(); + + ts.user = clock_ticks * user; + ts.nice = clock_ticks * nice; + ts.sys = clock_ticks * sys; + ts.idle = clock_ticks * idle; + ts.irq = clock_ticks * irq; + ci[num++].cpu_times = ts; + } + assert(num == numcpus); + + return 0; +} + + +static unsigned long read_cpufreq(unsigned int cpunum) { + unsigned long val; + char buf[1024]; + FILE* fp; + + snprintf(buf, + sizeof(buf), + "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", + cpunum); + + fp = uv__open_file(buf); + if (fp == NULL) + return 0; + + if (fscanf(fp, "%lu", &val) != 1) + val = 0; + + fclose(fp); + + return val; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, + int* count) { +#ifndef HAVE_IFADDRS_H + return -ENOSYS; +#else + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_ll *sll; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + *addresses = NULL; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family == PF_PACKET)) { + continue; + } + + (*count)++; + } + + if (*count == 0) + return 0; + + *addresses = uv__malloc(*count * sizeof(**addresses)); + if (!(*addresses)) { + freeifaddrs(addrs); + return -ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + /* + * On Linux getifaddrs returns information related to the raw underlying + * devices. We're not interested in this information yet. + */ + if (ent->ifa_addr->sa_family == PF_PACKET) + continue; + + address->name = uv__strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != PF_PACKET)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sll = (struct sockaddr_ll*)ent->ifa_addr; + memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +#endif +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(addresses[i].name); + } + + uv__free(addresses); +} + + +void uv__set_process_title(const char* title) { +#if defined(PR_SET_NAME) + prctl(PR_SET_NAME, title); /* Only copies first 16 characters. */ +#endif +} diff --git a/src/unix/linux-inotify.c b/src/unix/linux-inotify.c new file mode 100644 index 0000000..4708c05 --- /dev/null +++ b/src/unix/linux-inotify.c @@ -0,0 +1,285 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "tree.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +struct watcher_list { + RB_ENTRY(watcher_list) entry; + QUEUE watchers; + int iterating; + char* path; + int wd; +}; + +struct watcher_root { + struct watcher_list* rbh_root; +}; +#define CAST(p) ((struct watcher_root*)(p)) + + +static int compare_watchers(const struct watcher_list* a, + const struct watcher_list* b) { + if (a->wd < b->wd) return -1; + if (a->wd > b->wd) return 1; + return 0; +} + + +RB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers) + + +static void uv__inotify_read(uv_loop_t* loop, + uv__io_t* w, + unsigned int revents); + + +static int new_inotify_fd(void) { + int err; + int fd; + + fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC); + if (fd != -1) + return fd; + + if (errno != ENOSYS) + return -errno; + + fd = uv__inotify_init(); + if (fd == -1) + return -errno; + + err = uv__cloexec(fd, 1); + if (err == 0) + err = uv__nonblock(fd, 1); + + if (err) { + uv__close(fd); + return err; + } + + return fd; +} + + +static int init_inotify(uv_loop_t* loop) { + int err; + + if (loop->inotify_fd != -1) + return 0; + + err = new_inotify_fd(); + if (err < 0) + return err; + + loop->inotify_fd = err; + uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd); + uv__io_start(loop, &loop->inotify_read_watcher, POLLIN); + + return 0; +} + + +static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) { + struct watcher_list w; + w.wd = wd; + return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w); +} + +static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) { + /* if the watcher_list->watchers is being iterated over, we can't free it. */ + if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) { + /* No watchers left for this path. Clean up. */ + RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w); + uv__inotify_rm_watch(loop->inotify_fd, w->wd); + uv__free(w); + } +} + +static void uv__inotify_read(uv_loop_t* loop, + uv__io_t* dummy, + unsigned int events) { + const struct uv__inotify_event* e; + struct watcher_list* w; + uv_fs_event_t* h; + QUEUE queue; + QUEUE* q; + const char* path; + ssize_t size; + const char *p; + /* needs to be large enough for sizeof(inotify_event) + strlen(path) */ + char buf[4096]; + + while (1) { + do + size = read(loop->inotify_fd, buf, sizeof(buf)); + while (size == -1 && errno == EINTR); + + if (size == -1) { + assert(errno == EAGAIN || errno == EWOULDBLOCK); + break; + } + + assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */ + + /* Now we have one or more inotify_event structs. */ + for (p = buf; p < buf + size; p += sizeof(*e) + e->len) { + e = (const struct uv__inotify_event*)p; + + events = 0; + if (e->mask & (UV__IN_ATTRIB|UV__IN_MODIFY)) + events |= UV_CHANGE; + if (e->mask & ~(UV__IN_ATTRIB|UV__IN_MODIFY)) + events |= UV_RENAME; + + w = find_watcher(loop, e->wd); + if (w == NULL) + continue; /* Stale event, no watchers left. */ + + /* inotify does not return the filename when monitoring a single file + * for modifications. Repurpose the filename for API compatibility. + * I'm not convinced this is a good thing, maybe it should go. + */ + path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path); + + /* We're about to iterate over the queue and call user's callbacks. + * What can go wrong? + * A callback could call uv_fs_event_stop() + * and the queue can change under our feet. + * So, we use QUEUE_MOVE() trick to safely iterate over the queue. + * And we don't free the watcher_list until we're done iterating. + * + * First, + * tell uv_fs_event_stop() (that could be called from a user's callback) + * not to free watcher_list. + */ + w->iterating = 1; + QUEUE_MOVE(&w->watchers, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + h = QUEUE_DATA(q, uv_fs_event_t, watchers); + + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&w->watchers, q); + + h->cb(h, path, events, 0); + } + /* done iterating, time to (maybe) free empty watcher_list */ + w->iterating = 0; + maybe_free_watcher_list(w, loop); + } + } +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + return 0; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* path, + unsigned int flags) { + struct watcher_list* w; + int events; + int err; + int wd; + + if (uv__is_active(handle)) + return -EINVAL; + + err = init_inotify(handle->loop); + if (err) + return err; + + events = UV__IN_ATTRIB + | UV__IN_CREATE + | UV__IN_MODIFY + | UV__IN_DELETE + | UV__IN_DELETE_SELF + | UV__IN_MOVE_SELF + | UV__IN_MOVED_FROM + | UV__IN_MOVED_TO; + + wd = uv__inotify_add_watch(handle->loop->inotify_fd, path, events); + if (wd == -1) + return -errno; + + w = find_watcher(handle->loop, wd); + if (w) + goto no_insert; + + w = uv__malloc(sizeof(*w) + strlen(path) + 1); + if (w == NULL) + return -ENOMEM; + + w->wd = wd; + w->path = strcpy((char*)(w + 1), path); + QUEUE_INIT(&w->watchers); + w->iterating = 0; + RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w); + +no_insert: + uv__handle_start(handle); + QUEUE_INSERT_TAIL(&w->watchers, &handle->watchers); + handle->path = w->path; + handle->cb = cb; + handle->wd = wd; + + return 0; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + struct watcher_list* w; + + if (!uv__is_active(handle)) + return 0; + + w = find_watcher(handle->loop, handle->wd); + assert(w != NULL); + + handle->wd = -1; + handle->path = NULL; + uv__handle_stop(handle); + QUEUE_REMOVE(&handle->watchers); + + maybe_free_watcher_list(w, handle->loop); + + return 0; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + uv_fs_event_stop(handle); +} diff --git a/src/unix/linux-syscalls.c b/src/unix/linux-syscalls.c new file mode 100644 index 0000000..89998de --- /dev/null +++ b/src/unix/linux-syscalls.c @@ -0,0 +1,471 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "linux-syscalls.h" +#include +#include +#include +#include +#include + +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# define MSAN_ACTIVE 1 +# include +# endif +#endif + +#if defined(__i386__) +# ifndef __NR_socketcall +# define __NR_socketcall 102 +# endif +#endif + +#if defined(__arm__) +# if defined(__thumb__) || defined(__ARM_EABI__) +# define UV_SYSCALL_BASE 0 +# else +# define UV_SYSCALL_BASE 0x900000 +# endif +#endif /* __arm__ */ + +#ifndef __NR_accept4 +# if defined(__x86_64__) +# define __NR_accept4 288 +# elif defined(__i386__) + /* Nothing. Handled through socketcall(). */ +# elif defined(__arm__) +# define __NR_accept4 (UV_SYSCALL_BASE + 366) +# endif +#endif /* __NR_accept4 */ + +#ifndef __NR_eventfd +# if defined(__x86_64__) +# define __NR_eventfd 284 +# elif defined(__i386__) +# define __NR_eventfd 323 +# elif defined(__arm__) +# define __NR_eventfd (UV_SYSCALL_BASE + 351) +# endif +#endif /* __NR_eventfd */ + +#ifndef __NR_eventfd2 +# if defined(__x86_64__) +# define __NR_eventfd2 290 +# elif defined(__i386__) +# define __NR_eventfd2 328 +# elif defined(__arm__) +# define __NR_eventfd2 (UV_SYSCALL_BASE + 356) +# endif +#endif /* __NR_eventfd2 */ + +#ifndef __NR_epoll_create +# if defined(__x86_64__) +# define __NR_epoll_create 213 +# elif defined(__i386__) +# define __NR_epoll_create 254 +# elif defined(__arm__) +# define __NR_epoll_create (UV_SYSCALL_BASE + 250) +# endif +#endif /* __NR_epoll_create */ + +#ifndef __NR_epoll_create1 +# if defined(__x86_64__) +# define __NR_epoll_create1 291 +# elif defined(__i386__) +# define __NR_epoll_create1 329 +# elif defined(__arm__) +# define __NR_epoll_create1 (UV_SYSCALL_BASE + 357) +# endif +#endif /* __NR_epoll_create1 */ + +#ifndef __NR_epoll_ctl +# if defined(__x86_64__) +# define __NR_epoll_ctl 233 /* used to be 214 */ +# elif defined(__i386__) +# define __NR_epoll_ctl 255 +# elif defined(__arm__) +# define __NR_epoll_ctl (UV_SYSCALL_BASE + 251) +# endif +#endif /* __NR_epoll_ctl */ + +#ifndef __NR_epoll_wait +# if defined(__x86_64__) +# define __NR_epoll_wait 232 /* used to be 215 */ +# elif defined(__i386__) +# define __NR_epoll_wait 256 +# elif defined(__arm__) +# define __NR_epoll_wait (UV_SYSCALL_BASE + 252) +# endif +#endif /* __NR_epoll_wait */ + +#ifndef __NR_epoll_pwait +# if defined(__x86_64__) +# define __NR_epoll_pwait 281 +# elif defined(__i386__) +# define __NR_epoll_pwait 319 +# elif defined(__arm__) +# define __NR_epoll_pwait (UV_SYSCALL_BASE + 346) +# endif +#endif /* __NR_epoll_pwait */ + +#ifndef __NR_inotify_init +# if defined(__x86_64__) +# define __NR_inotify_init 253 +# elif defined(__i386__) +# define __NR_inotify_init 291 +# elif defined(__arm__) +# define __NR_inotify_init (UV_SYSCALL_BASE + 316) +# endif +#endif /* __NR_inotify_init */ + +#ifndef __NR_inotify_init1 +# if defined(__x86_64__) +# define __NR_inotify_init1 294 +# elif defined(__i386__) +# define __NR_inotify_init1 332 +# elif defined(__arm__) +# define __NR_inotify_init1 (UV_SYSCALL_BASE + 360) +# endif +#endif /* __NR_inotify_init1 */ + +#ifndef __NR_inotify_add_watch +# if defined(__x86_64__) +# define __NR_inotify_add_watch 254 +# elif defined(__i386__) +# define __NR_inotify_add_watch 292 +# elif defined(__arm__) +# define __NR_inotify_add_watch (UV_SYSCALL_BASE + 317) +# endif +#endif /* __NR_inotify_add_watch */ + +#ifndef __NR_inotify_rm_watch +# if defined(__x86_64__) +# define __NR_inotify_rm_watch 255 +# elif defined(__i386__) +# define __NR_inotify_rm_watch 293 +# elif defined(__arm__) +# define __NR_inotify_rm_watch (UV_SYSCALL_BASE + 318) +# endif +#endif /* __NR_inotify_rm_watch */ + +#ifndef __NR_pipe2 +# if defined(__x86_64__) +# define __NR_pipe2 293 +# elif defined(__i386__) +# define __NR_pipe2 331 +# elif defined(__arm__) +# define __NR_pipe2 (UV_SYSCALL_BASE + 359) +# endif +#endif /* __NR_pipe2 */ + +#ifndef __NR_recvmmsg +# if defined(__x86_64__) +# define __NR_recvmmsg 299 +# elif defined(__i386__) +# define __NR_recvmmsg 337 +# elif defined(__arm__) +# define __NR_recvmmsg (UV_SYSCALL_BASE + 365) +# endif +#endif /* __NR_recvmsg */ + +#ifndef __NR_sendmmsg +# if defined(__x86_64__) +# define __NR_sendmmsg 307 +# elif defined(__i386__) +# define __NR_sendmmsg 345 +# elif defined(__arm__) +# define __NR_sendmmsg (UV_SYSCALL_BASE + 374) +# endif +#endif /* __NR_sendmmsg */ + +#ifndef __NR_utimensat +# if defined(__x86_64__) +# define __NR_utimensat 280 +# elif defined(__i386__) +# define __NR_utimensat 320 +# elif defined(__arm__) +# define __NR_utimensat (UV_SYSCALL_BASE + 348) +# endif +#endif /* __NR_utimensat */ + +#ifndef __NR_preadv +# if defined(__x86_64__) +# define __NR_preadv 295 +# elif defined(__i386__) +# define __NR_preadv 333 +# elif defined(__arm__) +# define __NR_preadv (UV_SYSCALL_BASE + 361) +# endif +#endif /* __NR_preadv */ + +#ifndef __NR_pwritev +# if defined(__x86_64__) +# define __NR_pwritev 296 +# elif defined(__i386__) +# define __NR_pwritev 334 +# elif defined(__arm__) +# define __NR_pwritev (UV_SYSCALL_BASE + 362) +# endif +#endif /* __NR_pwritev */ + +#ifndef __NR_dup3 +# if defined(__x86_64__) +# define __NR_dup3 292 +# elif defined(__i386__) +# define __NR_dup3 330 +# elif defined(__arm__) +# define __NR_dup3 (UV_SYSCALL_BASE + 358) +# endif +#endif /* __NR_pwritev */ + + +int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) { +#if defined(__i386__) + unsigned long args[4]; + int r; + + args[0] = (unsigned long) fd; + args[1] = (unsigned long) addr; + args[2] = (unsigned long) addrlen; + args[3] = (unsigned long) flags; + + r = syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args); + + /* socketcall() raises EINVAL when SYS_ACCEPT4 is not supported but so does + * a bad flags argument. Try to distinguish between the two cases. + */ + if (r == -1) + if (errno == EINVAL) + if ((flags & ~(UV__SOCK_CLOEXEC|UV__SOCK_NONBLOCK)) == 0) + errno = ENOSYS; + + return r; +#elif defined(__NR_accept4) + return syscall(__NR_accept4, fd, addr, addrlen, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__eventfd(unsigned int count) { +#if defined(__NR_eventfd) + return syscall(__NR_eventfd, count); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__eventfd2(unsigned int count, int flags) { +#if defined(__NR_eventfd2) + return syscall(__NR_eventfd2, count, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__epoll_create(int size) { +#if defined(__NR_epoll_create) + return syscall(__NR_epoll_create, size); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__epoll_create1(int flags) { +#if defined(__NR_epoll_create1) + return syscall(__NR_epoll_create1, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event* events) { +#if defined(__NR_epoll_ctl) + return syscall(__NR_epoll_ctl, epfd, op, fd, events); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__epoll_wait(int epfd, + struct uv__epoll_event* events, + int nevents, + int timeout) { +#if defined(__NR_epoll_wait) + int result; + result = syscall(__NR_epoll_wait, epfd, events, nevents, timeout); +#if MSAN_ACTIVE + if (result > 0) + __msan_unpoison(events, sizeof(events[0]) * result); +#endif + return result; +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__epoll_pwait(int epfd, + struct uv__epoll_event* events, + int nevents, + int timeout, + uint64_t sigmask) { +#if defined(__NR_epoll_pwait) + int result; + result = syscall(__NR_epoll_pwait, + epfd, + events, + nevents, + timeout, + &sigmask, + sizeof(sigmask)); +#if MSAN_ACTIVE + if (result > 0) + __msan_unpoison(events, sizeof(events[0]) * result); +#endif + return result; +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__inotify_init(void) { +#if defined(__NR_inotify_init) + return syscall(__NR_inotify_init); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__inotify_init1(int flags) { +#if defined(__NR_inotify_init1) + return syscall(__NR_inotify_init1, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__inotify_add_watch(int fd, const char* path, uint32_t mask) { +#if defined(__NR_inotify_add_watch) + return syscall(__NR_inotify_add_watch, fd, path, mask); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__inotify_rm_watch(int fd, int32_t wd) { +#if defined(__NR_inotify_rm_watch) + return syscall(__NR_inotify_rm_watch, fd, wd); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__pipe2(int pipefd[2], int flags) { +#if defined(__NR_pipe2) + int result; + result = syscall(__NR_pipe2, pipefd, flags); +#if MSAN_ACTIVE + if (!result) + __msan_unpoison(pipefd, sizeof(int[2])); +#endif + return result; +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__sendmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags) { +#if defined(__NR_sendmmsg) + return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__recvmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags, + struct timespec* timeout) { +#if defined(__NR_recvmmsg) + return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__utimesat(int dirfd, + const char* path, + const struct timespec times[2], + int flags) +{ +#if defined(__NR_utimensat) + return syscall(__NR_utimensat, dirfd, path, times, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { +#if defined(__NR_preadv) + return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32)); +#else + return errno = ENOSYS, -1; +#endif +} + + +ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { +#if defined(__NR_pwritev) + return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32)); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__dup3(int oldfd, int newfd, int flags) { +#if defined(__NR_dup3) + return syscall(__NR_dup3, oldfd, newfd, flags); +#else + return errno = ENOSYS, -1; +#endif +} diff --git a/src/unix/linux-syscalls.h b/src/unix/linux-syscalls.h new file mode 100644 index 0000000..4c095e9 --- /dev/null +++ b/src/unix/linux-syscalls.h @@ -0,0 +1,151 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_LINUX_SYSCALL_H_ +#define UV_LINUX_SYSCALL_H_ + +#undef _GNU_SOURCE +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#if defined(__alpha__) +# define UV__O_CLOEXEC 0x200000 +#elif defined(__hppa__) +# define UV__O_CLOEXEC 0x200000 +#elif defined(__sparc__) +# define UV__O_CLOEXEC 0x400000 +#else +# define UV__O_CLOEXEC 0x80000 +#endif + +#if defined(__alpha__) +# define UV__O_NONBLOCK 0x4 +#elif defined(__hppa__) +# define UV__O_NONBLOCK O_NONBLOCK +#elif defined(__mips__) +# define UV__O_NONBLOCK 0x80 +#elif defined(__sparc__) +# define UV__O_NONBLOCK 0x4000 +#else +# define UV__O_NONBLOCK 0x800 +#endif + +#define UV__EFD_CLOEXEC UV__O_CLOEXEC +#define UV__EFD_NONBLOCK UV__O_NONBLOCK + +#define UV__IN_CLOEXEC UV__O_CLOEXEC +#define UV__IN_NONBLOCK UV__O_NONBLOCK + +#define UV__SOCK_CLOEXEC UV__O_CLOEXEC +#if defined(SOCK_NONBLOCK) +# define UV__SOCK_NONBLOCK SOCK_NONBLOCK +#else +# define UV__SOCK_NONBLOCK UV__O_NONBLOCK +#endif + +/* epoll flags */ +#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC +#define UV__EPOLL_CTL_ADD 1 +#define UV__EPOLL_CTL_DEL 2 +#define UV__EPOLL_CTL_MOD 3 + +/* inotify flags */ +#define UV__IN_ACCESS 0x001 +#define UV__IN_MODIFY 0x002 +#define UV__IN_ATTRIB 0x004 +#define UV__IN_CLOSE_WRITE 0x008 +#define UV__IN_CLOSE_NOWRITE 0x010 +#define UV__IN_OPEN 0x020 +#define UV__IN_MOVED_FROM 0x040 +#define UV__IN_MOVED_TO 0x080 +#define UV__IN_CREATE 0x100 +#define UV__IN_DELETE 0x200 +#define UV__IN_DELETE_SELF 0x400 +#define UV__IN_MOVE_SELF 0x800 + +#if defined(__x86_64__) +struct uv__epoll_event { + uint32_t events; + uint64_t data; +} __attribute__((packed)); +#else +struct uv__epoll_event { + uint32_t events; + uint64_t data; +}; +#endif + +struct uv__inotify_event { + int32_t wd; + uint32_t mask; + uint32_t cookie; + uint32_t len; + /* char name[0]; */ +}; + +struct uv__mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags); +int uv__eventfd(unsigned int count); +int uv__epoll_create(int size); +int uv__epoll_create1(int flags); +int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event *ev); +int uv__epoll_wait(int epfd, + struct uv__epoll_event* events, + int nevents, + int timeout); +int uv__epoll_pwait(int epfd, + struct uv__epoll_event* events, + int nevents, + int timeout, + uint64_t sigmask); +int uv__eventfd2(unsigned int count, int flags); +int uv__inotify_init(void); +int uv__inotify_init1(int flags); +int uv__inotify_add_watch(int fd, const char* path, uint32_t mask); +int uv__inotify_rm_watch(int fd, int32_t wd); +int uv__pipe2(int pipefd[2], int flags); +int uv__recvmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags, + struct timespec* timeout); +int uv__sendmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags); +int uv__utimesat(int dirfd, + const char* path, + const struct timespec times[2], + int flags); +ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset); +ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset); +int uv__dup3(int oldfd, int newfd, int flags); + +#endif /* UV_LINUX_SYSCALL_H_ */ diff --git a/src/unix/loop-watcher.c b/src/unix/loop-watcher.c new file mode 100644 index 0000000..340bb0d --- /dev/null +++ b/src/unix/loop-watcher.c @@ -0,0 +1,68 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#define UV_LOOP_WATCHER_DEFINE(name, type) \ + int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \ + uv__handle_init(loop, (uv_handle_t*)handle, UV_##type); \ + handle->name##_cb = NULL; \ + return 0; \ + } \ + \ + int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \ + if (uv__is_active(handle)) return 0; \ + if (cb == NULL) return -EINVAL; \ + QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \ + handle->name##_cb = cb; \ + uv__handle_start(handle); \ + return 0; \ + } \ + \ + int uv_##name##_stop(uv_##name##_t* handle) { \ + if (!uv__is_active(handle)) return 0; \ + QUEUE_REMOVE(&handle->queue); \ + uv__handle_stop(handle); \ + return 0; \ + } \ + \ + void uv__run_##name(uv_loop_t* loop) { \ + uv_##name##_t* h; \ + QUEUE queue; \ + QUEUE* q; \ + QUEUE_MOVE(&loop->name##_handles, &queue); \ + while (!QUEUE_EMPTY(&queue)) { \ + q = QUEUE_HEAD(&queue); \ + h = QUEUE_DATA(q, uv_##name##_t, queue); \ + QUEUE_REMOVE(q); \ + QUEUE_INSERT_TAIL(&loop->name##_handles, q); \ + h->name##_cb(h); \ + } \ + } \ + \ + void uv__##name##_close(uv_##name##_t* handle) { \ + uv_##name##_stop(handle); \ + } + +UV_LOOP_WATCHER_DEFINE(prepare, PREPARE) +UV_LOOP_WATCHER_DEFINE(check, CHECK) +UV_LOOP_WATCHER_DEFINE(idle, IDLE) diff --git a/src/unix/loop.c b/src/unix/loop.c new file mode 100644 index 0000000..bd63c2f --- /dev/null +++ b/src/unix/loop.c @@ -0,0 +1,159 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "tree.h" +#include "internal.h" +#include "heap-inl.h" +#include +#include +#include + +int uv_loop_init(uv_loop_t* loop) { + void* saved_data; + int err; + + uv__signal_global_once_init(); + + saved_data = loop->data; + memset(loop, 0, sizeof(*loop)); + loop->data = saved_data; + + heap_init((struct heap*) &loop->timer_heap); + QUEUE_INIT(&loop->wq); + QUEUE_INIT(&loop->active_reqs); + QUEUE_INIT(&loop->idle_handles); + QUEUE_INIT(&loop->async_handles); + QUEUE_INIT(&loop->check_handles); + QUEUE_INIT(&loop->prepare_handles); + QUEUE_INIT(&loop->handle_queue); + + loop->nfds = 0; + loop->watchers = NULL; + loop->nwatchers = 0; + QUEUE_INIT(&loop->pending_queue); + QUEUE_INIT(&loop->watcher_queue); + + loop->closing_handles = NULL; + uv__update_time(loop); + uv__async_init(&loop->async_watcher); + loop->signal_pipefd[0] = -1; + loop->signal_pipefd[1] = -1; + loop->backend_fd = -1; + loop->emfile_fd = -1; + + loop->timer_counter = 0; + loop->stop_flag = 0; + + err = uv__platform_loop_init(loop); + if (err) + return err; + + err = uv_signal_init(loop, &loop->child_watcher); + if (err) + goto fail_signal_init; + + uv__handle_unref(&loop->child_watcher); + loop->child_watcher.flags |= UV__HANDLE_INTERNAL; + QUEUE_INIT(&loop->process_handles); + + err = uv_rwlock_init(&loop->cloexec_lock); + if (err) + goto fail_rwlock_init; + + err = uv_mutex_init(&loop->wq_mutex); + if (err) + goto fail_mutex_init; + + err = uv_async_init(loop, &loop->wq_async, uv__work_done); + if (err) + goto fail_async_init; + + uv__handle_unref(&loop->wq_async); + loop->wq_async.flags |= UV__HANDLE_INTERNAL; + + return 0; + +fail_async_init: + uv_mutex_destroy(&loop->wq_mutex); + +fail_mutex_init: + uv_rwlock_destroy(&loop->cloexec_lock); + +fail_rwlock_init: + uv__signal_loop_cleanup(loop); + +fail_signal_init: + uv__platform_loop_delete(loop); + + return err; +} + + +void uv__loop_close(uv_loop_t* loop) { + uv__signal_loop_cleanup(loop); + uv__platform_loop_delete(loop); + uv__async_stop(loop, &loop->async_watcher); + + if (loop->emfile_fd != -1) { + uv__close(loop->emfile_fd); + loop->emfile_fd = -1; + } + + if (loop->backend_fd != -1) { + uv__close(loop->backend_fd); + loop->backend_fd = -1; + } + + uv_mutex_lock(&loop->wq_mutex); + assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!"); + assert(!uv__has_active_reqs(loop)); + uv_mutex_unlock(&loop->wq_mutex); + uv_mutex_destroy(&loop->wq_mutex); + + /* + * Note that all thread pool stuff is finished at this point and + * it is safe to just destroy rw lock + */ + uv_rwlock_destroy(&loop->cloexec_lock); + +#if 0 + assert(QUEUE_EMPTY(&loop->pending_queue)); + assert(QUEUE_EMPTY(&loop->watcher_queue)); + assert(loop->nfds == 0); +#endif + + uv__free(loop->watchers); + loop->watchers = NULL; + loop->nwatchers = 0; +} + + +int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) { + if (option != UV_LOOP_BLOCK_SIGNAL) + return UV_ENOSYS; + + if (va_arg(ap, int) != SIGPROF) + return UV_EINVAL; + + loop->flags |= UV_LOOP_BLOCK_SIGPROF; + return 0; +} diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c new file mode 100644 index 0000000..4a9e6cb --- /dev/null +++ b/src/unix/netbsd.c @@ -0,0 +1,380 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + +static char *process_title; + + +int uv__platform_loop_init(uv_loop_t* loop) { + return uv__kqueue_init(loop); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); +} + + +void uv_loadavg(double avg[3]) { + struct loadavg info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_LOADAVG}; + + if (sysctl(which, 2, &info, &size, NULL, 0) == -1) return; + + avg[0] = (double) info.ldavg[0] / info.fscale; + avg[1] = (double) info.ldavg[1] / info.fscale; + avg[2] = (double) info.ldavg[2] / info.fscale; +} + + +int uv_exepath(char* buffer, size_t* size) { + int mib[4]; + size_t cb; + pid_t mypid; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + mypid = getpid(); + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = mypid; + mib[3] = KERN_PROC_ARGV; + + cb = *size; + if (sysctl(mib, 4, buffer, &cb, NULL, 0)) + return -errno; + *size = strlen(buffer); + + return 0; +} + + +uint64_t uv_get_free_memory(void) { + struct uvmexp info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_UVMEXP}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info.free * sysconf(_SC_PAGESIZE); +} + + +uint64_t uv_get_total_memory(void) { +#if defined(HW_PHYSMEM64) + uint64_t info; + int which[] = {CTL_HW, HW_PHYSMEM64}; +#else + unsigned int info; + int which[] = {CTL_HW, HW_PHYSMEM}; +#endif + size_t size = sizeof(info); + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info; +} + + +char** uv_setup_args(int argc, char** argv) { + process_title = argc ? uv__strdup(argv[0]) : NULL; + return argv; +} + + +int uv_set_process_title(const char* title) { + if (process_title) uv__free(process_title); + + process_title = uv__strdup(title); + setproctitle("%s", title); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return -EINVAL; + + if (process_title) { + len = strlen(process_title) + 1; + + if (size < len) + return -ENOBUFS; + + memcpy(buffer, process_title, len); + } else { + len = 0; + } + + buffer[len] = '\0'; + + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + kvm_t *kd = NULL; + struct kinfo_proc2 *kinfo = NULL; + pid_t pid; + int nprocs; + int max_size = sizeof(struct kinfo_proc2); + int page_size; + + page_size = getpagesize(); + pid = getpid(); + + kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open"); + + if (kd == NULL) goto error; + + kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs); + if (kinfo == NULL) goto error; + + *rss = kinfo->p_vm_rssize * page_size; + + kvm_close(kd); + + return 0; + +error: + if (kd) kvm_close(kd); + return -EPERM; +} + + +int uv_uptime(double* uptime) { + time_t now; + struct timeval info; + size_t size = sizeof(info); + static int which[] = {CTL_KERN, KERN_BOOTTIME}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + now = time(NULL); + + *uptime = (double)(now - info.tv_sec); + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK); + unsigned int multiplier = ((uint64_t)1000L / ticks); + unsigned int cur = 0; + uv_cpu_info_t* cpu_info; + u_int64_t* cp_times; + char model[512]; + u_int64_t cpuspeed; + int numcpus; + size_t size; + int i; + + size = sizeof(model); + if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) && + sysctlbyname("hw.model", &model, &size, NULL, 0)) { + return -errno; + } + + size = sizeof(numcpus); + if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) + return -errno; + *count = numcpus; + + /* Only i386 and amd64 have machdep.tsc_freq */ + size = sizeof(cpuspeed); + if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0)) + cpuspeed = 0; + + size = numcpus * CPUSTATES * sizeof(*cp_times); + cp_times = uv__malloc(size); + if (cp_times == NULL) + return -ENOMEM; + + if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0)) + return -errno; + + *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) { + uv__free(cp_times); + uv__free(*cpu_infos); + return -ENOMEM; + } + + for (i = 0; i < numcpus; i++) { + cpu_info = &(*cpu_infos)[i]; + cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier; + cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier; + cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier; + cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier; + cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier; + cpu_info->model = uv__strdup(model); + cpu_info->speed = (int)(cpuspeed/(uint64_t) 1e6); + cur += CPUSTATES; + } + uv__free(cp_times); + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != PF_INET)) { + continue; + } + (*count)++; + } + + *addresses = uv__malloc(*count * sizeof(**addresses)); + + if (!(*addresses)) { + freeifaddrs(addrs); + return -ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + if (ent->ifa_addr->sa_family != PF_INET) + continue; + + address->name = uv__strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(addresses[i].name); + } + + uv__free(addresses); +} diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c new file mode 100644 index 0000000..909288c --- /dev/null +++ b/src/unix/openbsd.c @@ -0,0 +1,396 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + + +static char *process_title; + + +int uv__platform_loop_init(uv_loop_t* loop) { + return uv__kqueue_init(loop); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); +} + + +void uv_loadavg(double avg[3]) { + struct loadavg info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_LOADAVG}; + + if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return; + + avg[0] = (double) info.ldavg[0] / info.fscale; + avg[1] = (double) info.ldavg[1] / info.fscale; + avg[2] = (double) info.ldavg[2] / info.fscale; +} + + +int uv_exepath(char* buffer, size_t* size) { + int mib[4]; + char **argsbuf = NULL; + char **argsbuf_tmp; + size_t argsbuf_size = 100U; + size_t exepath_size; + pid_t mypid; + int err; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + mypid = getpid(); + for (;;) { + err = -ENOMEM; + argsbuf_tmp = uv__realloc(argsbuf, argsbuf_size); + if (argsbuf_tmp == NULL) + goto out; + argsbuf = argsbuf_tmp; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = mypid; + mib[3] = KERN_PROC_ARGV; + if (sysctl(mib, 4, argsbuf, &argsbuf_size, NULL, 0) == 0) { + break; + } + if (errno != ENOMEM) { + err = -errno; + goto out; + } + argsbuf_size *= 2U; + } + + if (argsbuf[0] == NULL) { + err = -EINVAL; /* FIXME(bnoordhuis) More appropriate error. */ + goto out; + } + + *size -= 1; + exepath_size = strlen(argsbuf[0]); + if (*size > exepath_size) + *size = exepath_size; + + memcpy(buffer, argsbuf[0], *size); + buffer[*size] = '\0'; + err = 0; + +out: + uv__free(argsbuf); + + return err; +} + + +uint64_t uv_get_free_memory(void) { + struct uvmexp info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_UVMEXP}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info.free * sysconf(_SC_PAGESIZE); +} + + +uint64_t uv_get_total_memory(void) { + uint64_t info; + int which[] = {CTL_HW, HW_PHYSMEM64}; + size_t size = sizeof(info); + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info; +} + + +char** uv_setup_args(int argc, char** argv) { + process_title = argc ? uv__strdup(argv[0]) : NULL; + return argv; +} + + +int uv_set_process_title(const char* title) { + uv__free(process_title); + process_title = uv__strdup(title); + setproctitle(title); + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return -EINVAL; + + if (process_title) { + len = strlen(process_title) + 1; + + if (size < len) + return -ENOBUFS; + + memcpy(buffer, process_title, len); + } else { + len = 0; + } + + buffer[len] = '\0'; + + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + struct kinfo_proc kinfo; + size_t page_size = getpagesize(); + size_t size = sizeof(struct kinfo_proc); + int mib[6]; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + mib[4] = sizeof(struct kinfo_proc); + mib[5] = 1; + + if (sysctl(mib, 6, &kinfo, &size, NULL, 0) < 0) + return -errno; + + *rss = kinfo.p_vm_rssize * page_size; + return 0; +} + + +int uv_uptime(double* uptime) { + time_t now; + struct timeval info; + size_t size = sizeof(info); + static int which[] = {CTL_KERN, KERN_BOOTTIME}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + now = time(NULL); + + *uptime = (double)(now - info.tv_sec); + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), + multiplier = ((uint64_t)1000L / ticks), cpuspeed; + uint64_t info[CPUSTATES]; + char model[512]; + int numcpus = 1; + int which[] = {CTL_HW,HW_MODEL,0}; + size_t size; + int i; + uv_cpu_info_t* cpu_info; + + size = sizeof(model); + if (sysctl(which, 2, &model, &size, NULL, 0)) + return -errno; + + which[1] = HW_NCPU; + size = sizeof(numcpus); + if (sysctl(which, 2, &numcpus, &size, NULL, 0)) + return -errno; + + *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) + return -ENOMEM; + + *count = numcpus; + + which[1] = HW_CPUSPEED; + size = sizeof(cpuspeed); + if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) { + uv__free(*cpu_infos); + return -errno; + } + + size = sizeof(info); + which[0] = CTL_KERN; + which[1] = KERN_CPTIME2; + for (i = 0; i < numcpus; i++) { + which[2] = i; + size = sizeof(info); + if (sysctl(which, 3, &info, &size, NULL, 0)) { + uv__free(*cpu_infos); + return -errno; + } + + cpu_info = &(*cpu_infos)[i]; + + cpu_info->cpu_times.user = (uint64_t)(info[CP_USER]) * multiplier; + cpu_info->cpu_times.nice = (uint64_t)(info[CP_NICE]) * multiplier; + cpu_info->cpu_times.sys = (uint64_t)(info[CP_SYS]) * multiplier; + cpu_info->cpu_times.idle = (uint64_t)(info[CP_IDLE]) * multiplier; + cpu_info->cpu_times.irq = (uint64_t)(info[CP_INTR]) * multiplier; + + cpu_info->model = uv__strdup(model); + cpu_info->speed = cpuspeed; + } + + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, + int* count) { + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; + + if (getifaddrs(&addrs) != 0) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != PF_INET)) { + continue; + } + (*count)++; + } + + *addresses = uv__malloc(*count * sizeof(**addresses)); + + if (!(*addresses)) { + freeifaddrs(addrs); + return -ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + if (ent->ifa_addr->sa_family != PF_INET) + continue; + + address->name = uv__strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(addresses[i].name); + } + + uv__free(addresses); +} diff --git a/src/unix/os390.c b/src/unix/os390.c new file mode 100644 index 0000000..bcdbc4b --- /dev/null +++ b/src/unix/os390.c @@ -0,0 +1,42 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * 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. + */ + +#include "internal.h" + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct pollfd p[1]; + int rv; + + p[0].fd = fd; + p[0].events = POLLIN; + + do + rv = poll(p, 1, 0); + while (rv == -1 && errno == EINTR); + + if (rv == -1) + abort(); + + if (p[0].revents & POLLNVAL) + return -1; + + return 0; +} diff --git a/src/unix/pipe.c b/src/unix/pipe.c new file mode 100644 index 0000000..b73994c --- /dev/null +++ b/src/unix/pipe.c @@ -0,0 +1,298 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + + +int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { + uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); + handle->shutdown_req = NULL; + handle->connect_req = NULL; + handle->pipe_fname = NULL; + handle->ipc = ipc; + return 0; +} + + +int uv_pipe_bind(uv_pipe_t* handle, const char* name) { + struct sockaddr_un saddr; + const char* pipe_fname; + int sockfd; + int err; + + pipe_fname = NULL; + sockfd = -1; + + /* Already bound? */ + if (uv__stream_fd(handle) >= 0) + return -EINVAL; + + /* Make a copy of the file name, it outlives this function's scope. */ + pipe_fname = uv__strdup(name); + if (pipe_fname == NULL) + return -ENOMEM; + + /* We've got a copy, don't touch the original any more. */ + name = NULL; + + err = uv__socket(AF_UNIX, SOCK_STREAM, 0); + if (err < 0) + goto err_socket; + sockfd = err; + + memset(&saddr, 0, sizeof saddr); + strncpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path) - 1); + saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0'; + saddr.sun_family = AF_UNIX; + + if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) { + err = -errno; + /* Convert ENOENT to EACCES for compatibility with Windows. */ + if (err == -ENOENT) + err = -EACCES; + goto err_bind; + } + + /* Success. */ + handle->flags |= UV_HANDLE_BOUND; + handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */ + handle->io_watcher.fd = sockfd; + return 0; + +err_bind: + uv__close(sockfd); + +err_socket: + uv__free((void*)pipe_fname); + return err; +} + + +int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { + if (uv__stream_fd(handle) == -1) + return -EINVAL; + +#if defined(__MVS__) + /* On zOS, backlog=0 has undefined behaviour */ + if (backlog == 0) + backlog = 1; + else if (backlog < 0) + backlog = SOMAXCONN; +#endif + + if (listen(uv__stream_fd(handle), backlog)) + return -errno; + + handle->connection_cb = cb; + handle->io_watcher.cb = uv__server_io; + uv__io_start(handle->loop, &handle->io_watcher, POLLIN); + return 0; +} + + +void uv__pipe_close(uv_pipe_t* handle) { + if (handle->pipe_fname) { + /* + * Unlink the file system entity before closing the file descriptor. + * Doing it the other way around introduces a race where our process + * unlinks a socket with the same name that's just been created by + * another thread or process. + */ + unlink(handle->pipe_fname); + uv__free((void*)handle->pipe_fname); + handle->pipe_fname = NULL; + } + + uv__stream_close((uv_stream_t*)handle); +} + + +int uv_pipe_open(uv_pipe_t* handle, uv_file fd) { + int err; + + err = uv__nonblock(fd, 1); + if (err) + return err; + +#if defined(__APPLE__) + err = uv__stream_try_select((uv_stream_t*) handle, &fd); + if (err) + return err; +#endif /* defined(__APPLE__) */ + + return uv__stream_open((uv_stream_t*)handle, + fd, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); +} + + +void uv_pipe_connect(uv_connect_t* req, + uv_pipe_t* handle, + const char* name, + uv_connect_cb cb) { + struct sockaddr_un saddr; + int new_sock; + int err; + int r; + + new_sock = (uv__stream_fd(handle) == -1); + + if (new_sock) { + err = uv__socket(AF_UNIX, SOCK_STREAM, 0); + if (err < 0) + goto out; + handle->io_watcher.fd = err; + } + + memset(&saddr, 0, sizeof saddr); + strncpy(saddr.sun_path, name, sizeof(saddr.sun_path) - 1); + saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0'; + saddr.sun_family = AF_UNIX; + + do { + r = connect(uv__stream_fd(handle), + (struct sockaddr*)&saddr, sizeof saddr); + } + while (r == -1 && errno == EINTR); + + if (r == -1 && errno != EINPROGRESS) { + err = -errno; + goto out; + } + + err = 0; + if (new_sock) { + err = uv__stream_open((uv_stream_t*)handle, + uv__stream_fd(handle), + UV_STREAM_READABLE | UV_STREAM_WRITABLE); + } + + if (err == 0) + uv__io_start(handle->loop, &handle->io_watcher, POLLIN | POLLOUT); + +out: + handle->delayed_error = err; + handle->connect_req = req; + + uv__req_init(handle->loop, req, UV_CONNECT); + req->handle = (uv_stream_t*)handle; + req->cb = cb; + QUEUE_INIT(&req->queue); + + /* Force callback to run on next tick in case of error. */ + if (err) + uv__io_feed(handle->loop, &handle->io_watcher); + +} + + +typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*); + + +static int uv__pipe_getsockpeername(const uv_pipe_t* handle, + uv__peersockfunc func, + char* buffer, + size_t* size) { + struct sockaddr_un sa; + socklen_t addrlen; + int err; + + addrlen = sizeof(sa); + memset(&sa, 0, addrlen); + err = func(uv__stream_fd(handle), (struct sockaddr*) &sa, &addrlen); + if (err < 0) { + *size = 0; + return -errno; + } + +#if defined(__linux__) + if (sa.sun_path[0] == 0) + /* Linux abstract namespace */ + addrlen -= offsetof(struct sockaddr_un, sun_path); + else +#endif + addrlen = strlen(sa.sun_path); + + + if (addrlen >= *size) { + *size = addrlen + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, sa.sun_path, addrlen); + *size = addrlen; + + /* only null-terminate if it's not an abstract socket */ + if (buffer[0] != '\0') + buffer[addrlen] = '\0'; + + return 0; +} + + +int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) { + return uv__pipe_getsockpeername(handle, getsockname, buffer, size); +} + + +int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) { + return uv__pipe_getsockpeername(handle, getpeername, buffer, size); +} + + +void uv_pipe_pending_instances(uv_pipe_t* handle, int count) { +} + + +int uv_pipe_pending_count(uv_pipe_t* handle) { + uv__stream_queued_fds_t* queued_fds; + + if (!handle->ipc) + return 0; + + if (handle->accepted_fd == -1) + return 0; + + if (handle->queued_fds == NULL) + return 1; + + queued_fds = handle->queued_fds; + return queued_fds->offset + 1; +} + + +uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { + if (!handle->ipc) + return UV_UNKNOWN_HANDLE; + + if (handle->accepted_fd == -1) + return UV_UNKNOWN_HANDLE; + else + return uv__handle_type(handle->accepted_fd); +} diff --git a/src/unix/poll.c b/src/unix/poll.c new file mode 100644 index 0000000..4c0d478 --- /dev/null +++ b/src/unix/poll.c @@ -0,0 +1,130 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + + +static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + uv_poll_t* handle; + int pevents; + + handle = container_of(w, uv_poll_t, io_watcher); + + if (events & POLLERR) { + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); + uv__handle_stop(handle); + handle->poll_cb(handle, -EBADF, 0); + return; + } + + pevents = 0; + if (events & POLLIN) + pevents |= UV_READABLE; + if (events & POLLOUT) + pevents |= UV_WRITABLE; + if (events & UV__POLLRDHUP) + pevents |= UV_DISCONNECT; + + handle->poll_cb(handle, 0, pevents); +} + + +int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { + int err; + + err = uv__io_check_fd(loop, fd); + if (err) + return err; + + /* If ioctl(FIONBIO) reports ENOTTY, try fcntl(F_GETFL) + fcntl(F_SETFL). + * Workaround for e.g. kqueue fds not supporting ioctls. + */ + err = uv__nonblock(fd, 1); + if (err == -ENOTTY) + if (uv__nonblock == uv__nonblock_ioctl) + err = uv__nonblock_fcntl(fd, 1); + + if (err) + return err; + + uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL); + uv__io_init(&handle->io_watcher, uv__poll_io, fd); + handle->poll_cb = NULL; + return 0; +} + + +int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, + uv_os_sock_t socket) { + return uv_poll_init(loop, handle, socket); +} + + +static void uv__poll_stop(uv_poll_t* handle) { + uv__io_stop(handle->loop, + &handle->io_watcher, + POLLIN | POLLOUT | UV__POLLRDHUP); + uv__handle_stop(handle); +} + + +int uv_poll_stop(uv_poll_t* handle) { + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + uv__poll_stop(handle); + return 0; +} + + +int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { + int events; + + assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + + uv__poll_stop(handle); + + if (pevents == 0) + return 0; + + events = 0; + if (pevents & UV_READABLE) + events |= POLLIN; + if (pevents & UV_WRITABLE) + events |= POLLOUT; + if (pevents & UV_DISCONNECT) + events |= UV__POLLRDHUP; + + uv__io_start(handle->loop, &handle->io_watcher, events); + uv__handle_start(handle); + handle->poll_cb = poll_cb; + + return 0; +} + + +void uv__poll_close(uv_poll_t* handle) { + uv__poll_stop(handle); +} diff --git a/src/unix/process.c b/src/unix/process.c new file mode 100644 index 0000000..45f5b45 --- /dev/null +++ b/src/unix/process.c @@ -0,0 +1,563 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(__APPLE__) && !TARGET_OS_IPHONE +# include +# define environ (*_NSGetEnviron()) +#else +extern char **environ; +#endif + +#if defined(__linux__) || defined(__GLIBC__) +# include +#endif + + +static void uv__chld(uv_signal_t* handle, int signum) { + uv_process_t* process; + uv_loop_t* loop; + int exit_status; + int term_signal; + int status; + pid_t pid; + QUEUE pending; + QUEUE* q; + QUEUE* h; + + assert(signum == SIGCHLD); + + QUEUE_INIT(&pending); + loop = handle->loop; + + h = &loop->process_handles; + q = QUEUE_HEAD(h); + while (q != h) { + process = QUEUE_DATA(q, uv_process_t, queue); + q = QUEUE_NEXT(q); + + do + pid = waitpid(process->pid, &status, WNOHANG); + while (pid == -1 && errno == EINTR); + + if (pid == 0) + continue; + + if (pid == -1) { + if (errno != ECHILD) + abort(); + continue; + } + + process->status = status; + QUEUE_REMOVE(&process->queue); + QUEUE_INSERT_TAIL(&pending, &process->queue); + } + + h = &pending; + q = QUEUE_HEAD(h); + while (q != h) { + process = QUEUE_DATA(q, uv_process_t, queue); + q = QUEUE_NEXT(q); + + QUEUE_REMOVE(&process->queue); + QUEUE_INIT(&process->queue); + uv__handle_stop(process); + + if (process->exit_cb == NULL) + continue; + + exit_status = 0; + if (WIFEXITED(process->status)) + exit_status = WEXITSTATUS(process->status); + + term_signal = 0; + if (WIFSIGNALED(process->status)) + term_signal = WTERMSIG(process->status); + + process->exit_cb(process, exit_status, term_signal); + } + assert(QUEUE_EMPTY(&pending)); +} + + +int uv__make_socketpair(int fds[2], int flags) { +#if defined(__linux__) + static int no_cloexec; + + if (no_cloexec) + goto skip; + + if (socketpair(AF_UNIX, SOCK_STREAM | UV__SOCK_CLOEXEC | flags, 0, fds) == 0) + return 0; + + /* Retry on EINVAL, it means SOCK_CLOEXEC is not supported. + * Anything else is a genuine error. + */ + if (errno != EINVAL) + return -errno; + + no_cloexec = 1; + +skip: +#endif + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) + return -errno; + + uv__cloexec(fds[0], 1); + uv__cloexec(fds[1], 1); + + if (flags & UV__F_NONBLOCK) { + uv__nonblock(fds[0], 1); + uv__nonblock(fds[1], 1); + } + + return 0; +} + + +int uv__make_pipe(int fds[2], int flags) { +#if defined(__linux__) + static int no_pipe2; + + if (no_pipe2) + goto skip; + + if (uv__pipe2(fds, flags | UV__O_CLOEXEC) == 0) + return 0; + + if (errno != ENOSYS) + return -errno; + + no_pipe2 = 1; + +skip: +#endif + + if (pipe(fds)) + return -errno; + + uv__cloexec(fds[0], 1); + uv__cloexec(fds[1], 1); + + if (flags & UV__F_NONBLOCK) { + uv__nonblock(fds[0], 1); + uv__nonblock(fds[1], 1); + } + + return 0; +} + + +/* + * Used for initializing stdio streams like options.stdin_stream. Returns + * zero on success. See also the cleanup section in uv_spawn(). + */ +static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { + int mask; + int fd; + + mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM; + + switch (container->flags & mask) { + case UV_IGNORE: + return 0; + + case UV_CREATE_PIPE: + assert(container->data.stream != NULL); + if (container->data.stream->type != UV_NAMED_PIPE) + return -EINVAL; + else + return uv__make_socketpair(fds, 0); + + case UV_INHERIT_FD: + case UV_INHERIT_STREAM: + if (container->flags & UV_INHERIT_FD) + fd = container->data.fd; + else + fd = uv__stream_fd(container->data.stream); + + if (fd == -1) + return -EINVAL; + + fds[1] = fd; + return 0; + + default: + assert(0 && "Unexpected flags"); + return -EINVAL; + } +} + + +static int uv__process_open_stream(uv_stdio_container_t* container, + int pipefds[2], + int writable) { + int flags; + int err; + + if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0) + return 0; + + err = uv__close(pipefds[1]); + if (err != 0) + abort(); + + pipefds[1] = -1; + uv__nonblock(pipefds[0], 1); + + if (container->data.stream->type == UV_NAMED_PIPE && + ((uv_pipe_t*)container->data.stream)->ipc) + flags = UV_STREAM_READABLE | UV_STREAM_WRITABLE; + else if (writable) + flags = UV_STREAM_WRITABLE; + else + flags = UV_STREAM_READABLE; + + return uv__stream_open(container->data.stream, pipefds[0], flags); +} + + +static void uv__process_close_stream(uv_stdio_container_t* container) { + if (!(container->flags & UV_CREATE_PIPE)) return; + uv__stream_close((uv_stream_t*)container->data.stream); +} + + +static void uv__write_int(int fd, int val) { + ssize_t n; + + do + n = write(fd, &val, sizeof(val)); + while (n == -1 && errno == EINTR); + + if (n == -1 && errno == EPIPE) + return; /* parent process has quit */ + + assert(n == sizeof(val)); +} + + +#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) +/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be + * avoided. Since this isn't called on those targets, the function + * doesn't even need to be defined for them. + */ +static void uv__process_child_init(const uv_process_options_t* options, + int stdio_count, + int (*pipes)[2], + int error_fd) { + int close_fd; + int use_fd; + int fd; + + if (options->flags & UV_PROCESS_DETACHED) + setsid(); + + /* First duplicate low numbered fds, since it's not safe to duplicate them, + * they could get replaced. Example: swapping stdout and stderr; without + * this fd 2 (stderr) would be duplicated into fd 1, thus making both + * stdout and stderr go to the same fd, which was not the intention. */ + for (fd = 0; fd < stdio_count; fd++) { + use_fd = pipes[fd][1]; + if (use_fd < 0 || use_fd >= fd) + continue; + pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); + if (pipes[fd][1] == -1) { + uv__write_int(error_fd, -errno); + _exit(127); + } + } + + for (fd = 0; fd < stdio_count; fd++) { + close_fd = pipes[fd][0]; + use_fd = pipes[fd][1]; + + if (use_fd < 0) { + if (fd >= 3) + continue; + else { + /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is + * set + */ + use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); + close_fd = use_fd; + + if (use_fd == -1) { + uv__write_int(error_fd, -errno); + _exit(127); + } + } + } + + if (fd == use_fd) + uv__cloexec(use_fd, 0); + else + fd = dup2(use_fd, fd); + + if (fd == -1) { + uv__write_int(error_fd, -errno); + _exit(127); + } + + if (fd <= 2) + uv__nonblock(fd, 0); + + if (close_fd >= stdio_count) + uv__close(close_fd); + } + + for (fd = 0; fd < stdio_count; fd++) { + use_fd = pipes[fd][1]; + + if (use_fd >= stdio_count) + uv__close(use_fd); + } + + if (options->cwd != NULL && chdir(options->cwd)) { + uv__write_int(error_fd, -errno); + _exit(127); + } + + if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) { + /* When dropping privileges from root, the `setgroups` call will + * remove any extraneous groups. If we don't call this, then + * even though our uid has dropped, we may still have groups + * that enable us to do super-user things. This will fail if we + * aren't root, so don't bother checking the return value, this + * is just done as an optimistic privilege dropping function. + */ + SAVE_ERRNO(setgroups(0, NULL)); + } + + if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) { + uv__write_int(error_fd, -errno); + _exit(127); + } + + if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) { + uv__write_int(error_fd, -errno); + _exit(127); + } + + if (options->env != NULL) { + environ = options->env; + } + + execvp(options->file, options->args); + uv__write_int(error_fd, -errno); + _exit(127); +} +#endif + + +int uv_spawn(uv_loop_t* loop, + uv_process_t* process, + const uv_process_options_t* options) { +#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) + /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */ + return -ENOSYS; +#else + int signal_pipe[2] = { -1, -1 }; + int (*pipes)[2]; + int stdio_count; + ssize_t r; + pid_t pid; + int err; + int exec_errorno; + int i; + int status; + + assert(options->file != NULL); + assert(!(options->flags & ~(UV_PROCESS_DETACHED | + UV_PROCESS_SETGID | + UV_PROCESS_SETUID | + UV_PROCESS_WINDOWS_HIDE | + UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); + + uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); + QUEUE_INIT(&process->queue); + + stdio_count = options->stdio_count; + if (stdio_count < 3) + stdio_count = 3; + + err = -ENOMEM; + pipes = uv__malloc(stdio_count * sizeof(*pipes)); + if (pipes == NULL) + goto error; + + for (i = 0; i < stdio_count; i++) { + pipes[i][0] = -1; + pipes[i][1] = -1; + } + + for (i = 0; i < options->stdio_count; i++) { + err = uv__process_init_stdio(options->stdio + i, pipes[i]); + if (err) + goto error; + } + + /* This pipe is used by the parent to wait until + * the child has called `execve()`. We need this + * to avoid the following race condition: + * + * if ((pid = fork()) > 0) { + * kill(pid, SIGTERM); + * } + * else if (pid == 0) { + * execve("/bin/cat", argp, envp); + * } + * + * The parent sends a signal immediately after forking. + * Since the child may not have called `execve()` yet, + * there is no telling what process receives the signal, + * our fork or /bin/cat. + * + * To avoid ambiguity, we create a pipe with both ends + * marked close-on-exec. Then, after the call to `fork()`, + * the parent polls the read end until it EOFs or errors with EPIPE. + */ + err = uv__make_pipe(signal_pipe, 0); + if (err) + goto error; + + uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); + + /* Acquire write lock to prevent opening new fds in worker threads */ + uv_rwlock_wrlock(&loop->cloexec_lock); + pid = fork(); + + if (pid == -1) { + err = -errno; + uv_rwlock_wrunlock(&loop->cloexec_lock); + uv__close(signal_pipe[0]); + uv__close(signal_pipe[1]); + goto error; + } + + if (pid == 0) { + uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]); + abort(); + } + + /* Release lock in parent process */ + uv_rwlock_wrunlock(&loop->cloexec_lock); + uv__close(signal_pipe[1]); + + process->status = 0; + exec_errorno = 0; + do + r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno)); + while (r == -1 && errno == EINTR); + + if (r == 0) + ; /* okay, EOF */ + else if (r == sizeof(exec_errorno)) { + do + err = waitpid(pid, &status, 0); /* okay, read errorno */ + while (err == -1 && errno == EINTR); + assert(err == pid); + } else if (r == -1 && errno == EPIPE) { + do + err = waitpid(pid, &status, 0); /* okay, got EPIPE */ + while (err == -1 && errno == EINTR); + assert(err == pid); + } else + abort(); + + uv__close_nocheckstdio(signal_pipe[0]); + + for (i = 0; i < options->stdio_count; i++) { + err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0); + if (err == 0) + continue; + + while (i--) + uv__process_close_stream(options->stdio + i); + + goto error; + } + + /* Only activate this handle if exec() happened successfully */ + if (exec_errorno == 0) { + QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue); + uv__handle_start(process); + } + + process->pid = pid; + process->exit_cb = options->exit_cb; + + uv__free(pipes); + return exec_errorno; + +error: + if (pipes != NULL) { + for (i = 0; i < stdio_count; i++) { + if (i < options->stdio_count) + if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM)) + continue; + if (pipes[i][0] != -1) + uv__close_nocheckstdio(pipes[i][0]); + if (pipes[i][1] != -1) + uv__close_nocheckstdio(pipes[i][1]); + } + uv__free(pipes); + } + + return err; +#endif +} + + +int uv_process_kill(uv_process_t* process, int signum) { + return uv_kill(process->pid, signum); +} + + +int uv_kill(int pid, int signum) { + if (kill(pid, signum)) + return -errno; + else + return 0; +} + + +void uv__process_close(uv_process_t* handle) { + QUEUE_REMOVE(&handle->queue); + uv__handle_stop(handle); + if (QUEUE_EMPTY(&handle->loop->process_handles)) + uv_signal_stop(&handle->loop->child_watcher); +} diff --git a/src/unix/proctitle.c b/src/unix/proctitle.c new file mode 100644 index 0000000..08d875f --- /dev/null +++ b/src/unix/proctitle.c @@ -0,0 +1,105 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +extern void uv__set_process_title(const char* title); + +static void* args_mem; + +static struct { + char* str; + size_t len; +} process_title; + + +char** uv_setup_args(int argc, char** argv) { + char** new_argv; + size_t size; + char* s; + int i; + + if (argc <= 0) + return argv; + + /* Calculate how much memory we need for the argv strings. */ + size = 0; + for (i = 0; i < argc; i++) + size += strlen(argv[i]) + 1; + + process_title.str = argv[0]; + process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0]; + assert(process_title.len + 1 == size); /* argv memory should be adjacent. */ + + /* Add space for the argv pointers. */ + size += (argc + 1) * sizeof(char*); + + new_argv = uv__malloc(size); + if (new_argv == NULL) + return argv; + args_mem = new_argv; + + /* Copy over the strings and set up the pointer table. */ + s = (char*) &new_argv[argc + 1]; + for (i = 0; i < argc; i++) { + size = strlen(argv[i]) + 1; + memcpy(s, argv[i], size); + new_argv[i] = s; + s += size; + } + new_argv[i] = NULL; + + return new_argv; +} + + +int uv_set_process_title(const char* title) { + if (process_title.len == 0) + return 0; + + /* No need to terminate, byte after is always '\0'. */ + strncpy(process_title.str, title, process_title.len); + uv__set_process_title(title); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + if (buffer == NULL || size == 0) + return -EINVAL; + else if (size <= process_title.len) + return -ENOBUFS; + + memcpy(buffer, process_title.str, process_title.len + 1); + buffer[process_title.len] = '\0'; + + return 0; +} + + +UV_DESTRUCTOR(static void free_args_mem(void)) { + uv__free(args_mem); /* Keep valgrind happy. */ + args_mem = NULL; +} diff --git a/src/unix/pthread-barrier.c b/src/unix/pthread-barrier.c new file mode 100644 index 0000000..f57bf25 --- /dev/null +++ b/src/unix/pthread-barrier.c @@ -0,0 +1,120 @@ +/* +Copyright (c) 2016, Kari Tristan Helgason + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +#include "uv-common.h" +#include "pthread-barrier.h" + +#include +#include + +/* TODO: support barrier_attr */ +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || count == 0) + return EINVAL; + + if (barrier_attr != NULL) + return ENOTSUP; + + b = uv__malloc(sizeof(*b)); + if (b == NULL) + return ENOMEM; + + b->in = 0; + b->out = 0; + b->threshold = count; + + if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) + goto error2; + if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) + goto error; + + barrier->b = b; + return 0; + +error: + pthread_mutex_destroy(&b->mutex); +error2: + uv__free(b); + return rc; +} + +int pthread_barrier_wait(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + /* Lock the mutex*/ + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + /* Increment the count. If this is the first thread to reach the threshold, + wake up waiters, unlock the mutex, then return + PTHREAD_BARRIER_SERIAL_THREAD. */ + if (++b->in == b->threshold) { + b->in = 0; + b->out = b->threshold - 1; + assert(pthread_cond_signal(&b->cond) == 0); + + pthread_mutex_unlock(&b->mutex); + return PTHREAD_BARRIER_SERIAL_THREAD; + } + /* Otherwise, wait for other threads until in is set to 0, + then return 0 to indicate this is not the first thread. */ + do { + if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) + break; + } while (b->in != 0); + + /* mark thread exit */ + b->out--; + pthread_cond_signal(&b->cond); + pthread_mutex_unlock(&b->mutex); + return rc; +} + +int pthread_barrier_destroy(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + if (b->in > 0 || b->out > 0) + rc = EBUSY; + + pthread_mutex_unlock(&b->mutex); + + if (rc) + return rc; + + pthread_cond_destroy(&b->cond); + pthread_mutex_destroy(&b->mutex); + uv__free(barrier->b); + barrier->b = NULL; + return 0; +} diff --git a/src/unix/pthread-fixes.c b/src/unix/pthread-fixes.c new file mode 100644 index 0000000..fb17995 --- /dev/null +++ b/src/unix/pthread-fixes.c @@ -0,0 +1,56 @@ +/* Copyright (c) 2013, Sony Mobile Communications AB + * Copyright (c) 2012, 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. +*/ + +/* Android versions < 4.1 have a broken pthread_sigmask. */ +#include +#include +#include + +int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) { + static int workaround; + int err; + + if (workaround) { + return sigprocmask(how, set, oset); + } else { + err = pthread_sigmask(how, set, oset); + if (err) { + if (err == EINVAL && sigprocmask(how, set, oset) == 0) { + workaround = 1; + return 0; + } else { + return -1; + } + } + } + + return 0; +} diff --git a/src/unix/signal.c b/src/unix/signal.c new file mode 100644 index 0000000..d82b9b7 --- /dev/null +++ b/src/unix/signal.c @@ -0,0 +1,467 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + + +typedef struct { + uv_signal_t* handle; + int signum; +} uv__signal_msg_t; + +RB_HEAD(uv__signal_tree_s, uv_signal_s); + + +static int uv__signal_unlock(void); +static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events); +static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2); +static void uv__signal_stop(uv_signal_t* handle); + + +static pthread_once_t uv__signal_global_init_guard = PTHREAD_ONCE_INIT; +static struct uv__signal_tree_s uv__signal_tree = + RB_INITIALIZER(uv__signal_tree); +static int uv__signal_lock_pipefd[2]; + + +RB_GENERATE_STATIC(uv__signal_tree_s, + uv_signal_s, tree_entry, + uv__signal_compare) + + +static void uv__signal_global_init(void) { + if (uv__make_pipe(uv__signal_lock_pipefd, 0)) + abort(); + + if (uv__signal_unlock()) + abort(); +} + + +void uv__signal_global_once_init(void) { + pthread_once(&uv__signal_global_init_guard, uv__signal_global_init); +} + + + +static int uv__signal_lock(void) { + int r; + char data; + + do { + r = read(uv__signal_lock_pipefd[0], &data, sizeof data); + } while (r < 0 && errno == EINTR); + + return (r < 0) ? -1 : 0; +} + + +static int uv__signal_unlock(void) { + int r; + char data = 42; + + do { + r = write(uv__signal_lock_pipefd[1], &data, sizeof data); + } while (r < 0 && errno == EINTR); + + return (r < 0) ? -1 : 0; +} + + +static void uv__signal_block_and_lock(sigset_t* saved_sigmask) { + sigset_t new_mask; + + if (sigfillset(&new_mask)) + abort(); + + if (pthread_sigmask(SIG_SETMASK, &new_mask, saved_sigmask)) + abort(); + + if (uv__signal_lock()) + abort(); +} + + +static void uv__signal_unlock_and_unblock(sigset_t* saved_sigmask) { + if (uv__signal_unlock()) + abort(); + + if (pthread_sigmask(SIG_SETMASK, saved_sigmask, NULL)) + abort(); +} + + +static uv_signal_t* uv__signal_first_handle(int signum) { + /* This function must be called with the signal lock held. */ + uv_signal_t lookup; + uv_signal_t* handle; + + lookup.signum = signum; + lookup.loop = NULL; + + handle = RB_NFIND(uv__signal_tree_s, &uv__signal_tree, &lookup); + + if (handle != NULL && handle->signum == signum) + return handle; + + return NULL; +} + + +static void uv__signal_handler(int signum) { + uv__signal_msg_t msg; + uv_signal_t* handle; + int saved_errno; + + saved_errno = errno; + memset(&msg, 0, sizeof msg); + + if (uv__signal_lock()) { + errno = saved_errno; + return; + } + + for (handle = uv__signal_first_handle(signum); + handle != NULL && handle->signum == signum; + handle = RB_NEXT(uv__signal_tree_s, &uv__signal_tree, handle)) { + int r; + + msg.signum = signum; + msg.handle = handle; + + /* write() should be atomic for small data chunks, so the entire message + * should be written at once. In theory the pipe could become full, in + * which case the user is out of luck. + */ + do { + r = write(handle->loop->signal_pipefd[1], &msg, sizeof msg); + } while (r == -1 && errno == EINTR); + + assert(r == sizeof msg || + (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))); + + if (r != -1) + handle->caught_signals++; + } + + uv__signal_unlock(); + errno = saved_errno; +} + + +static int uv__signal_register_handler(int signum) { + /* When this function is called, the signal lock must be held. */ + struct sigaction sa; + + /* XXX use a separate signal stack? */ + memset(&sa, 0, sizeof(sa)); + if (sigfillset(&sa.sa_mask)) + abort(); + sa.sa_handler = uv__signal_handler; + + /* XXX save old action so we can restore it later on? */ + if (sigaction(signum, &sa, NULL)) + return -errno; + + return 0; +} + + +static void uv__signal_unregister_handler(int signum) { + /* When this function is called, the signal lock must be held. */ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + + /* sigaction can only fail with EINVAL or EFAULT; an attempt to deregister a + * signal implies that it was successfully registered earlier, so EINVAL + * should never happen. + */ + if (sigaction(signum, &sa, NULL)) + abort(); +} + + +static int uv__signal_loop_once_init(uv_loop_t* loop) { + int err; + + /* Return if already initialized. */ + if (loop->signal_pipefd[0] != -1) + return 0; + + err = uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK); + if (err) + return err; + + uv__io_init(&loop->signal_io_watcher, + uv__signal_event, + loop->signal_pipefd[0]); + uv__io_start(loop, &loop->signal_io_watcher, POLLIN); + + return 0; +} + + +void uv__signal_loop_cleanup(uv_loop_t* loop) { + QUEUE* q; + + /* Stop all the signal watchers that are still attached to this loop. This + * ensures that the (shared) signal tree doesn't contain any invalid entries + * entries, and that signal handlers are removed when appropriate. + * It's safe to use QUEUE_FOREACH here because the handles and the handle + * queue are not modified by uv__signal_stop(). + */ + QUEUE_FOREACH(q, &loop->handle_queue) { + uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue); + + if (handle->type == UV_SIGNAL) + uv__signal_stop((uv_signal_t*) handle); + } + + if (loop->signal_pipefd[0] != -1) { + uv__close(loop->signal_pipefd[0]); + loop->signal_pipefd[0] = -1; + } + + if (loop->signal_pipefd[1] != -1) { + uv__close(loop->signal_pipefd[1]); + loop->signal_pipefd[1] = -1; + } +} + + +int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { + int err; + + err = uv__signal_loop_once_init(loop); + if (err) + return err; + + uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL); + handle->signum = 0; + handle->caught_signals = 0; + handle->dispatched_signals = 0; + + return 0; +} + + +void uv__signal_close(uv_signal_t* handle) { + + uv__signal_stop(handle); + + /* If there are any caught signals "trapped" in the signal pipe, we can't + * call the close callback yet. Otherwise, add the handle to the finish_close + * queue. + */ + if (handle->caught_signals == handle->dispatched_signals) { + uv__make_close_pending((uv_handle_t*) handle); + } +} + + +int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { + sigset_t saved_sigmask; + int err; + + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + + /* If the user supplies signum == 0, then return an error already. If the + * signum is otherwise invalid then uv__signal_register will find out + * eventually. + */ + if (signum == 0) + return -EINVAL; + + /* Short circuit: if the signal watcher is already watching {signum} don't + * go through the process of deregistering and registering the handler. + * Additionally, this avoids pending signals getting lost in the small time + * time frame that handle->signum == 0. + */ + if (signum == handle->signum) { + handle->signal_cb = signal_cb; + return 0; + } + + /* If the signal handler was already active, stop it first. */ + if (handle->signum != 0) { + uv__signal_stop(handle); + } + + uv__signal_block_and_lock(&saved_sigmask); + + /* If at this point there are no active signal watchers for this signum (in + * any of the loops), it's time to try and register a handler for it here. + */ + if (uv__signal_first_handle(signum) == NULL) { + err = uv__signal_register_handler(signum); + if (err) { + /* Registering the signal handler failed. Must be an invalid signal. */ + uv__signal_unlock_and_unblock(&saved_sigmask); + return err; + } + } + + handle->signum = signum; + RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle); + + uv__signal_unlock_and_unblock(&saved_sigmask); + + handle->signal_cb = signal_cb; + uv__handle_start(handle); + + return 0; +} + + +static void uv__signal_event(uv_loop_t* loop, + uv__io_t* w, + unsigned int events) { + uv__signal_msg_t* msg; + uv_signal_t* handle; + char buf[sizeof(uv__signal_msg_t) * 32]; + size_t bytes, end, i; + int r; + + bytes = 0; + end = 0; + + do { + r = read(loop->signal_pipefd[0], buf + bytes, sizeof(buf) - bytes); + + if (r == -1 && errno == EINTR) + continue; + + if (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { + /* If there are bytes in the buffer already (which really is extremely + * unlikely if possible at all) we can't exit the function here. We'll + * spin until more bytes are read instead. + */ + if (bytes > 0) + continue; + + /* Otherwise, there was nothing there. */ + return; + } + + /* Other errors really should never happen. */ + if (r == -1) + abort(); + + bytes += r; + + /* `end` is rounded down to a multiple of sizeof(uv__signal_msg_t). */ + end = (bytes / sizeof(uv__signal_msg_t)) * sizeof(uv__signal_msg_t); + + for (i = 0; i < end; i += sizeof(uv__signal_msg_t)) { + msg = (uv__signal_msg_t*) (buf + i); + handle = msg->handle; + + if (msg->signum == handle->signum) { + assert(!(handle->flags & UV_CLOSING)); + handle->signal_cb(handle, handle->signum); + } + + handle->dispatched_signals++; + + /* If uv_close was called while there were caught signals that were not + * yet dispatched, the uv__finish_close was deferred. Make close pending + * now if this has happened. + */ + if ((handle->flags & UV_CLOSING) && + (handle->caught_signals == handle->dispatched_signals)) { + uv__make_close_pending((uv_handle_t*) handle); + } + } + + bytes -= end; + + /* If there are any "partial" messages left, move them to the start of the + * the buffer, and spin. This should not happen. + */ + if (bytes) { + memmove(buf, buf + end, bytes); + continue; + } + } while (end == sizeof buf); +} + + +static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { + /* Compare signums first so all watchers with the same signnum end up + * adjacent. + */ + if (w1->signum < w2->signum) return -1; + if (w1->signum > w2->signum) return 1; + + /* Sort by loop pointer, so we can easily look up the first item after + * { .signum = x, .loop = NULL }. + */ + if (w1->loop < w2->loop) return -1; + if (w1->loop > w2->loop) return 1; + + if (w1 < w2) return -1; + if (w1 > w2) return 1; + + return 0; +} + + +int uv_signal_stop(uv_signal_t* handle) { + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + uv__signal_stop(handle); + return 0; +} + + +static void uv__signal_stop(uv_signal_t* handle) { + uv_signal_t* removed_handle; + sigset_t saved_sigmask; + + /* If the watcher wasn't started, this is a no-op. */ + if (handle->signum == 0) + return; + + uv__signal_block_and_lock(&saved_sigmask); + + removed_handle = RB_REMOVE(uv__signal_tree_s, &uv__signal_tree, handle); + assert(removed_handle == handle); + (void) removed_handle; + + /* Check if there are other active signal watchers observing this signal. If + * not, unregister the signal handler. + */ + if (uv__signal_first_handle(handle->signum) == NULL) + uv__signal_unregister_handler(handle->signum); + + uv__signal_unlock_and_unblock(&saved_sigmask); + + handle->signum = 0; + uv__handle_stop(handle); +} diff --git a/src/unix/spinlock.h b/src/unix/spinlock.h new file mode 100644 index 0000000..a20c83c --- /dev/null +++ b/src/unix/spinlock.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef UV_SPINLOCK_H_ +#define UV_SPINLOCK_H_ + +#include "internal.h" /* ACCESS_ONCE, UV_UNUSED */ +#include "atomic-ops.h" + +#define UV_SPINLOCK_INITIALIZER { 0 } + +typedef struct { + int lock; +} uv_spinlock_t; + +UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)); +UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)); +UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)); +UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)); + +UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)) { + ACCESS_ONCE(int, spinlock->lock) = 0; +} + +UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)) { + while (!uv_spinlock_trylock(spinlock)) cpu_relax(); +} + +UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)) { + ACCESS_ONCE(int, spinlock->lock) = 0; +} + +UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)) { + /* TODO(bnoordhuis) Maybe change to a ticket lock to guarantee fair queueing. + * Not really critical until we have locks that are (frequently) contended + * for by several threads. + */ + return 0 == cmpxchgi(&spinlock->lock, 0, 1); +} + +#endif /* UV_SPINLOCK_H_ */ diff --git a/src/unix/stream.c b/src/unix/stream.c new file mode 100644 index 0000000..d20d0bc --- /dev/null +++ b/src/unix/stream.c @@ -0,0 +1,1638 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include /* IOV_MAX */ + +#if defined(__APPLE__) +# include +# include +# include + +/* Forward declaration */ +typedef struct uv__stream_select_s uv__stream_select_t; + +struct uv__stream_select_s { + uv_stream_t* stream; + uv_thread_t thread; + uv_sem_t close_sem; + uv_sem_t async_sem; + uv_async_t async; + int events; + int fake_fd; + int int_fd; + int fd; + fd_set* sread; + size_t sread_sz; + fd_set* swrite; + size_t swrite_sz; +}; +#endif /* defined(__APPLE__) */ + +static void uv__stream_connect(uv_stream_t*); +static void uv__write(uv_stream_t* stream); +static void uv__read(uv_stream_t* stream); +static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); +static void uv__write_callbacks(uv_stream_t* stream); +static size_t uv__write_req_size(uv_write_t* req); + + +void uv__stream_init(uv_loop_t* loop, + uv_stream_t* stream, + uv_handle_type type) { + int err; + + uv__handle_init(loop, (uv_handle_t*)stream, type); + stream->read_cb = NULL; + stream->alloc_cb = NULL; + stream->close_cb = NULL; + stream->connection_cb = NULL; + stream->connect_req = NULL; + stream->shutdown_req = NULL; + stream->accepted_fd = -1; + stream->queued_fds = NULL; + stream->delayed_error = 0; + QUEUE_INIT(&stream->write_queue); + QUEUE_INIT(&stream->write_completed_queue); + stream->write_queue_size = 0; + + if (loop->emfile_fd == -1) { + err = uv__open_cloexec("/dev/null", O_RDONLY); + if (err < 0) + /* In the rare case that "/dev/null" isn't mounted open "/" + * instead. + */ + err = uv__open_cloexec("/", O_RDONLY); + if (err >= 0) + loop->emfile_fd = err; + } + +#if defined(__APPLE__) + stream->select = NULL; +#endif /* defined(__APPLE_) */ + + uv__io_init(&stream->io_watcher, uv__stream_io, -1); +} + + +static void uv__stream_osx_interrupt_select(uv_stream_t* stream) { +#if defined(__APPLE__) + /* Notify select() thread about state change */ + uv__stream_select_t* s; + int r; + + s = stream->select; + if (s == NULL) + return; + + /* Interrupt select() loop + * NOTE: fake_fd and int_fd are socketpair(), thus writing to one will + * emit read event on other side + */ + do + r = write(s->fake_fd, "x", 1); + while (r == -1 && errno == EINTR); + + assert(r == 1); +#else /* !defined(__APPLE__) */ + /* No-op on any other platform */ +#endif /* !defined(__APPLE__) */ +} + + +#if defined(__APPLE__) +static void uv__stream_osx_select(void* arg) { + uv_stream_t* stream; + uv__stream_select_t* s; + char buf[1024]; + int events; + int fd; + int r; + int max_fd; + + stream = arg; + s = stream->select; + fd = s->fd; + + if (fd > s->int_fd) + max_fd = fd; + else + max_fd = s->int_fd; + + while (1) { + /* Terminate on semaphore */ + if (uv_sem_trywait(&s->close_sem) == 0) + break; + + /* Watch fd using select(2) */ + memset(s->sread, 0, s->sread_sz); + memset(s->swrite, 0, s->swrite_sz); + + if (uv__io_active(&stream->io_watcher, POLLIN)) + FD_SET(fd, s->sread); + if (uv__io_active(&stream->io_watcher, POLLOUT)) + FD_SET(fd, s->swrite); + FD_SET(s->int_fd, s->sread); + + /* Wait indefinitely for fd events */ + r = select(max_fd + 1, s->sread, s->swrite, NULL, NULL); + if (r == -1) { + if (errno == EINTR) + continue; + + /* XXX: Possible?! */ + abort(); + } + + /* Ignore timeouts */ + if (r == 0) + continue; + + /* Empty socketpair's buffer in case of interruption */ + if (FD_ISSET(s->int_fd, s->sread)) + while (1) { + r = read(s->int_fd, buf, sizeof(buf)); + + if (r == sizeof(buf)) + continue; + + if (r != -1) + break; + + if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + + if (errno == EINTR) + continue; + + abort(); + } + + /* Handle events */ + events = 0; + if (FD_ISSET(fd, s->sread)) + events |= POLLIN; + if (FD_ISSET(fd, s->swrite)) + events |= POLLOUT; + + assert(events != 0 || FD_ISSET(s->int_fd, s->sread)); + if (events != 0) { + ACCESS_ONCE(int, s->events) = events; + + uv_async_send(&s->async); + uv_sem_wait(&s->async_sem); + + /* Should be processed at this stage */ + assert((s->events == 0) || (stream->flags & UV_CLOSING)); + } + } +} + + +static void uv__stream_osx_select_cb(uv_async_t* handle) { + uv__stream_select_t* s; + uv_stream_t* stream; + int events; + + s = container_of(handle, uv__stream_select_t, async); + stream = s->stream; + + /* Get and reset stream's events */ + events = s->events; + ACCESS_ONCE(int, s->events) = 0; + + assert(events != 0); + assert(events == (events & (POLLIN | POLLOUT))); + + /* Invoke callback on event-loop */ + if ((events & POLLIN) && uv__io_active(&stream->io_watcher, POLLIN)) + uv__stream_io(stream->loop, &stream->io_watcher, POLLIN); + + if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT)) + uv__stream_io(stream->loop, &stream->io_watcher, POLLOUT); + + if (stream->flags & UV_CLOSING) + return; + + /* NOTE: It is important to do it here, otherwise `select()` might be called + * before the actual `uv__read()`, leading to the blocking syscall + */ + uv_sem_post(&s->async_sem); +} + + +static void uv__stream_osx_cb_close(uv_handle_t* async) { + uv__stream_select_t* s; + + s = container_of(async, uv__stream_select_t, async); + uv__free(s); +} + + +int uv__stream_try_select(uv_stream_t* stream, int* fd) { + /* + * kqueue doesn't work with some files from /dev mount on osx. + * select(2) in separate thread for those fds + */ + + struct kevent filter[1]; + struct kevent events[1]; + struct timespec timeout; + uv__stream_select_t* s; + int fds[2]; + int err; + int ret; + int kq; + int old_fd; + int max_fd; + size_t sread_sz; + size_t swrite_sz; + + kq = kqueue(); + if (kq == -1) { + perror("(libuv) kqueue()"); + return -errno; + } + + EV_SET(&filter[0], *fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); + + /* Use small timeout, because we only want to capture EINVALs */ + timeout.tv_sec = 0; + timeout.tv_nsec = 1; + + do + ret = kevent(kq, filter, 1, events, 1, &timeout); + while (ret == -1 && errno == EINTR); + + uv__close(kq); + + if (ret == -1) + return -errno; + + if (ret == 0 || (events[0].flags & EV_ERROR) == 0 || events[0].data != EINVAL) + return 0; + + /* At this point we definitely know that this fd won't work with kqueue */ + + /* + * Create fds for io watcher and to interrupt the select() loop. + * NOTE: do it ahead of malloc below to allocate enough space for fd_sets + */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) + return -errno; + + max_fd = *fd; + if (fds[1] > max_fd) + max_fd = fds[1]; + + sread_sz = ROUND_UP(max_fd + 1, sizeof(uint32_t) * NBBY) / NBBY; + swrite_sz = sread_sz; + + s = uv__malloc(sizeof(*s) + sread_sz + swrite_sz); + if (s == NULL) { + err = -ENOMEM; + goto failed_malloc; + } + + s->events = 0; + s->fd = *fd; + s->sread = (fd_set*) ((char*) s + sizeof(*s)); + s->sread_sz = sread_sz; + s->swrite = (fd_set*) ((char*) s->sread + sread_sz); + s->swrite_sz = swrite_sz; + + err = uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb); + if (err) + goto failed_async_init; + + s->async.flags |= UV__HANDLE_INTERNAL; + uv__handle_unref(&s->async); + + err = uv_sem_init(&s->close_sem, 0); + if (err != 0) + goto failed_close_sem_init; + + err = uv_sem_init(&s->async_sem, 0); + if (err != 0) + goto failed_async_sem_init; + + s->fake_fd = fds[0]; + s->int_fd = fds[1]; + + old_fd = *fd; + s->stream = stream; + stream->select = s; + *fd = s->fake_fd; + + err = uv_thread_create(&s->thread, uv__stream_osx_select, stream); + if (err != 0) + goto failed_thread_create; + + return 0; + +failed_thread_create: + s->stream = NULL; + stream->select = NULL; + *fd = old_fd; + + uv_sem_destroy(&s->async_sem); + +failed_async_sem_init: + uv_sem_destroy(&s->close_sem); + +failed_close_sem_init: + uv__close(fds[0]); + uv__close(fds[1]); + uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close); + return err; + +failed_async_init: + uv__free(s); + +failed_malloc: + uv__close(fds[0]); + uv__close(fds[1]); + + return err; +} +#endif /* defined(__APPLE__) */ + + +int uv__stream_open(uv_stream_t* stream, int fd, int flags) { +#if defined(__APPLE__) + int enable; +#endif + + if (!(stream->io_watcher.fd == -1 || stream->io_watcher.fd == fd)) + return -EBUSY; + + assert(fd >= 0); + stream->flags |= flags; + + if (stream->type == UV_TCP) { + if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) + return -errno; + + /* TODO Use delay the user passed in. */ + if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60)) + return -errno; + } + +#if defined(__APPLE__) + enable = 1; + if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) && + errno != ENOTSOCK && + errno != EINVAL) { + return -errno; + } +#endif + + stream->io_watcher.fd = fd; + + return 0; +} + + +void uv__stream_flush_write_queue(uv_stream_t* stream, int error) { + uv_write_t* req; + QUEUE* q; + while (!QUEUE_EMPTY(&stream->write_queue)) { + q = QUEUE_HEAD(&stream->write_queue); + QUEUE_REMOVE(q); + + req = QUEUE_DATA(q, uv_write_t, queue); + req->error = error; + + QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue); + } +} + + +void uv__stream_destroy(uv_stream_t* stream) { + assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT)); + assert(stream->flags & UV_CLOSED); + + if (stream->connect_req) { + uv__req_unregister(stream->loop, stream->connect_req); + stream->connect_req->cb(stream->connect_req, -ECANCELED); + stream->connect_req = NULL; + } + + uv__stream_flush_write_queue(stream, -ECANCELED); + uv__write_callbacks(stream); + + if (stream->shutdown_req) { + /* The ECANCELED error code is a lie, the shutdown(2) syscall is a + * fait accompli at this point. Maybe we should revisit this in v0.11. + * A possible reason for leaving it unchanged is that it informs the + * callee that the handle has been destroyed. + */ + uv__req_unregister(stream->loop, stream->shutdown_req); + stream->shutdown_req->cb(stream->shutdown_req, -ECANCELED); + stream->shutdown_req = NULL; + } + + assert(stream->write_queue_size == 0); +} + + +/* Implements a best effort approach to mitigating accept() EMFILE errors. + * We have a spare file descriptor stashed away that we close to get below + * the EMFILE limit. Next, we accept all pending connections and close them + * immediately to signal the clients that we're overloaded - and we are, but + * we still keep on trucking. + * + * There is one caveat: it's not reliable in a multi-threaded environment. + * The file descriptor limit is per process. Our party trick fails if another + * thread opens a file or creates a socket in the time window between us + * calling close() and accept(). + */ +static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) { + int err; + int emfile_fd; + + if (loop->emfile_fd == -1) + return -EMFILE; + + uv__close(loop->emfile_fd); + loop->emfile_fd = -1; + + do { + err = uv__accept(accept_fd); + if (err >= 0) + uv__close(err); + } while (err >= 0 || err == -EINTR); + + emfile_fd = uv__open_cloexec("/", O_RDONLY); + if (emfile_fd >= 0) + loop->emfile_fd = emfile_fd; + + return err; +} + + +#if defined(UV_HAVE_KQUEUE) +# define UV_DEC_BACKLOG(w) w->rcount--; +#else +# define UV_DEC_BACKLOG(w) /* no-op */ +#endif /* defined(UV_HAVE_KQUEUE) */ + + +void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + uv_stream_t* stream; + int err; + + stream = container_of(w, uv_stream_t, io_watcher); + assert(events == POLLIN); + assert(stream->accepted_fd == -1); + assert(!(stream->flags & UV_CLOSING)); + + uv__io_start(stream->loop, &stream->io_watcher, POLLIN); + + /* connection_cb can close the server socket while we're + * in the loop so check it on each iteration. + */ + while (uv__stream_fd(stream) != -1) { + assert(stream->accepted_fd == -1); + +#if defined(UV_HAVE_KQUEUE) + if (w->rcount <= 0) + return; +#endif /* defined(UV_HAVE_KQUEUE) */ + + err = uv__accept(uv__stream_fd(stream)); + if (err < 0) { + if (err == -EAGAIN || err == -EWOULDBLOCK) + return; /* Not an error. */ + + if (err == -ECONNABORTED) + continue; /* Ignore. Nothing we can do about that. */ + + if (err == -EMFILE || err == -ENFILE) { + err = uv__emfile_trick(loop, uv__stream_fd(stream)); + if (err == -EAGAIN || err == -EWOULDBLOCK) + break; + } + + stream->connection_cb(stream, err); + continue; + } + + UV_DEC_BACKLOG(w) + stream->accepted_fd = err; + stream->connection_cb(stream, 0); + + if (stream->accepted_fd != -1) { + /* The user hasn't yet accepted called uv_accept() */ + uv__io_stop(loop, &stream->io_watcher, POLLIN); + return; + } + + if (stream->type == UV_TCP && (stream->flags & UV_TCP_SINGLE_ACCEPT)) { + /* Give other processes a chance to accept connections. */ + struct timespec timeout = { 0, 1 }; + nanosleep(&timeout, NULL); + } + } +} + + +#undef UV_DEC_BACKLOG + + +int uv_accept(uv_stream_t* server, uv_stream_t* client) { + int err; + + assert(server->loop == client->loop); + + if (server->accepted_fd == -1) + return -EAGAIN; + + switch (client->type) { + case UV_NAMED_PIPE: + case UV_TCP: + err = uv__stream_open(client, + server->accepted_fd, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); + if (err) { + /* TODO handle error */ + uv__close(server->accepted_fd); + goto done; + } + break; + + case UV_UDP: + err = uv_udp_open((uv_udp_t*) client, server->accepted_fd); + if (err) { + uv__close(server->accepted_fd); + goto done; + } + break; + + default: + return -EINVAL; + } + + client->flags |= UV_HANDLE_BOUND; + +done: + /* Process queued fds */ + if (server->queued_fds != NULL) { + uv__stream_queued_fds_t* queued_fds; + + queued_fds = server->queued_fds; + + /* Read first */ + server->accepted_fd = queued_fds->fds[0]; + + /* All read, free */ + assert(queued_fds->offset > 0); + if (--queued_fds->offset == 0) { + uv__free(queued_fds); + server->queued_fds = NULL; + } else { + /* Shift rest */ + memmove(queued_fds->fds, + queued_fds->fds + 1, + queued_fds->offset * sizeof(*queued_fds->fds)); + } + } else { + server->accepted_fd = -1; + if (err == 0) + uv__io_start(server->loop, &server->io_watcher, POLLIN); + } + return err; +} + + +int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { + int err; + + switch (stream->type) { + case UV_TCP: + err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb); + break; + + case UV_NAMED_PIPE: + err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb); + break; + + default: + err = -EINVAL; + } + + if (err == 0) + uv__handle_start(stream); + + return err; +} + + +static void uv__drain(uv_stream_t* stream) { + uv_shutdown_t* req; + int err; + + assert(QUEUE_EMPTY(&stream->write_queue)); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); + uv__stream_osx_interrupt_select(stream); + + /* Shutdown? */ + if ((stream->flags & UV_STREAM_SHUTTING) && + !(stream->flags & UV_CLOSING) && + !(stream->flags & UV_STREAM_SHUT)) { + assert(stream->shutdown_req); + + req = stream->shutdown_req; + stream->shutdown_req = NULL; + stream->flags &= ~UV_STREAM_SHUTTING; + uv__req_unregister(stream->loop, req); + + err = 0; + if (shutdown(uv__stream_fd(stream), SHUT_WR)) + err = -errno; + + if (err == 0) + stream->flags |= UV_STREAM_SHUT; + + if (req->cb != NULL) + req->cb(req, err); + } +} + + +static size_t uv__write_req_size(uv_write_t* req) { + size_t size; + + assert(req->bufs != NULL); + size = uv__count_bufs(req->bufs + req->write_index, + req->nbufs - req->write_index); + assert(req->handle->write_queue_size >= size); + + return size; +} + + +static void uv__write_req_finish(uv_write_t* req) { + uv_stream_t* stream = req->handle; + + /* Pop the req off tcp->write_queue. */ + QUEUE_REMOVE(&req->queue); + + /* Only free when there was no error. On error, we touch up write_queue_size + * right before making the callback. The reason we don't do that right away + * is that a write_queue_size > 0 is our only way to signal to the user that + * they should stop writing - which they should if we got an error. Something + * to revisit in future revisions of the libuv API. + */ + if (req->error == 0) { + if (req->bufs != req->bufsml) + uv__free(req->bufs); + req->bufs = NULL; + } + + /* Add it to the write_completed_queue where it will have its + * callback called in the near future. + */ + QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue); + uv__io_feed(stream->loop, &stream->io_watcher); +} + + +static int uv__handle_fd(uv_handle_t* handle) { + switch (handle->type) { + case UV_NAMED_PIPE: + case UV_TCP: + return ((uv_stream_t*) handle)->io_watcher.fd; + + case UV_UDP: + return ((uv_udp_t*) handle)->io_watcher.fd; + + default: + return -1; + } +} + +static void uv__write(uv_stream_t* stream) { + struct iovec* iov; + QUEUE* q; + uv_write_t* req; + int iovmax; + int iovcnt; + ssize_t n; + +start: + + assert(uv__stream_fd(stream) >= 0); + + if (QUEUE_EMPTY(&stream->write_queue)) + return; + + q = QUEUE_HEAD(&stream->write_queue); + req = QUEUE_DATA(q, uv_write_t, queue); + assert(req->handle == stream); + + /* + * Cast to iovec. We had to have our own uv_buf_t instead of iovec + * because Windows's WSABUF is not an iovec. + */ + assert(sizeof(uv_buf_t) == sizeof(struct iovec)); + iov = (struct iovec*) &(req->bufs[req->write_index]); + iovcnt = req->nbufs - req->write_index; + + iovmax = uv__getiovmax(); + + /* Limit iov count to avoid EINVALs from writev() */ + if (iovcnt > iovmax) + iovcnt = iovmax; + + /* + * Now do the actual writev. Note that we've been updating the pointers + * inside the iov each time we write. So there is no need to offset it. + */ + + if (req->send_handle) { + struct msghdr msg; + struct cmsghdr *cmsg; + int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); + char scratch[64] = {0}; + + assert(fd_to_send >= 0); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = iovcnt; + msg.msg_flags = 0; + + msg.msg_control = (void*) scratch; + msg.msg_controllen = CMSG_SPACE(sizeof(fd_to_send)); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send)); + + /* silence aliasing warning */ + { + void* pv = CMSG_DATA(cmsg); + int* pi = pv; + *pi = fd_to_send; + } + + do { + n = sendmsg(uv__stream_fd(stream), &msg, 0); + } +#if defined(__APPLE__) + /* + * Due to a possible kernel bug at least in OS X 10.10 "Yosemite", + * EPROTOTYPE can be returned while trying to write to a socket that is + * shutting down. If we retry the write, we should get the expected EPIPE + * instead. + */ + while (n == -1 && (errno == EINTR || errno == EPROTOTYPE)); +#else + while (n == -1 && errno == EINTR); +#endif + } else { + do { + if (iovcnt == 1) { + n = write(uv__stream_fd(stream), iov[0].iov_base, iov[0].iov_len); + } else { + n = writev(uv__stream_fd(stream), iov, iovcnt); + } + } +#if defined(__APPLE__) + /* + * Due to a possible kernel bug at least in OS X 10.10 "Yosemite", + * EPROTOTYPE can be returned while trying to write to a socket that is + * shutting down. If we retry the write, we should get the expected EPIPE + * instead. + */ + while (n == -1 && (errno == EINTR || errno == EPROTOTYPE)); +#else + while (n == -1 && errno == EINTR); +#endif + } + + if (n < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + /* Error */ + req->error = -errno; + uv__write_req_finish(req); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); + if (!uv__io_active(&stream->io_watcher, POLLIN)) + uv__handle_stop(stream); + uv__stream_osx_interrupt_select(stream); + return; + } else if (stream->flags & UV_STREAM_BLOCKING) { + /* If this is a blocking stream, try again. */ + goto start; + } + } else { + /* Successful write */ + + while (n >= 0) { + uv_buf_t* buf = &(req->bufs[req->write_index]); + size_t len = buf->len; + + assert(req->write_index < req->nbufs); + + if ((size_t)n < len) { + buf->base += n; + buf->len -= n; + stream->write_queue_size -= n; + n = 0; + + /* There is more to write. */ + if (stream->flags & UV_STREAM_BLOCKING) { + /* + * If we're blocking then we should not be enabling the write + * watcher - instead we need to try again. + */ + goto start; + } else { + /* Break loop and ensure the watcher is pending. */ + break; + } + + } else { + /* Finished writing the buf at index req->write_index. */ + req->write_index++; + + assert((size_t)n >= len); + n -= len; + + assert(stream->write_queue_size >= len); + stream->write_queue_size -= len; + + if (req->write_index == req->nbufs) { + /* Then we're done! */ + assert(n == 0); + uv__write_req_finish(req); + /* TODO: start trying to write the next request. */ + return; + } + } + } + } + + /* Either we've counted n down to zero or we've got EAGAIN. */ + assert(n == 0 || n == -1); + + /* Only non-blocking streams should use the write_watcher. */ + assert(!(stream->flags & UV_STREAM_BLOCKING)); + + /* We're not done. */ + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); + + /* Notify select() thread about state change */ + uv__stream_osx_interrupt_select(stream); +} + + +static void uv__write_callbacks(uv_stream_t* stream) { + uv_write_t* req; + QUEUE* q; + + while (!QUEUE_EMPTY(&stream->write_completed_queue)) { + /* Pop a req off write_completed_queue. */ + q = QUEUE_HEAD(&stream->write_completed_queue); + req = QUEUE_DATA(q, uv_write_t, queue); + QUEUE_REMOVE(q); + uv__req_unregister(stream->loop, req); + + if (req->bufs != NULL) { + stream->write_queue_size -= uv__write_req_size(req); + if (req->bufs != req->bufsml) + uv__free(req->bufs); + req->bufs = NULL; + } + + /* NOTE: call callback AFTER freeing the request data. */ + if (req->cb) + req->cb(req, req->error); + } + + assert(QUEUE_EMPTY(&stream->write_completed_queue)); +} + + +uv_handle_type uv__handle_type(int fd) { + struct sockaddr_storage ss; + socklen_t sslen; + socklen_t len; + int type; + + memset(&ss, 0, sizeof(ss)); + sslen = sizeof(ss); + + if (getsockname(fd, (struct sockaddr*)&ss, &sslen)) + return UV_UNKNOWN_HANDLE; + + len = sizeof type; + + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len)) + return UV_UNKNOWN_HANDLE; + + if (type == SOCK_STREAM) { +#if defined(_AIX) || defined(__DragonFly__) + /* on AIX/DragonFly the getsockname call returns an empty sa structure + * for sockets of type AF_UNIX. For all other types it will + * return a properly filled in structure. + */ + if (sslen == 0) + return UV_NAMED_PIPE; +#endif + switch (ss.ss_family) { + case AF_UNIX: + return UV_NAMED_PIPE; + case AF_INET: + case AF_INET6: + return UV_TCP; + } + } + + if (type == SOCK_DGRAM && + (ss.ss_family == AF_INET || ss.ss_family == AF_INET6)) + return UV_UDP; + + return UV_UNKNOWN_HANDLE; +} + + +static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) { + stream->flags |= UV_STREAM_READ_EOF; + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, POLLOUT)) + uv__handle_stop(stream); + uv__stream_osx_interrupt_select(stream); + stream->read_cb(stream, UV_EOF, buf); + stream->flags &= ~UV_STREAM_READING; +} + + +static int uv__stream_queue_fd(uv_stream_t* stream, int fd) { + uv__stream_queued_fds_t* queued_fds; + unsigned int queue_size; + + queued_fds = stream->queued_fds; + if (queued_fds == NULL) { + queue_size = 8; + queued_fds = uv__malloc((queue_size - 1) * sizeof(*queued_fds->fds) + + sizeof(*queued_fds)); + if (queued_fds == NULL) + return -ENOMEM; + queued_fds->size = queue_size; + queued_fds->offset = 0; + stream->queued_fds = queued_fds; + + /* Grow */ + } else if (queued_fds->size == queued_fds->offset) { + queue_size = queued_fds->size + 8; + queued_fds = uv__realloc(queued_fds, + (queue_size - 1) * sizeof(*queued_fds->fds) + + sizeof(*queued_fds)); + + /* + * Allocation failure, report back. + * NOTE: if it is fatal - sockets will be closed in uv__stream_close + */ + if (queued_fds == NULL) + return -ENOMEM; + queued_fds->size = queue_size; + stream->queued_fds = queued_fds; + } + + /* Put fd in a queue */ + queued_fds->fds[queued_fds->offset++] = fd; + + return 0; +} + + +#define UV__CMSG_FD_COUNT 64 +#define UV__CMSG_FD_SIZE (UV__CMSG_FD_COUNT * sizeof(int)) + + +static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) { + struct cmsghdr* cmsg; + + for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { + char* start; + char* end; + int err; + void* pv; + int* pi; + unsigned int i; + unsigned int count; + + if (cmsg->cmsg_type != SCM_RIGHTS) { + fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n", + cmsg->cmsg_type); + continue; + } + + /* silence aliasing warning */ + pv = CMSG_DATA(cmsg); + pi = pv; + + /* Count available fds */ + start = (char*) cmsg; + end = (char*) cmsg + cmsg->cmsg_len; + count = 0; + while (start + CMSG_LEN(count * sizeof(*pi)) < end) + count++; + assert(start + CMSG_LEN(count * sizeof(*pi)) == end); + + for (i = 0; i < count; i++) { + /* Already has accepted fd, queue now */ + if (stream->accepted_fd != -1) { + err = uv__stream_queue_fd(stream, pi[i]); + if (err != 0) { + /* Close rest */ + for (; i < count; i++) + uv__close(pi[i]); + return err; + } + } else { + stream->accepted_fd = pi[i]; + } + } + } + + return 0; +} + + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-folding-constant" +#endif + +static void uv__read(uv_stream_t* stream) { + uv_buf_t buf; + ssize_t nread; + struct msghdr msg; + char cmsg_space[CMSG_SPACE(UV__CMSG_FD_SIZE)]; + int count; + int err; + int is_ipc; + + stream->flags &= ~UV_STREAM_READ_PARTIAL; + + /* Prevent loop starvation when the data comes in as fast as (or faster than) + * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O. + */ + count = 32; + + is_ipc = stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) stream)->ipc; + + /* XXX: Maybe instead of having UV_STREAM_READING we just test if + * tcp->read_cb is NULL or not? + */ + while (stream->read_cb + && (stream->flags & UV_STREAM_READING) + && (count-- > 0)) { + assert(stream->alloc_cb != NULL); + + buf = uv_buf_init(NULL, 0); + stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf); + if (buf.base == NULL || buf.len == 0) { + /* User indicates it can't or won't handle the read. */ + stream->read_cb(stream, UV_ENOBUFS, &buf); + return; + } + + assert(buf.base != NULL); + assert(uv__stream_fd(stream) >= 0); + + if (!is_ipc) { + do { + nread = read(uv__stream_fd(stream), buf.base, buf.len); + } + while (nread < 0 && errno == EINTR); + } else { + /* ipc uses recvmsg */ + msg.msg_flags = 0; + msg.msg_iov = (struct iovec*) &buf; + msg.msg_iovlen = 1; + msg.msg_name = NULL; + msg.msg_namelen = 0; + /* Set up to receive a descriptor even if one isn't in the message */ + msg.msg_controllen = sizeof(cmsg_space); + msg.msg_control = cmsg_space; + + do { + nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0); + } + while (nread < 0 && errno == EINTR); + } + + if (nread < 0) { + /* Error */ + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* Wait for the next one. */ + if (stream->flags & UV_STREAM_READING) { + uv__io_start(stream->loop, &stream->io_watcher, POLLIN); + uv__stream_osx_interrupt_select(stream); + } + stream->read_cb(stream, 0, &buf); + } else { + /* Error. User should call uv_close(). */ + stream->read_cb(stream, -errno, &buf); + if (stream->flags & UV_STREAM_READING) { + stream->flags &= ~UV_STREAM_READING; + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, POLLOUT)) + uv__handle_stop(stream); + uv__stream_osx_interrupt_select(stream); + } + } + return; + } else if (nread == 0) { + uv__stream_eof(stream, &buf); + return; + } else { + /* Successful read */ + ssize_t buflen = buf.len; + + if (is_ipc) { + err = uv__stream_recv_cmsg(stream, &msg); + if (err != 0) { + stream->read_cb(stream, err, &buf); + return; + } + } + stream->read_cb(stream, nread, &buf); + + /* Return if we didn't fill the buffer, there is no more data to read. */ + if (nread < buflen) { + stream->flags |= UV_STREAM_READ_PARTIAL; + return; + } + } + } +} + + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + +#undef UV__CMSG_FD_COUNT +#undef UV__CMSG_FD_SIZE + + +int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { + assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE) && + "uv_shutdown (unix) only supports uv_handle_t right now"); + + if (!(stream->flags & UV_STREAM_WRITABLE) || + stream->flags & UV_STREAM_SHUT || + stream->flags & UV_STREAM_SHUTTING || + stream->flags & UV_CLOSED || + stream->flags & UV_CLOSING) { + return -ENOTCONN; + } + + assert(uv__stream_fd(stream) >= 0); + + /* Initialize request */ + uv__req_init(stream->loop, req, UV_SHUTDOWN); + req->handle = stream; + req->cb = cb; + stream->shutdown_req = req; + stream->flags |= UV_STREAM_SHUTTING; + + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); + uv__stream_osx_interrupt_select(stream); + + return 0; +} + + +static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + uv_stream_t* stream; + + stream = container_of(w, uv_stream_t, io_watcher); + + assert(stream->type == UV_TCP || + stream->type == UV_NAMED_PIPE || + stream->type == UV_TTY); + assert(!(stream->flags & UV_CLOSING)); + + if (stream->connect_req) { + uv__stream_connect(stream); + return; + } + + assert(uv__stream_fd(stream) >= 0); + + /* Ignore POLLHUP here. Even it it's set, there may still be data to read. */ + if (events & (POLLIN | POLLERR | POLLHUP)) + uv__read(stream); + + if (uv__stream_fd(stream) == -1) + return; /* read_cb closed stream. */ + + /* Short-circuit iff POLLHUP is set, the user is still interested in read + * events and uv__read() reported a partial read but not EOF. If the EOF + * flag is set, uv__read() called read_cb with err=UV_EOF and we don't + * have to do anything. If the partial read flag is not set, we can't + * report the EOF yet because there is still data to read. + */ + if ((events & POLLHUP) && + (stream->flags & UV_STREAM_READING) && + (stream->flags & UV_STREAM_READ_PARTIAL) && + !(stream->flags & UV_STREAM_READ_EOF)) { + uv_buf_t buf = { NULL, 0 }; + uv__stream_eof(stream, &buf); + } + + if (uv__stream_fd(stream) == -1) + return; /* read_cb closed stream. */ + + if (events & (POLLOUT | POLLERR | POLLHUP)) { + uv__write(stream); + uv__write_callbacks(stream); + + /* Write queue drained. */ + if (QUEUE_EMPTY(&stream->write_queue)) + uv__drain(stream); + } +} + + +/** + * We get called here from directly following a call to connect(2). + * In order to determine if we've errored out or succeeded must call + * getsockopt. + */ +static void uv__stream_connect(uv_stream_t* stream) { + int error; + uv_connect_t* req = stream->connect_req; + socklen_t errorsize = sizeof(int); + + assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE); + assert(req); + + if (stream->delayed_error) { + /* To smooth over the differences between unixes errors that + * were reported synchronously on the first connect can be delayed + * until the next tick--which is now. + */ + error = stream->delayed_error; + stream->delayed_error = 0; + } else { + /* Normal situation: we need to get the socket error from the kernel. */ + assert(uv__stream_fd(stream) >= 0); + getsockopt(uv__stream_fd(stream), + SOL_SOCKET, + SO_ERROR, + &error, + &errorsize); + error = -error; + } + + if (error == -EINPROGRESS) + return; + + stream->connect_req = NULL; + uv__req_unregister(stream->loop, req); + + if (error < 0 || QUEUE_EMPTY(&stream->write_queue)) { + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); + } + + if (req->cb) + req->cb(req, error); + + if (uv__stream_fd(stream) == -1) + return; + + if (error < 0) { + uv__stream_flush_write_queue(stream, -ECANCELED); + uv__write_callbacks(stream); + } +} + + +int uv_write2(uv_write_t* req, + uv_stream_t* stream, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb) { + int empty_queue; + + assert(nbufs > 0); + assert((stream->type == UV_TCP || + stream->type == UV_NAMED_PIPE || + stream->type == UV_TTY) && + "uv_write (unix) does not yet support other types of streams"); + + if (uv__stream_fd(stream) < 0) + return -EBADF; + + if (send_handle) { + if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) + return -EINVAL; + + /* XXX We abuse uv_write2() to send over UDP handles to child processes. + * Don't call uv__stream_fd() on those handles, it's a macro that on OS X + * evaluates to a function that operates on a uv_stream_t with a couple of + * OS X specific fields. On other Unices it does (handle)->io_watcher.fd, + * which works but only by accident. + */ + if (uv__handle_fd((uv_handle_t*) send_handle) < 0) + return -EBADF; + } + + /* It's legal for write_queue_size > 0 even when the write_queue is empty; + * it means there are error-state requests in the write_completed_queue that + * will touch up write_queue_size later, see also uv__write_req_finish(). + * We could check that write_queue is empty instead but that implies making + * a write() syscall when we know that the handle is in error mode. + */ + empty_queue = (stream->write_queue_size == 0); + + /* Initialize the req */ + uv__req_init(stream->loop, req, UV_WRITE); + req->cb = cb; + req->handle = stream; + req->error = 0; + req->send_handle = send_handle; + QUEUE_INIT(&req->queue); + + req->bufs = req->bufsml; + if (nbufs > ARRAY_SIZE(req->bufsml)) + req->bufs = uv__malloc(nbufs * sizeof(bufs[0])); + + if (req->bufs == NULL) + return -ENOMEM; + + memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); + req->nbufs = nbufs; + req->write_index = 0; + stream->write_queue_size += uv__count_bufs(bufs, nbufs); + + /* Append the request to write_queue. */ + QUEUE_INSERT_TAIL(&stream->write_queue, &req->queue); + + /* If the queue was empty when this function began, we should attempt to + * do the write immediately. Otherwise start the write_watcher and wait + * for the fd to become writable. + */ + if (stream->connect_req) { + /* Still connecting, do nothing. */ + } + else if (empty_queue) { + uv__write(stream); + } + else { + /* + * blocking streams should never have anything in the queue. + * if this assert fires then somehow the blocking stream isn't being + * sufficiently flushed in uv__write. + */ + assert(!(stream->flags & UV_STREAM_BLOCKING)); + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); + uv__stream_osx_interrupt_select(stream); + } + + return 0; +} + + +/* The buffers to be written must remain valid until the callback is called. + * This is not required for the uv_buf_t array. + */ +int uv_write(uv_write_t* req, + uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb) { + return uv_write2(req, handle, bufs, nbufs, NULL, cb); +} + + +void uv_try_write_cb(uv_write_t* req, int status) { + /* Should not be called */ + abort(); +} + + +int uv_try_write(uv_stream_t* stream, + const uv_buf_t bufs[], + unsigned int nbufs) { + int r; + int has_pollout; + size_t written; + size_t req_size; + uv_write_t req; + + /* Connecting or already writing some data */ + if (stream->connect_req != NULL || stream->write_queue_size != 0) + return -EAGAIN; + + has_pollout = uv__io_active(&stream->io_watcher, POLLOUT); + + r = uv_write(&req, stream, bufs, nbufs, uv_try_write_cb); + if (r != 0) + return r; + + /* Remove not written bytes from write queue size */ + written = uv__count_bufs(bufs, nbufs); + if (req.bufs != NULL) + req_size = uv__write_req_size(&req); + else + req_size = 0; + written -= req_size; + stream->write_queue_size -= req_size; + + /* Unqueue request, regardless of immediateness */ + QUEUE_REMOVE(&req.queue); + uv__req_unregister(stream->loop, &req); + if (req.bufs != req.bufsml) + uv__free(req.bufs); + req.bufs = NULL; + + /* Do not poll for writable, if we wasn't before calling this */ + if (!has_pollout) { + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); + uv__stream_osx_interrupt_select(stream); + } + + if (written == 0 && req_size != 0) + return -EAGAIN; + else + return written; +} + + +int uv_read_start(uv_stream_t* stream, + uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { + assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || + stream->type == UV_TTY); + + if (stream->flags & UV_CLOSING) + return -EINVAL; + + /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just + * expresses the desired state of the user. + */ + stream->flags |= UV_STREAM_READING; + + /* TODO: try to do the read inline? */ + /* TODO: keep track of tcp state. If we've gotten a EOF then we should + * not start the IO watcher. + */ + assert(uv__stream_fd(stream) >= 0); + assert(alloc_cb); + + stream->read_cb = read_cb; + stream->alloc_cb = alloc_cb; + + uv__io_start(stream->loop, &stream->io_watcher, POLLIN); + uv__handle_start(stream); + uv__stream_osx_interrupt_select(stream); + + return 0; +} + + +int uv_read_stop(uv_stream_t* stream) { + if (!(stream->flags & UV_STREAM_READING)) + return 0; + + stream->flags &= ~UV_STREAM_READING; + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, POLLOUT)) + uv__handle_stop(stream); + uv__stream_osx_interrupt_select(stream); + + stream->read_cb = NULL; + stream->alloc_cb = NULL; + return 0; +} + + +int uv_is_readable(const uv_stream_t* stream) { + return !!(stream->flags & UV_STREAM_READABLE); +} + + +int uv_is_writable(const uv_stream_t* stream) { + return !!(stream->flags & UV_STREAM_WRITABLE); +} + + +#if defined(__APPLE__) +int uv___stream_fd(const uv_stream_t* handle) { + const uv__stream_select_t* s; + + assert(handle->type == UV_TCP || + handle->type == UV_TTY || + handle->type == UV_NAMED_PIPE); + + s = handle->select; + if (s != NULL) + return s->fd; + + return handle->io_watcher.fd; +} +#endif /* defined(__APPLE__) */ + + +void uv__stream_close(uv_stream_t* handle) { + unsigned int i; + uv__stream_queued_fds_t* queued_fds; + +#if defined(__APPLE__) + /* Terminate select loop first */ + if (handle->select != NULL) { + uv__stream_select_t* s; + + s = handle->select; + + uv_sem_post(&s->close_sem); + uv_sem_post(&s->async_sem); + uv__stream_osx_interrupt_select(handle); + uv_thread_join(&s->thread); + uv_sem_destroy(&s->close_sem); + uv_sem_destroy(&s->async_sem); + uv__close(s->fake_fd); + uv__close(s->int_fd); + uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close); + + handle->select = NULL; + } +#endif /* defined(__APPLE__) */ + + uv__io_close(handle->loop, &handle->io_watcher); + uv_read_stop(handle); + uv__handle_stop(handle); + + if (handle->io_watcher.fd != -1) { + /* Don't close stdio file descriptors. Nothing good comes from it. */ + if (handle->io_watcher.fd > STDERR_FILENO) + uv__close(handle->io_watcher.fd); + handle->io_watcher.fd = -1; + } + + if (handle->accepted_fd != -1) { + uv__close(handle->accepted_fd); + handle->accepted_fd = -1; + } + + /* Close all queued fds */ + if (handle->queued_fds != NULL) { + queued_fds = handle->queued_fds; + for (i = 0; i < queued_fds->offset; i++) + uv__close(queued_fds->fds[i]); + uv__free(handle->queued_fds); + handle->queued_fds = NULL; + } + + assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT)); +} + + +int uv_stream_set_blocking(uv_stream_t* handle, int blocking) { + /* Don't need to check the file descriptor, uv__nonblock() + * will fail with EBADF if it's not valid. + */ + return uv__nonblock(uv__stream_fd(handle), !blocking); +} diff --git a/src/unix/sunos.c b/src/unix/sunos.c new file mode 100644 index 0000000..3e7a759 --- /dev/null +++ b/src/unix/sunos.c @@ -0,0 +1,821 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#ifndef SUNOS_NO_IFADDRS +# include +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#define PORT_FIRED 0x69 +#define PORT_UNUSED 0x0 +#define PORT_LOADED 0x99 +#define PORT_DELETED -1 + +#if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64) +#define PROCFS_FILE_OFFSET_BITS_HACK 1 +#undef _FILE_OFFSET_BITS +#else +#define PROCFS_FILE_OFFSET_BITS_HACK 0 +#endif + +#include + +#if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1) +#define _FILE_OFFSET_BITS 64 +#endif + + +int uv__platform_loop_init(uv_loop_t* loop) { + int err; + int fd; + + loop->fs_fd = -1; + loop->backend_fd = -1; + + fd = port_create(); + if (fd == -1) + return -errno; + + err = uv__cloexec(fd, 1); + if (err) { + uv__close(fd); + return err; + } + loop->backend_fd = fd; + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->fs_fd != -1) { + uv__close(loop->fs_fd); + loop->fs_fd = -1; + } + + if (loop->backend_fd != -1) { + uv__close(loop->backend_fd); + loop->backend_fd = -1; + } +} + + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct port_event* events; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + + events = (struct port_event*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + if (events == NULL) + return; + + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].portev_object == fd) + events[i].portev_object = -1; +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0)) + return -errno; + + if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) + abort(); + + return 0; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + struct port_event events[1024]; + struct port_event* pe; + struct timespec spec; + QUEUE* q; + uv__io_t* w; + sigset_t* pset; + sigset_t set; + uint64_t base; + uint64_t diff; + unsigned int nfds; + unsigned int i; + int saved_errno; + int have_signals; + int nevents; + int count; + int err; + int fd; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + + if (port_associate(loop->backend_fd, PORT_SOURCE_FD, w->fd, w->pevents, 0)) + abort(); + + w->events = w->pevents; + } + + pset = NULL; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + pset = &set; + sigemptyset(pset); + sigaddset(pset, SIGPROF); + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + + for (;;) { + if (timeout != -1) { + spec.tv_sec = timeout / 1000; + spec.tv_nsec = (timeout % 1000) * 1000000; + } + + /* Work around a kernel bug where nfds is not updated. */ + events[0].portev_source = 0; + + nfds = 1; + saved_errno = 0; + + if (pset != NULL) + pthread_sigmask(SIG_BLOCK, pset, NULL); + + err = port_getn(loop->backend_fd, + events, + ARRAY_SIZE(events), + &nfds, + timeout == -1 ? NULL : &spec); + + if (pset != NULL) + pthread_sigmask(SIG_UNBLOCK, pset, NULL); + + if (err) { + /* Work around another kernel bug: port_getn() may return events even + * on error. + */ + if (errno == EINTR || errno == ETIME) + saved_errno = errno; + else + abort(); + } + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (events[0].portev_source == 0) { + if (timeout == 0) + return; + + if (timeout == -1) + continue; + + goto update_timeout; + } + + if (nfds == 0) { + assert(timeout != -1); + return; + } + + have_signals = 0; + nevents = 0; + + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + for (i = 0; i < nfds; i++) { + pe = events + i; + fd = pe->portev_object; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (fd == -1) + continue; + + assert(fd >= 0); + assert((unsigned) fd < loop->nwatchers); + + w = loop->watchers[fd]; + + /* File descriptor that we've stopped watching, ignore. */ + if (w == NULL) + continue; + + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->portev_events); + + nevents++; + + if (w != loop->watchers[fd]) + continue; /* Disabled by callback. */ + + /* Events Ports operates in oneshot mode, rearm timer on next run. */ + if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) + QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (saved_errno == ETIME) { + assert(timeout != -1); + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + diff = loop->time - base; + if (diff >= (uint64_t) timeout) + return; + + timeout -= diff; + } +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + return gethrtime(); +} + + +/* + * We could use a static buffer for the path manipulations that we need outside + * of the function, but this function could be called by multiple consumers and + * we don't want to potentially create a race condition in the use of snprintf. + */ +int uv_exepath(char* buffer, size_t* size) { + ssize_t res; + char buf[128]; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid()); + + res = *size - 1; + if (res > 0) + res = readlink(buf, buffer, res); + + if (res == -1) + return -errno; + + buffer[res] = '\0'; + *size = res; + return 0; +} + + +uint64_t uv_get_free_memory(void) { + return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES); +} + + +uint64_t uv_get_total_memory(void) { + return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES); +} + + +void uv_loadavg(double avg[3]) { + (void) getloadavg(avg, 3); +} + + +#if defined(PORT_SOURCE_FILE) + +static int uv__fs_event_rearm(uv_fs_event_t *handle) { + if (handle->fd == -1) + return -EBADF; + + if (port_associate(handle->loop->fs_fd, + PORT_SOURCE_FILE, + (uintptr_t) &handle->fo, + FILE_ATTRIB | FILE_MODIFIED, + handle) == -1) { + return -errno; + } + handle->fd = PORT_LOADED; + + return 0; +} + + +static void uv__fs_event_read(uv_loop_t* loop, + uv__io_t* w, + unsigned int revents) { + uv_fs_event_t *handle = NULL; + timespec_t timeout; + port_event_t pe; + int events; + int r; + + (void) w; + (void) revents; + + do { + uint_t n = 1; + + /* + * Note that our use of port_getn() here (and not port_get()) is deliberate: + * there is a bug in event ports (Sun bug 6456558) whereby a zeroed timeout + * causes port_get() to return success instead of ETIME when there aren't + * actually any events (!); by using port_getn() in lieu of port_get(), + * we can at least workaround the bug by checking for zero returned events + * and treating it as we would ETIME. + */ + do { + memset(&timeout, 0, sizeof timeout); + r = port_getn(loop->fs_fd, &pe, 1, &n, &timeout); + } + while (r == -1 && errno == EINTR); + + if ((r == -1 && errno == ETIME) || n == 0) + break; + + handle = (uv_fs_event_t*) pe.portev_user; + assert((r == 0) && "unexpected port_get() error"); + + events = 0; + if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED)) + events |= UV_CHANGE; + if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED)) + events |= UV_RENAME; + assert(events != 0); + handle->fd = PORT_FIRED; + handle->cb(handle, NULL, events, 0); + + if (handle->fd != PORT_DELETED) { + r = uv__fs_event_rearm(handle); + if (r != 0) + handle->cb(handle, NULL, 0, r); + } + } + while (handle->fd != PORT_DELETED); +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + return 0; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* path, + unsigned int flags) { + int portfd; + int first_run; + int err; + + if (uv__is_active(handle)) + return -EINVAL; + + first_run = 0; + if (handle->loop->fs_fd == -1) { + portfd = port_create(); + if (portfd == -1) + return -errno; + handle->loop->fs_fd = portfd; + first_run = 1; + } + + uv__handle_start(handle); + handle->path = uv__strdup(path); + handle->fd = PORT_UNUSED; + handle->cb = cb; + + memset(&handle->fo, 0, sizeof handle->fo); + handle->fo.fo_name = handle->path; + err = uv__fs_event_rearm(handle); + if (err != 0) + return err; + + if (first_run) { + uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd); + uv__io_start(handle->loop, &handle->loop->fs_event_watcher, POLLIN); + } + + return 0; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + if (!uv__is_active(handle)) + return 0; + + if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) { + port_dissociate(handle->loop->fs_fd, + PORT_SOURCE_FILE, + (uintptr_t) &handle->fo); + } + + handle->fd = PORT_DELETED; + uv__free(handle->path); + handle->path = NULL; + handle->fo.fo_name = NULL; + uv__handle_stop(handle); + + return 0; +} + +void uv__fs_event_close(uv_fs_event_t* handle) { + uv_fs_event_stop(handle); +} + +#else /* !defined(PORT_SOURCE_FILE) */ + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + return -ENOSYS; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* filename, + unsigned int flags) { + return -ENOSYS; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + return -ENOSYS; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + UNREACHABLE(); +} + +#endif /* defined(PORT_SOURCE_FILE) */ + + +char** uv_setup_args(int argc, char** argv) { + return argv; +} + + +int uv_set_process_title(const char* title) { + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + if (buffer == NULL || size == 0) + return -EINVAL; + + buffer[0] = '\0'; + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + psinfo_t psinfo; + int err; + int fd; + + fd = open("/proc/self/psinfo", O_RDONLY); + if (fd == -1) + return -errno; + + /* FIXME(bnoordhuis) Handle EINTR. */ + err = -EINVAL; + if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) { + *rss = (size_t)psinfo.pr_rssize * 1024; + err = 0; + } + uv__close(fd); + + return err; +} + + +int uv_uptime(double* uptime) { + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *knp; + + long hz = sysconf(_SC_CLK_TCK); + + kc = kstat_open(); + if (kc == NULL) + return -EPERM; + + ksp = kstat_lookup(kc, (char*) "unix", 0, (char*) "system_misc"); + if (kstat_read(kc, ksp, NULL) == -1) { + *uptime = -1; + } else { + knp = (kstat_named_t*) kstat_data_lookup(ksp, (char*) "clk_intr"); + *uptime = knp->value.ul / hz; + } + kstat_close(kc); + + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + int lookup_instance; + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *knp; + uv_cpu_info_t* cpu_info; + + kc = kstat_open(); + if (kc == NULL) + return -EPERM; + + /* Get count of cpus */ + lookup_instance = 0; + while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) { + lookup_instance++; + } + + *cpu_infos = uv__malloc(lookup_instance * sizeof(**cpu_infos)); + if (!(*cpu_infos)) { + kstat_close(kc); + return -ENOMEM; + } + + *count = lookup_instance; + + cpu_info = *cpu_infos; + lookup_instance = 0; + while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) { + if (kstat_read(kc, ksp, NULL) == -1) { + cpu_info->speed = 0; + cpu_info->model = NULL; + } else { + knp = kstat_data_lookup(ksp, (char*) "clock_MHz"); + assert(knp->data_type == KSTAT_DATA_INT32 || + knp->data_type == KSTAT_DATA_INT64); + cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32 + : knp->value.i64; + + knp = kstat_data_lookup(ksp, (char*) "brand"); + assert(knp->data_type == KSTAT_DATA_STRING); + cpu_info->model = uv__strdup(KSTAT_NAMED_STR_PTR(knp)); + } + + lookup_instance++; + cpu_info++; + } + + cpu_info = *cpu_infos; + lookup_instance = 0; + for (;;) { + ksp = kstat_lookup(kc, (char*) "cpu", lookup_instance, (char*) "sys"); + + if (ksp == NULL) + break; + + if (kstat_read(kc, ksp, NULL) == -1) { + cpu_info->cpu_times.user = 0; + cpu_info->cpu_times.nice = 0; + cpu_info->cpu_times.sys = 0; + cpu_info->cpu_times.idle = 0; + cpu_info->cpu_times.irq = 0; + } else { + knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_user"); + assert(knp->data_type == KSTAT_DATA_UINT64); + cpu_info->cpu_times.user = knp->value.ui64; + + knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_kernel"); + assert(knp->data_type == KSTAT_DATA_UINT64); + cpu_info->cpu_times.sys = knp->value.ui64; + + knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_idle"); + assert(knp->data_type == KSTAT_DATA_UINT64); + cpu_info->cpu_times.idle = knp->value.ui64; + + knp = kstat_data_lookup(ksp, (char*) "intr"); + assert(knp->data_type == KSTAT_DATA_UINT64); + cpu_info->cpu_times.irq = knp->value.ui64; + cpu_info->cpu_times.nice = 0; + } + + lookup_instance++; + cpu_info++; + } + + kstat_close(kc); + + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + +/* + * Inspired By: + * https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris + * http://www.pauliesworld.org/project/getmac.c + */ +static int uv__set_phys_addr(uv_interface_address_t* address, + struct ifaddrs* ent) { + + struct sockaddr_dl* sa_addr; + int sockfd; + int i; + struct arpreq arpreq; + + /* This appears to only work as root */ + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + for (i = 0; i < sizeof(address->phys_addr); i++) { + if (address->phys_addr[i] != 0) + return 0; + } + memset(&arpreq, 0, sizeof(arpreq)); + if (address->address.address4.sin_family == AF_INET) { + struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa); + sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr; + } else if (address->address.address4.sin_family == AF_INET6) { + struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa); + memcpy(sin->sin6_addr.s6_addr, + address->address.address6.sin6_addr.s6_addr, + sizeof(address->address.address6.sin6_addr.s6_addr)); + } else { + return 0; + } + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + return -errno; + + if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) { + uv__close(sockfd); + return -errno; + } + memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr)); + uv__close(sockfd); + return 0; +} + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { +#ifdef SUNOS_NO_IFADDRS + return -ENOSYS; +#else + uv_interface_address_t* address; + struct ifaddrs* addrs; + struct ifaddrs* ent; + int i; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family == PF_PACKET)) { + continue; + } + + (*count)++; + } + + *addresses = uv__malloc(*count * sizeof(**addresses)); + if (!(*addresses)) { + freeifaddrs(addrs); + return -ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + address->name = uv__strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) || + (ent->ifa_flags & IFF_LOOPBACK)); + + uv__set_phys_addr(address, ent); + address++; + } + + freeifaddrs(addrs); + + return 0; +#endif /* SUNOS_NO_IFADDRS */ +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(addresses[i].name); + } + + uv__free(addresses); +} diff --git a/src/unix/tcp.c b/src/unix/tcp.c new file mode 100644 index 0000000..c423dcb --- /dev/null +++ b/src/unix/tcp.c @@ -0,0 +1,395 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include + + +static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) { + int sockfd; + int err; + + if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) { + handle->flags |= flags; + return 0; + } + + err = uv__socket(domain, SOCK_STREAM, 0); + if (err < 0) + return err; + sockfd = err; + + err = uv__stream_open((uv_stream_t*) handle, sockfd, flags); + if (err) { + uv__close(sockfd); + return err; + } + + return 0; +} + + +int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) { + int domain; + + /* Use the lower 8 bits for the domain */ + domain = flags & 0xFF; + if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) + return -EINVAL; + + if (flags & ~0xFF) + return -EINVAL; + + uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP); + + /* If anything fails beyond this point we need to remove the handle from + * the handle queue, since it was added by uv__handle_init in uv_stream_init. + */ + + if (domain != AF_UNSPEC) { + int err = maybe_new_socket(tcp, domain, 0); + if (err) { + QUEUE_REMOVE(&tcp->handle_queue); + return err; + } + } + + return 0; +} + + +int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) { + return uv_tcp_init_ex(loop, tcp, AF_UNSPEC); +} + + +int uv__tcp_bind(uv_tcp_t* tcp, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + int err; + int on; + + /* Cannot set IPv6-only mode on non-IPv6 socket. */ + if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6) + return -EINVAL; + + err = maybe_new_socket(tcp, + addr->sa_family, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); + if (err) + return err; + + on = 1; + if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) + return -errno; + +#ifdef IPV6_V6ONLY + if (addr->sa_family == AF_INET6) { + on = (flags & UV_TCP_IPV6ONLY) != 0; + if (setsockopt(tcp->io_watcher.fd, + IPPROTO_IPV6, + IPV6_V6ONLY, + &on, + sizeof on) == -1) { +#if defined(__MVS__) + if (errno == EOPNOTSUPP) + return -EINVAL; +#endif + return -errno; + } + } +#endif + + errno = 0; + if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) { + if (errno == EAFNOSUPPORT) + /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a + * socket created with AF_INET to an AF_INET6 address or vice versa. */ + return -EINVAL; + return -errno; + } + tcp->delayed_error = -errno; + + tcp->flags |= UV_HANDLE_BOUND; + if (addr->sa_family == AF_INET6) + tcp->flags |= UV_HANDLE_IPV6; + + return 0; +} + + +int uv__tcp_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + uv_connect_cb cb) { + int err; + int r; + + assert(handle->type == UV_TCP); + + if (handle->connect_req != NULL) + return -EALREADY; /* FIXME(bnoordhuis) -EINVAL or maybe -EBUSY. */ + + err = maybe_new_socket(handle, + addr->sa_family, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); + if (err) + return err; + + handle->delayed_error = 0; + + do { + errno = 0; + r = connect(uv__stream_fd(handle), addr, addrlen); + } while (r == -1 && errno == EINTR); + + /* We not only check the return value, but also check the errno != 0. + * Because in rare cases connect() will return -1 but the errno + * is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227) + * and actually the tcp three-way handshake is completed. + */ + if (r == -1 && errno != 0) { + if (errno == EINPROGRESS) + ; /* not an error */ + else if (errno == ECONNREFUSED) + /* If we get a ECONNREFUSED wait until the next tick to report the + * error. Solaris wants to report immediately--other unixes want to + * wait. + */ + handle->delayed_error = -errno; + else + return -errno; + } + + uv__req_init(handle->loop, req, UV_CONNECT); + req->cb = cb; + req->handle = (uv_stream_t*) handle; + QUEUE_INIT(&req->queue); + handle->connect_req = req; + + uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); + + if (handle->delayed_error) + uv__io_feed(handle->loop, &handle->io_watcher); + + return 0; +} + + +int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { + int err; + + err = uv__nonblock(sock, 1); + if (err) + return err; + + return uv__stream_open((uv_stream_t*)handle, + sock, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); +} + + +int uv_tcp_getsockname(const uv_tcp_t* handle, + struct sockaddr* name, + int* namelen) { + socklen_t socklen; + + if (handle->delayed_error) + return handle->delayed_error; + + if (uv__stream_fd(handle) < 0) + return -EINVAL; /* FIXME(bnoordhuis) -EBADF */ + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (getsockname(uv__stream_fd(handle), name, &socklen)) + return -errno; + + *namelen = (int) socklen; + return 0; +} + + +int uv_tcp_getpeername(const uv_tcp_t* handle, + struct sockaddr* name, + int* namelen) { + socklen_t socklen; + + if (handle->delayed_error) + return handle->delayed_error; + + if (uv__stream_fd(handle) < 0) + return -EINVAL; /* FIXME(bnoordhuis) -EBADF */ + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (getpeername(uv__stream_fd(handle), name, &socklen)) + return -errno; + + *namelen = (int) socklen; + return 0; +} + + +int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { + static int single_accept = -1; + int err; + + if (tcp->delayed_error) + return tcp->delayed_error; + + if (single_accept == -1) { + const char* val = getenv("UV_TCP_SINGLE_ACCEPT"); + single_accept = (val != NULL && atoi(val) != 0); /* Off by default. */ + } + + if (single_accept) + tcp->flags |= UV_TCP_SINGLE_ACCEPT; + + err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE); + if (err) + return err; + +#ifdef __MVS__ + /* on zOS the listen call does not bind automatically + if the socket is unbound. Hence the manual binding to + an arbitrary port is required to be done manually + */ + + if (!(tcp->flags & UV_HANDLE_BOUND)) { + struct sockaddr_storage saddr; + socklen_t slen = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + + if (getsockname(tcp->io_watcher.fd, (struct sockaddr*) &saddr, &slen)) + return -errno; + + if (bind(tcp->io_watcher.fd, (struct sockaddr*) &saddr, slen)) + return -errno; + + tcp->flags |= UV_HANDLE_BOUND; + } +#endif + + if (listen(tcp->io_watcher.fd, backlog)) + return -errno; + + tcp->connection_cb = cb; + tcp->flags |= UV_HANDLE_BOUND; + + /* Start listening for connections. */ + tcp->io_watcher.cb = uv__server_io; + uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN); + + return 0; +} + + +int uv__tcp_nodelay(int fd, int on) { + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on))) + return -errno; + return 0; +} + + +int uv__tcp_keepalive(int fd, int on, unsigned int delay) { + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on))) + return -errno; + +#ifdef TCP_KEEPIDLE + if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) + return -errno; +#endif + + /* Solaris/SmartOS, if you don't support keep-alive, + * then don't advertise it in your system headers... + */ + /* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */ +#if defined(TCP_KEEPALIVE) && !defined(__sun) + if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay))) + return -errno; +#endif + + return 0; +} + + +int uv_tcp_nodelay(uv_tcp_t* handle, int on) { + int err; + + if (uv__stream_fd(handle) != -1) { + err = uv__tcp_nodelay(uv__stream_fd(handle), on); + if (err) + return err; + } + + if (on) + handle->flags |= UV_TCP_NODELAY; + else + handle->flags &= ~UV_TCP_NODELAY; + + return 0; +} + + +int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { + int err; + + if (uv__stream_fd(handle) != -1) { + err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay); + if (err) + return err; + } + + if (on) + handle->flags |= UV_TCP_KEEPALIVE; + else + handle->flags &= ~UV_TCP_KEEPALIVE; + + /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge + * uv_tcp_t with an int that's almost never used... + */ + + return 0; +} + + +int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { + if (enable) + handle->flags &= ~UV_TCP_SINGLE_ACCEPT; + else + handle->flags |= UV_TCP_SINGLE_ACCEPT; + return 0; +} + + +void uv__tcp_close(uv_tcp_t* handle) { + uv__stream_close((uv_stream_t*)handle); +} diff --git a/src/unix/thread.c b/src/unix/thread.c new file mode 100644 index 0000000..52989f7 --- /dev/null +++ b/src/unix/thread.c @@ -0,0 +1,605 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + +#include +#include /* getrlimit() */ +#include /* getpagesize() */ + +#include + +#ifdef __MVS__ +#include +#include +#endif + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + +struct thread_ctx { + void (*entry)(void* arg); + void* arg; +}; + + +static void* uv__thread_start(void *arg) +{ + struct thread_ctx *ctx_p; + struct thread_ctx ctx; + + ctx_p = arg; + ctx = *ctx_p; + uv__free(ctx_p); + ctx.entry(ctx.arg); + + return 0; +} + + +int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { + struct thread_ctx* ctx; + int err; + pthread_attr_t* attr; +#if defined(__APPLE__) + pthread_attr_t attr_storage; + struct rlimit lim; +#endif + + ctx = uv__malloc(sizeof(*ctx)); + if (ctx == NULL) + return UV_ENOMEM; + + ctx->entry = entry; + ctx->arg = arg; + + /* On OSX threads other than the main thread are created with a reduced stack + * size by default, adjust it to RLIMIT_STACK. + */ +#if defined(__APPLE__) + if (getrlimit(RLIMIT_STACK, &lim)) + abort(); + + attr = &attr_storage; + if (pthread_attr_init(attr)) + abort(); + + if (lim.rlim_cur != RLIM_INFINITY) { + /* pthread_attr_setstacksize() expects page-aligned values. */ + lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize(); + + if (lim.rlim_cur >= PTHREAD_STACK_MIN) + if (pthread_attr_setstacksize(attr, lim.rlim_cur)) + abort(); + } +#else + attr = NULL; +#endif + + err = pthread_create(tid, attr, uv__thread_start, ctx); + + if (attr != NULL) + pthread_attr_destroy(attr); + + if (err) + uv__free(ctx); + + return -err; +} + + +uv_thread_t uv_thread_self(void) { + return pthread_self(); +} + +int uv_thread_join(uv_thread_t *tid) { + return -pthread_join(*tid, NULL); +} + + +int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { + return pthread_equal(*t1, *t2); +} + + +int uv_mutex_init(uv_mutex_t* mutex) { +#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK) + return -pthread_mutex_init(mutex, NULL); +#else + pthread_mutexattr_t attr; + int err; + + if (pthread_mutexattr_init(&attr)) + abort(); + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)) + abort(); + + err = pthread_mutex_init(mutex, &attr); + + if (pthread_mutexattr_destroy(&attr)) + abort(); + + return -err; +#endif +} + + +void uv_mutex_destroy(uv_mutex_t* mutex) { + if (pthread_mutex_destroy(mutex)) + abort(); +} + + +void uv_mutex_lock(uv_mutex_t* mutex) { + if (pthread_mutex_lock(mutex)) + abort(); +} + + +int uv_mutex_trylock(uv_mutex_t* mutex) { + int err; + + err = pthread_mutex_trylock(mutex); + if (err) { + if (err != EBUSY && err != EAGAIN) + abort(); + return -EBUSY; + } + + return 0; +} + + +void uv_mutex_unlock(uv_mutex_t* mutex) { + if (pthread_mutex_unlock(mutex)) + abort(); +} + + +int uv_rwlock_init(uv_rwlock_t* rwlock) { + return -pthread_rwlock_init(rwlock, NULL); +} + + +void uv_rwlock_destroy(uv_rwlock_t* rwlock) { + if (pthread_rwlock_destroy(rwlock)) + abort(); +} + + +void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { + if (pthread_rwlock_rdlock(rwlock)) + abort(); +} + + +int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { + int err; + + err = pthread_rwlock_tryrdlock(rwlock); + if (err) { + if (err != EBUSY && err != EAGAIN) + abort(); + return -EBUSY; + } + + return 0; +} + + +void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { + if (pthread_rwlock_unlock(rwlock)) + abort(); +} + + +void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { + if (pthread_rwlock_wrlock(rwlock)) + abort(); +} + + +int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { + int err; + + err = pthread_rwlock_trywrlock(rwlock); + if (err) { + if (err != EBUSY && err != EAGAIN) + abort(); + return -EBUSY; + } + + return 0; +} + + +void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { + if (pthread_rwlock_unlock(rwlock)) + abort(); +} + + +void uv_once(uv_once_t* guard, void (*callback)(void)) { + if (pthread_once(guard, callback)) + abort(); +} + +#if defined(__APPLE__) && defined(__MACH__) + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + kern_return_t err; + + err = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value); + if (err == KERN_SUCCESS) + return 0; + if (err == KERN_INVALID_ARGUMENT) + return -EINVAL; + if (err == KERN_RESOURCE_SHORTAGE) + return -ENOMEM; + + abort(); + return -EINVAL; /* Satisfy the compiler. */ +} + + +void uv_sem_destroy(uv_sem_t* sem) { + if (semaphore_destroy(mach_task_self(), *sem)) + abort(); +} + + +void uv_sem_post(uv_sem_t* sem) { + if (semaphore_signal(*sem)) + abort(); +} + + +void uv_sem_wait(uv_sem_t* sem) { + int r; + + do + r = semaphore_wait(*sem); + while (r == KERN_ABORTED); + + if (r != KERN_SUCCESS) + abort(); +} + + +int uv_sem_trywait(uv_sem_t* sem) { + mach_timespec_t interval; + kern_return_t err; + + interval.tv_sec = 0; + interval.tv_nsec = 0; + + err = semaphore_timedwait(*sem, interval); + if (err == KERN_SUCCESS) + return 0; + if (err == KERN_OPERATION_TIMED_OUT) + return -EAGAIN; + + abort(); + return -EINVAL; /* Satisfy the compiler. */ +} + +#elif defined(__MVS__) + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + uv_sem_t semid; + struct sembuf buf; + int err; + + buf.sem_num = 0; + buf.sem_op = value; + buf.sem_flg = 0; + + semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR); + if (semid == -1) + return -errno; + + if (-1 == semop(semid, &buf, 1)) { + err = errno; + if (-1 == semctl(*sem, 0, IPC_RMID)) + abort(); + return -err; + } + + *sem = semid; + return 0; +} + +void uv_sem_destroy(uv_sem_t* sem) { + if (-1 == semctl(*sem, 0, IPC_RMID)) + abort(); +} + +void uv_sem_post(uv_sem_t* sem) { + struct sembuf buf; + + buf.sem_num = 0; + buf.sem_op = 1; + buf.sem_flg = 0; + + if (-1 == semop(*sem, &buf, 1)) + abort(); +} + +void uv_sem_wait(uv_sem_t* sem) { + struct sembuf buf; + int op_status; + + buf.sem_num = 0; + buf.sem_op = -1; + buf.sem_flg = 0; + + do + op_status = semop(*sem, &buf, 1); + while (op_status == -1 && errno == EINTR); + + if (op_status) + abort(); +} + +int uv_sem_trywait(uv_sem_t* sem) { + struct sembuf buf; + int op_status; + + buf.sem_num = 0; + buf.sem_op = -1; + buf.sem_flg = IPC_NOWAIT; + + do + op_status = semop(*sem, &buf, 1); + while (op_status == -1 && errno == EINTR); + + if (op_status) { + if (errno == EAGAIN) + return -EAGAIN; + abort(); + } + + return 0; +} + +#else /* !(defined(__APPLE__) && defined(__MACH__)) */ + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + if (sem_init(sem, 0, value)) + return -errno; + return 0; +} + + +void uv_sem_destroy(uv_sem_t* sem) { + if (sem_destroy(sem)) + abort(); +} + + +void uv_sem_post(uv_sem_t* sem) { + if (sem_post(sem)) + abort(); +} + + +void uv_sem_wait(uv_sem_t* sem) { + int r; + + do + r = sem_wait(sem); + while (r == -1 && errno == EINTR); + + if (r) + abort(); +} + + +int uv_sem_trywait(uv_sem_t* sem) { + int r; + + do + r = sem_trywait(sem); + while (r == -1 && errno == EINTR); + + if (r) { + if (errno == EAGAIN) + return -EAGAIN; + abort(); + } + + return 0; +} + +#endif /* defined(__APPLE__) && defined(__MACH__) */ + + +#if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__) + +int uv_cond_init(uv_cond_t* cond) { + return -pthread_cond_init(cond, NULL); +} + +#else /* !(defined(__APPLE__) && defined(__MACH__)) */ + +int uv_cond_init(uv_cond_t* cond) { + pthread_condattr_t attr; + int err; + + err = pthread_condattr_init(&attr); + if (err) + return -err; + +#if !(defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)) + err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + if (err) + goto error2; +#endif + + err = pthread_cond_init(cond, &attr); + if (err) + goto error2; + + err = pthread_condattr_destroy(&attr); + if (err) + goto error; + + return 0; + +error: + pthread_cond_destroy(cond); +error2: + pthread_condattr_destroy(&attr); + return -err; +} + +#endif /* defined(__APPLE__) && defined(__MACH__) */ + +void uv_cond_destroy(uv_cond_t* cond) { +#if defined(__APPLE__) && defined(__MACH__) + /* It has been reported that destroying condition variables that have been + * signalled but not waited on can sometimes result in application crashes. + * See https://codereview.chromium.org/1323293005. + */ + pthread_mutex_t mutex; + struct timespec ts; + int err; + + if (pthread_mutex_init(&mutex, NULL)) + abort(); + + if (pthread_mutex_lock(&mutex)) + abort(); + + ts.tv_sec = 0; + ts.tv_nsec = 1; + + err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts); + if (err != 0 && err != ETIMEDOUT) + abort(); + + if (pthread_mutex_unlock(&mutex)) + abort(); + + if (pthread_mutex_destroy(&mutex)) + abort(); +#endif /* defined(__APPLE__) && defined(__MACH__) */ + + if (pthread_cond_destroy(cond)) + abort(); +} + +void uv_cond_signal(uv_cond_t* cond) { + if (pthread_cond_signal(cond)) + abort(); +} + +void uv_cond_broadcast(uv_cond_t* cond) { + if (pthread_cond_broadcast(cond)) + abort(); +} + +void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) { + if (pthread_cond_wait(cond, mutex)) + abort(); +} + + +int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { + int r; + struct timespec ts; + +#if defined(__APPLE__) && defined(__MACH__) + ts.tv_sec = timeout / NANOSEC; + ts.tv_nsec = timeout % NANOSEC; + r = pthread_cond_timedwait_relative_np(cond, mutex, &ts); +#else + timeout += uv__hrtime(UV_CLOCK_PRECISE); + ts.tv_sec = timeout / NANOSEC; + ts.tv_nsec = timeout % NANOSEC; +#if defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) + /* + * The bionic pthread implementation doesn't support CLOCK_MONOTONIC, + * but has this alternative function instead. + */ + r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts); +#else + r = pthread_cond_timedwait(cond, mutex, &ts); +#endif /* __ANDROID__ */ +#endif + + + if (r == 0) + return 0; + + if (r == ETIMEDOUT) + return -ETIMEDOUT; + + abort(); + return -EINVAL; /* Satisfy the compiler. */ +} + + +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + return -pthread_barrier_init(barrier, NULL, count); +} + + +void uv_barrier_destroy(uv_barrier_t* barrier) { + if (pthread_barrier_destroy(barrier)) + abort(); +} + + +int uv_barrier_wait(uv_barrier_t* barrier) { + int r = pthread_barrier_wait(barrier); + if (r && r != PTHREAD_BARRIER_SERIAL_THREAD) + abort(); + return r == PTHREAD_BARRIER_SERIAL_THREAD; +} + + +int uv_key_create(uv_key_t* key) { + return -pthread_key_create(key, NULL); +} + + +void uv_key_delete(uv_key_t* key) { + if (pthread_key_delete(*key)) + abort(); +} + + +void* uv_key_get(uv_key_t* key) { + return pthread_getspecific(*key); +} + + +void uv_key_set(uv_key_t* key, void* value) { + if (pthread_setspecific(*key, value)) + abort(); +} diff --git a/src/unix/timer.c b/src/unix/timer.c new file mode 100644 index 0000000..ca3ec3d --- /dev/null +++ b/src/unix/timer.c @@ -0,0 +1,172 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" +#include "heap-inl.h" + +#include +#include + + +static int timer_less_than(const struct heap_node* ha, + const struct heap_node* hb) { + const uv_timer_t* a; + const uv_timer_t* b; + + a = container_of(ha, const uv_timer_t, heap_node); + b = container_of(hb, const uv_timer_t, heap_node); + + if (a->timeout < b->timeout) + return 1; + if (b->timeout < a->timeout) + return 0; + + /* Compare start_id when both have the same timeout. start_id is + * allocated with loop->timer_counter in uv_timer_start(). + */ + if (a->start_id < b->start_id) + return 1; + if (b->start_id < a->start_id) + return 0; + + return 0; +} + + +int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER); + handle->timer_cb = NULL; + handle->repeat = 0; + return 0; +} + + +int uv_timer_start(uv_timer_t* handle, + uv_timer_cb cb, + uint64_t timeout, + uint64_t repeat) { + uint64_t clamped_timeout; + + if (cb == NULL) + return -EINVAL; + + if (uv__is_active(handle)) + uv_timer_stop(handle); + + clamped_timeout = handle->loop->time + timeout; + if (clamped_timeout < timeout) + clamped_timeout = (uint64_t) -1; + + handle->timer_cb = cb; + handle->timeout = clamped_timeout; + handle->repeat = repeat; + /* start_id is the second index to be compared in uv__timer_cmp() */ + handle->start_id = handle->loop->timer_counter++; + + heap_insert((struct heap*) &handle->loop->timer_heap, + (struct heap_node*) &handle->heap_node, + timer_less_than); + uv__handle_start(handle); + + return 0; +} + + +int uv_timer_stop(uv_timer_t* handle) { + if (!uv__is_active(handle)) + return 0; + + heap_remove((struct heap*) &handle->loop->timer_heap, + (struct heap_node*) &handle->heap_node, + timer_less_than); + uv__handle_stop(handle); + + return 0; +} + + +int uv_timer_again(uv_timer_t* handle) { + if (handle->timer_cb == NULL) + return -EINVAL; + + if (handle->repeat) { + uv_timer_stop(handle); + uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat); + } + + return 0; +} + + +void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) { + handle->repeat = repeat; +} + + +uint64_t uv_timer_get_repeat(const uv_timer_t* handle) { + return handle->repeat; +} + + +int uv__next_timeout(const uv_loop_t* loop) { + const struct heap_node* heap_node; + const uv_timer_t* handle; + uint64_t diff; + + heap_node = heap_min((const struct heap*) &loop->timer_heap); + if (heap_node == NULL) + return -1; /* block indefinitely */ + + handle = container_of(heap_node, const uv_timer_t, heap_node); + if (handle->timeout <= loop->time) + return 0; + + diff = handle->timeout - loop->time; + if (diff > INT_MAX) + diff = INT_MAX; + + return diff; +} + + +void uv__run_timers(uv_loop_t* loop) { + struct heap_node* heap_node; + uv_timer_t* handle; + + for (;;) { + heap_node = heap_min((struct heap*) &loop->timer_heap); + if (heap_node == NULL) + break; + + handle = container_of(heap_node, uv_timer_t, heap_node); + if (handle->timeout > loop->time) + break; + + uv_timer_stop(handle); + uv_timer_again(handle); + handle->timer_cb(handle); + } +} + + +void uv__timer_close(uv_timer_t* handle) { + uv_timer_stop(handle); +} diff --git a/src/unix/tty.c b/src/unix/tty.c new file mode 100644 index 0000000..b2d37f4 --- /dev/null +++ b/src/unix/tty.c @@ -0,0 +1,336 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" +#include "spinlock.h" + +#include +#include +#include +#include +#include +#include + +#if defined(__MVS__) && !defined(IMAXBEL) +#define IMAXBEL 0 +#endif + +static int orig_termios_fd = -1; +static struct termios orig_termios; +static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; + +static int uv__tty_is_slave(const int fd) { + int result; +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + int dummy; + + result = ioctl(fd, TIOCGPTN, &dummy) != 0; +#elif defined(__APPLE__) + char dummy[256]; + + result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0; +#else + /* Fallback to ptsname + */ + result = ptsname(fd) == NULL; +#endif + return result; +} + +int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { + uv_handle_type type; + int flags; + int newfd; + int r; + int saved_flags; + char path[256]; + + /* File descriptors that refer to files cannot be monitored with epoll. + * That restriction also applies to character devices like /dev/random + * (but obviously not /dev/tty.) + */ + type = uv_guess_handle(fd); + if (type == UV_FILE || type == UV_UNKNOWN_HANDLE) + return -EINVAL; + + flags = 0; + newfd = -1; + + /* Reopen the file descriptor when it refers to a tty. This lets us put the + * tty in non-blocking mode without affecting other processes that share it + * with us. + * + * Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also + * affects fd 1 of `cat` because both file descriptors refer to the same + * struct file in the kernel. When we reopen our fd 0, it points to a + * different struct file, hence changing its properties doesn't affect + * other processes. + */ + if (type == UV_TTY) { + /* Reopening a pty in master mode won't work either because the reopened + * pty will be in slave mode (*BSD) or reopening will allocate a new + * master/slave pair (Linux). Therefore check if the fd points to a + * slave device. + */ + if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0) + r = uv__open_cloexec(path, O_RDWR); + else + r = -1; + + if (r < 0) { + /* fallback to using blocking writes */ + if (!readable) + flags |= UV_STREAM_BLOCKING; + goto skip; + } + + newfd = r; + + r = uv__dup2_cloexec(newfd, fd); + if (r < 0 && r != -EINVAL) { + /* EINVAL means newfd == fd which could conceivably happen if another + * thread called close(fd) between our calls to isatty() and open(). + * That's a rather unlikely event but let's handle it anyway. + */ + uv__close(newfd); + return r; + } + + fd = newfd; + } + +#if defined(__APPLE__) + /* Save the fd flags in case we need to restore them due to an error. */ + do + saved_flags = fcntl(fd, F_GETFL); + while (saved_flags == -1 && errno == EINTR); + + if (saved_flags == -1) { + if (newfd != -1) + uv__close(newfd); + return -errno; + } +#endif + + /* Pacify the compiler. */ + (void) &saved_flags; + +skip: + uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY); + + /* If anything fails beyond this point we need to remove the handle from + * the handle queue, since it was added by uv__handle_init in uv_stream_init. + */ + + if (!(flags & UV_STREAM_BLOCKING)) + uv__nonblock(fd, 1); + +#if defined(__APPLE__) + r = uv__stream_try_select((uv_stream_t*) tty, &fd); + if (r) { + int rc = r; + if (newfd != -1) + uv__close(newfd); + QUEUE_REMOVE(&tty->handle_queue); + do + r = fcntl(fd, F_SETFL, saved_flags); + while (r == -1 && errno == EINTR); + return rc; + } +#endif + + if (readable) + flags |= UV_STREAM_READABLE; + else + flags |= UV_STREAM_WRITABLE; + + uv__stream_open((uv_stream_t*) tty, fd, flags); + tty->mode = UV_TTY_MODE_NORMAL; + + return 0; +} + +static void uv__tty_make_raw(struct termios* tio) { + assert(tio != NULL); + +#if defined __sun || defined __MVS__ + /* + * This implementation of cfmakeraw for Solaris and derivatives is taken from + * http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html. + */ + tio->c_iflag &= ~(IMAXBEL | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | + IGNCR | ICRNL | IXON); + tio->c_oflag &= ~OPOST; + tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + tio->c_cflag &= ~(CSIZE | PARENB); + tio->c_cflag |= CS8; +#else + cfmakeraw(tio); +#endif /* #ifdef __sun */ +} + +int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { + struct termios tmp; + int fd; + + if (tty->mode == (int) mode) + return 0; + + fd = uv__stream_fd(tty); + if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) { + if (tcgetattr(fd, &tty->orig_termios)) + return -errno; + + /* This is used for uv_tty_reset_mode() */ + uv_spinlock_lock(&termios_spinlock); + if (orig_termios_fd == -1) { + orig_termios = tty->orig_termios; + orig_termios_fd = fd; + } + uv_spinlock_unlock(&termios_spinlock); + } + + tmp = tty->orig_termios; + switch (mode) { + case UV_TTY_MODE_NORMAL: + break; + case UV_TTY_MODE_RAW: + tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + tmp.c_oflag |= (ONLCR); + tmp.c_cflag |= (CS8); + tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + tmp.c_cc[VMIN] = 1; + tmp.c_cc[VTIME] = 0; + break; + case UV_TTY_MODE_IO: + uv__tty_make_raw(&tmp); + break; + } + + /* Apply changes after draining */ + if (tcsetattr(fd, TCSADRAIN, &tmp)) + return -errno; + + tty->mode = mode; + return 0; +} + + +int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { + struct winsize ws; + int err; + + do + err = ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws); + while (err == -1 && errno == EINTR); + + if (err == -1) + return -errno; + + *width = ws.ws_col; + *height = ws.ws_row; + + return 0; +} + + +uv_handle_type uv_guess_handle(uv_file file) { + struct sockaddr sa; + struct stat s; + socklen_t len; + int type; + + if (file < 0) + return UV_UNKNOWN_HANDLE; + + if (isatty(file)) + return UV_TTY; + + if (fstat(file, &s)) + return UV_UNKNOWN_HANDLE; + + if (S_ISREG(s.st_mode)) + return UV_FILE; + + if (S_ISCHR(s.st_mode)) + return UV_FILE; /* XXX UV_NAMED_PIPE? */ + + if (S_ISFIFO(s.st_mode)) + return UV_NAMED_PIPE; + + if (!S_ISSOCK(s.st_mode)) + return UV_UNKNOWN_HANDLE; + + len = sizeof(type); + if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len)) + return UV_UNKNOWN_HANDLE; + + len = sizeof(sa); + if (getsockname(file, &sa, &len)) + return UV_UNKNOWN_HANDLE; + + if (type == SOCK_DGRAM) + if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) + return UV_UDP; + + if (type == SOCK_STREAM) { +#if defined(_AIX) || defined(__DragonFly__) + /* on AIX/DragonFly the getsockname call returns an empty sa structure + * for sockets of type AF_UNIX. For all other types it will + * return a properly filled in structure. + */ + if (len == 0) + return UV_NAMED_PIPE; +#endif /* defined(_AIX) || defined(__DragonFly__) */ + + if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) + return UV_TCP; + if (sa.sa_family == AF_UNIX) + return UV_NAMED_PIPE; + } + + return UV_UNKNOWN_HANDLE; +} + + +/* This function is async signal-safe, meaning that it's safe to call from + * inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s + * critical section when the signal was raised. + */ +int uv_tty_reset_mode(void) { + int saved_errno; + int err; + + saved_errno = errno; + if (!uv_spinlock_trylock(&termios_spinlock)) + return -EBUSY; /* In uv_tty_set_mode(). */ + + err = 0; + if (orig_termios_fd != -1) + if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios)) + err = -errno; + + uv_spinlock_unlock(&termios_spinlock); + errno = saved_errno; + + return err; +} diff --git a/src/unix/udp.c b/src/unix/udp.c new file mode 100644 index 0000000..1cd4925 --- /dev/null +++ b/src/unix/udp.c @@ -0,0 +1,895 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#if defined(__MVS__) +#include +#endif + +#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP) +# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#endif + +#if defined(IPV6_LEAVE_GROUP) && !defined(IPV6_DROP_MEMBERSHIP) +# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#endif + + +static void uv__udp_run_completed(uv_udp_t* handle); +static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents); +static void uv__udp_recvmsg(uv_udp_t* handle); +static void uv__udp_sendmsg(uv_udp_t* handle); +static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, + int domain, + unsigned int flags); + + +void uv__udp_close(uv_udp_t* handle) { + uv__io_close(handle->loop, &handle->io_watcher); + uv__handle_stop(handle); + + if (handle->io_watcher.fd != -1) { + uv__close(handle->io_watcher.fd); + handle->io_watcher.fd = -1; + } +} + + +void uv__udp_finish_close(uv_udp_t* handle) { + uv_udp_send_t* req; + QUEUE* q; + + assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT)); + assert(handle->io_watcher.fd == -1); + + while (!QUEUE_EMPTY(&handle->write_queue)) { + q = QUEUE_HEAD(&handle->write_queue); + QUEUE_REMOVE(q); + + req = QUEUE_DATA(q, uv_udp_send_t, queue); + req->status = -ECANCELED; + QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); + } + + uv__udp_run_completed(handle); + + assert(handle->send_queue_size == 0); + assert(handle->send_queue_count == 0); + + /* Now tear down the handle. */ + handle->recv_cb = NULL; + handle->alloc_cb = NULL; + /* but _do not_ touch close_cb */ +} + + +static void uv__udp_run_completed(uv_udp_t* handle) { + uv_udp_send_t* req; + QUEUE* q; + + assert(!(handle->flags & UV_UDP_PROCESSING)); + handle->flags |= UV_UDP_PROCESSING; + + while (!QUEUE_EMPTY(&handle->write_completed_queue)) { + q = QUEUE_HEAD(&handle->write_completed_queue); + QUEUE_REMOVE(q); + + req = QUEUE_DATA(q, uv_udp_send_t, queue); + uv__req_unregister(handle->loop, req); + + handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs); + handle->send_queue_count--; + + if (req->bufs != req->bufsml) + uv__free(req->bufs); + req->bufs = NULL; + + if (req->send_cb == NULL) + continue; + + /* req->status >= 0 == bytes written + * req->status < 0 == errno + */ + if (req->status >= 0) + req->send_cb(req, 0); + else + req->send_cb(req, req->status); + } + + if (QUEUE_EMPTY(&handle->write_queue)) { + /* Pending queue and completion queue empty, stop watcher. */ + uv__io_stop(handle->loop, &handle->io_watcher, POLLOUT); + if (!uv__io_active(&handle->io_watcher, POLLIN)) + uv__handle_stop(handle); + } + + handle->flags &= ~UV_UDP_PROCESSING; +} + + +static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { + uv_udp_t* handle; + + handle = container_of(w, uv_udp_t, io_watcher); + assert(handle->type == UV_UDP); + + if (revents & POLLIN) + uv__udp_recvmsg(handle); + + if (revents & POLLOUT) { + uv__udp_sendmsg(handle); + uv__udp_run_completed(handle); + } +} + + +static void uv__udp_recvmsg(uv_udp_t* handle) { + struct sockaddr_storage peer; + struct msghdr h; + ssize_t nread; + uv_buf_t buf; + int flags; + int count; + + assert(handle->recv_cb != NULL); + assert(handle->alloc_cb != NULL); + + /* Prevent loop starvation when the data comes in as fast as (or faster than) + * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O. + */ + count = 32; + + memset(&h, 0, sizeof(h)); + h.msg_name = &peer; + + do { + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf); + if (buf.base == NULL || buf.len == 0) { + handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); + return; + } + assert(buf.base != NULL); + + h.msg_namelen = sizeof(peer); + h.msg_iov = (void*) &buf; + h.msg_iovlen = 1; + + do { + nread = recvmsg(handle->io_watcher.fd, &h, 0); + } + while (nread == -1 && errno == EINTR); + + if (nread == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + handle->recv_cb(handle, 0, &buf, NULL, 0); + else + handle->recv_cb(handle, -errno, &buf, NULL, 0); + } + else { + const struct sockaddr *addr; + if (h.msg_namelen == 0) + addr = NULL; + else + addr = (const struct sockaddr*) &peer; + + flags = 0; + if (h.msg_flags & MSG_TRUNC) + flags |= UV_UDP_PARTIAL; + + handle->recv_cb(handle, nread, &buf, addr, flags); + } + } + /* recv_cb callback may decide to pause or close the handle */ + while (nread != -1 + && count-- > 0 + && handle->io_watcher.fd != -1 + && handle->recv_cb != NULL); +} + + +static void uv__udp_sendmsg(uv_udp_t* handle) { + uv_udp_send_t* req; + QUEUE* q; + struct msghdr h; + ssize_t size; + + while (!QUEUE_EMPTY(&handle->write_queue)) { + q = QUEUE_HEAD(&handle->write_queue); + assert(q != NULL); + + req = QUEUE_DATA(q, uv_udp_send_t, queue); + assert(req != NULL); + + memset(&h, 0, sizeof h); + h.msg_name = &req->addr; + h.msg_namelen = (req->addr.ss_family == AF_INET6 ? + sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); + h.msg_iov = (struct iovec*) req->bufs; + h.msg_iovlen = req->nbufs; + + do { + size = sendmsg(handle->io_watcher.fd, &h, 0); + } while (size == -1 && errno == EINTR); + + if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) + break; + + req->status = (size == -1 ? -errno : size); + + /* Sending a datagram is an atomic operation: either all data + * is written or nothing is (and EMSGSIZE is raised). That is + * why we don't handle partial writes. Just pop the request + * off the write queue and onto the completed queue, done. + */ + QUEUE_REMOVE(&req->queue); + QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); + uv__io_feed(handle->loop, &handle->io_watcher); + } +} + + +/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional + * refinements for programs that use multicast. + * + * Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that + * are different from the BSDs: it _shares_ the port rather than steal it + * from the current listener. While useful, it's not something we can emulate + * on other platforms so we don't enable it. + */ +static int uv__set_reuse(int fd) { + int yes; + +#if defined(SO_REUSEPORT) && !defined(__linux__) + yes = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) + return -errno; +#else + yes = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) + return -errno; +#endif + + return 0; +} + + +int uv__udp_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + int err; + int yes; + int fd; + + /* Check for bad flags. */ + if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR)) + return -EINVAL; + + /* Cannot set IPv6-only mode on non-IPv6 socket. */ + if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) + return -EINVAL; + + fd = handle->io_watcher.fd; + if (fd == -1) { + err = uv__socket(addr->sa_family, SOCK_DGRAM, 0); + if (err < 0) + return err; + fd = err; + handle->io_watcher.fd = fd; + } + + if (flags & UV_UDP_REUSEADDR) { + err = uv__set_reuse(fd); + if (err) + goto out; + } + + if (flags & UV_UDP_IPV6ONLY) { +#ifdef IPV6_V6ONLY + yes = 1; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) { + err = -errno; + goto out; + } +#else + err = -ENOTSUP; + goto out; +#endif + } + + if (bind(fd, addr, addrlen)) { + err = -errno; + if (errno == EAFNOSUPPORT) + /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a + * socket created with AF_INET to an AF_INET6 address or vice versa. */ + err = -EINVAL; + goto out; + } + + if (addr->sa_family == AF_INET6) + handle->flags |= UV_HANDLE_IPV6; + + handle->flags |= UV_HANDLE_BOUND; + + return 0; + +out: + uv__close(handle->io_watcher.fd); + handle->io_watcher.fd = -1; + return err; +} + + +static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, + int domain, + unsigned int flags) { + unsigned char taddr[sizeof(struct sockaddr_in6)]; + socklen_t addrlen; + + if (handle->io_watcher.fd != -1) + return 0; + + switch (domain) { + case AF_INET: + { + struct sockaddr_in* addr = (void*)&taddr; + memset(addr, 0, sizeof *addr); + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = INADDR_ANY; + addrlen = sizeof *addr; + break; + } + case AF_INET6: + { + struct sockaddr_in6* addr = (void*)&taddr; + memset(addr, 0, sizeof *addr); + addr->sin6_family = AF_INET6; + addr->sin6_addr = in6addr_any; + addrlen = sizeof *addr; + break; + } + default: + assert(0 && "unsupported address family"); + abort(); + } + + return uv__udp_bind(handle, (const struct sockaddr*) &taddr, addrlen, flags); +} + + +int uv__udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen, + uv_udp_send_cb send_cb) { + int err; + int empty_queue; + + assert(nbufs > 0); + + err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); + if (err) + return err; + + /* It's legal for send_queue_count > 0 even when the write_queue is empty; + * it means there are error-state requests in the write_completed_queue that + * will touch up send_queue_size/count later. + */ + empty_queue = (handle->send_queue_count == 0); + + uv__req_init(handle->loop, req, UV_UDP_SEND); + assert(addrlen <= sizeof(req->addr)); + memcpy(&req->addr, addr, addrlen); + req->send_cb = send_cb; + req->handle = handle; + req->nbufs = nbufs; + + req->bufs = req->bufsml; + if (nbufs > ARRAY_SIZE(req->bufsml)) + req->bufs = uv__malloc(nbufs * sizeof(bufs[0])); + + if (req->bufs == NULL) { + uv__req_unregister(handle->loop, req); + return -ENOMEM; + } + + memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); + handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs); + handle->send_queue_count++; + QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue); + uv__handle_start(handle); + + if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) { + uv__udp_sendmsg(handle); + } else { + uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); + } + + return 0; +} + + +int uv__udp_try_send(uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen) { + int err; + struct msghdr h; + ssize_t size; + + assert(nbufs > 0); + + /* already sending a message */ + if (handle->send_queue_count != 0) + return -EAGAIN; + + err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); + if (err) + return err; + + memset(&h, 0, sizeof h); + h.msg_name = (struct sockaddr*) addr; + h.msg_namelen = addrlen; + h.msg_iov = (struct iovec*) bufs; + h.msg_iovlen = nbufs; + + do { + size = sendmsg(handle->io_watcher.fd, &h, 0); + } while (size == -1 && errno == EINTR); + + if (size == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return -EAGAIN; + else + return -errno; + } + + return size; +} + + +static int uv__udp_set_membership4(uv_udp_t* handle, + const struct sockaddr_in* multicast_addr, + const char* interface_addr, + uv_membership membership) { + struct ip_mreq mreq; + int optname; + int err; + + memset(&mreq, 0, sizeof mreq); + + if (interface_addr) { + err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr); + if (err) + return err; + } else { + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + } + + mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr; + + switch (membership) { + case UV_JOIN_GROUP: + optname = IP_ADD_MEMBERSHIP; + break; + case UV_LEAVE_GROUP: + optname = IP_DROP_MEMBERSHIP; + break; + default: + return -EINVAL; + } + + if (setsockopt(handle->io_watcher.fd, + IPPROTO_IP, + optname, + &mreq, + sizeof(mreq))) { +#if defined(__MVS__) + if (errno == ENXIO) + return -ENODEV; +#endif + return -errno; + } + + return 0; +} + + +static int uv__udp_set_membership6(uv_udp_t* handle, + const struct sockaddr_in6* multicast_addr, + const char* interface_addr, + uv_membership membership) { + int optname; + struct ipv6_mreq mreq; + struct sockaddr_in6 addr6; + + memset(&mreq, 0, sizeof mreq); + + if (interface_addr) { + if (uv_ip6_addr(interface_addr, 0, &addr6)) + return -EINVAL; + mreq.ipv6mr_interface = addr6.sin6_scope_id; + } else { + mreq.ipv6mr_interface = 0; + } + + mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr; + + switch (membership) { + case UV_JOIN_GROUP: + optname = IPV6_ADD_MEMBERSHIP; + break; + case UV_LEAVE_GROUP: + optname = IPV6_DROP_MEMBERSHIP; + break; + default: + return -EINVAL; + } + + if (setsockopt(handle->io_watcher.fd, + IPPROTO_IPV6, + optname, + &mreq, + sizeof(mreq))) { +#if defined(__MVS__) + if (errno == ENXIO) + return -ENODEV; +#endif + return -errno; + } + + return 0; +} + + +int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) { + int domain; + int err; + int fd; + + /* Use the lower 8 bits for the domain */ + domain = flags & 0xFF; + if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) + return -EINVAL; + + if (flags & ~0xFF) + return -EINVAL; + + if (domain != AF_UNSPEC) { + err = uv__socket(domain, SOCK_DGRAM, 0); + if (err < 0) + return err; + fd = err; + } else { + fd = -1; + } + + uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP); + handle->alloc_cb = NULL; + handle->recv_cb = NULL; + handle->send_queue_size = 0; + handle->send_queue_count = 0; + uv__io_init(&handle->io_watcher, uv__udp_io, fd); + QUEUE_INIT(&handle->write_queue); + QUEUE_INIT(&handle->write_completed_queue); + return 0; +} + + +int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { + return uv_udp_init_ex(loop, handle, AF_UNSPEC); +} + + +int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { + int err; + + /* Check for already active socket. */ + if (handle->io_watcher.fd != -1) + return -EBUSY; + + err = uv__nonblock(sock, 1); + if (err) + return err; + + err = uv__set_reuse(sock); + if (err) + return err; + + handle->io_watcher.fd = sock; + return 0; +} + + +int uv_udp_set_membership(uv_udp_t* handle, + const char* multicast_addr, + const char* interface_addr, + uv_membership membership) { + int err; + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; + + if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0) { + err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR); + if (err) + return err; + return uv__udp_set_membership4(handle, &addr4, interface_addr, membership); + } else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0) { + err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR); + if (err) + return err; + return uv__udp_set_membership6(handle, &addr6, interface_addr, membership); + } else { + return -EINVAL; + } +} + +static int uv__setsockopt(uv_udp_t* handle, + int option4, + int option6, + const void* val, + size_t size) { + int r; + + if (handle->flags & UV_HANDLE_IPV6) + r = setsockopt(handle->io_watcher.fd, + IPPROTO_IPV6, + option6, + val, + size); + else + r = setsockopt(handle->io_watcher.fd, + IPPROTO_IP, + option4, + val, + size); + if (r) + return -errno; + + return 0; +} + +static int uv__setsockopt_maybe_char(uv_udp_t* handle, + int option4, + int option6, + int val) { +#if defined(__sun) || defined(_AIX) || defined(__MVS__) + char arg = val; +#elif defined(__OpenBSD__) + unsigned char arg = val; +#else + int arg = val; +#endif + + if (val < 0 || val > 255) + return -EINVAL; + + return uv__setsockopt(handle, option4, option6, &arg, sizeof(arg)); +} + + +int uv_udp_set_broadcast(uv_udp_t* handle, int on) { + if (setsockopt(handle->io_watcher.fd, + SOL_SOCKET, + SO_BROADCAST, + &on, + sizeof(on))) { + return -errno; + } + + return 0; +} + + +int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { + if (ttl < 1 || ttl > 255) + return -EINVAL; + +#if defined(__MVS__) + if (!(handle->flags & UV_HANDLE_IPV6)) + return -ENOTSUP; /* zOS does not support setting ttl for IPv4 */ +#endif + +/* + * On Solaris and derivatives such as SmartOS, the length of socket options + * is sizeof(int) for IP_TTL and IPV6_UNICAST_HOPS, + * so hardcode the size of these options on this platform, + * and use the general uv__setsockopt_maybe_char call on other platforms. + */ +#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ + defined(__MVS__) + + return uv__setsockopt(handle, + IP_TTL, + IPV6_UNICAST_HOPS, + &ttl, + sizeof(ttl)); +#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) || + defined(__MVS__) */ + + return uv__setsockopt_maybe_char(handle, + IP_TTL, + IPV6_UNICAST_HOPS, + ttl); +} + + +int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) { +/* + * On Solaris and derivatives such as SmartOS, the length of socket options + * is sizeof(int) for IPV6_MULTICAST_HOPS and sizeof(char) for + * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case, + * and use the general uv__setsockopt_maybe_char call otherwise. + */ +#if defined(__sun) || defined(_AIX) || defined(__MVS__) + if (handle->flags & UV_HANDLE_IPV6) + return uv__setsockopt(handle, + IP_MULTICAST_TTL, + IPV6_MULTICAST_HOPS, + &ttl, + sizeof(ttl)); +#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ + + return uv__setsockopt_maybe_char(handle, + IP_MULTICAST_TTL, + IPV6_MULTICAST_HOPS, + ttl); +} + + +int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) { +/* + * On Solaris and derivatives such as SmartOS, the length of socket options + * is sizeof(int) for IPV6_MULTICAST_LOOP and sizeof(char) for + * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case, + * and use the general uv__setsockopt_maybe_char call otherwise. + */ +#if defined(__sun) || defined(_AIX) || defined(__MVS__) + if (handle->flags & UV_HANDLE_IPV6) + return uv__setsockopt(handle, + IP_MULTICAST_LOOP, + IPV6_MULTICAST_LOOP, + &on, + sizeof(on)); +#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ + + return uv__setsockopt_maybe_char(handle, + IP_MULTICAST_LOOP, + IPV6_MULTICAST_LOOP, + on); +} + +int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) { + struct sockaddr_storage addr_st; + struct sockaddr_in* addr4; + struct sockaddr_in6* addr6; + + addr4 = (struct sockaddr_in*) &addr_st; + addr6 = (struct sockaddr_in6*) &addr_st; + + if (!interface_addr) { + memset(&addr_st, 0, sizeof addr_st); + if (handle->flags & UV_HANDLE_IPV6) { + addr_st.ss_family = AF_INET6; + addr6->sin6_scope_id = 0; + } else { + addr_st.ss_family = AF_INET; + addr4->sin_addr.s_addr = htonl(INADDR_ANY); + } + } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) { + /* nothing, address was parsed */ + } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) { + /* nothing, address was parsed */ + } else { + return -EINVAL; + } + + if (addr_st.ss_family == AF_INET) { + if (setsockopt(handle->io_watcher.fd, + IPPROTO_IP, + IP_MULTICAST_IF, + (void*) &addr4->sin_addr, + sizeof(addr4->sin_addr)) == -1) { + return -errno; + } + } else if (addr_st.ss_family == AF_INET6) { + if (setsockopt(handle->io_watcher.fd, + IPPROTO_IPV6, + IPV6_MULTICAST_IF, + &addr6->sin6_scope_id, + sizeof(addr6->sin6_scope_id)) == -1) { + return -errno; + } + } else { + assert(0 && "unexpected address family"); + abort(); + } + + return 0; +} + + +int uv_udp_getsockname(const uv_udp_t* handle, + struct sockaddr* name, + int* namelen) { + socklen_t socklen; + + if (handle->io_watcher.fd == -1) + return -EINVAL; /* FIXME(bnoordhuis) -EBADF */ + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (getsockname(handle->io_watcher.fd, name, &socklen)) + return -errno; + + *namelen = (int) socklen; + return 0; +} + + +int uv__udp_recv_start(uv_udp_t* handle, + uv_alloc_cb alloc_cb, + uv_udp_recv_cb recv_cb) { + int err; + + if (alloc_cb == NULL || recv_cb == NULL) + return -EINVAL; + + if (uv__io_active(&handle->io_watcher, POLLIN)) + return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */ + + err = uv__udp_maybe_deferred_bind(handle, AF_INET, 0); + if (err) + return err; + + handle->alloc_cb = alloc_cb; + handle->recv_cb = recv_cb; + + uv__io_start(handle->loop, &handle->io_watcher, POLLIN); + uv__handle_start(handle); + + return 0; +} + + +int uv__udp_recv_stop(uv_udp_t* handle) { + uv__io_stop(handle->loop, &handle->io_watcher, POLLIN); + + if (!uv__io_active(&handle->io_watcher, POLLOUT)) + uv__handle_stop(handle); + + handle->alloc_cb = NULL; + handle->recv_cb = NULL; + + return 0; +} diff --git a/src/uv-common.c b/src/uv-common.c new file mode 100644 index 0000000..434a502 --- /dev/null +++ b/src/uv-common.c @@ -0,0 +1,652 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "uv-common.h" + +#include +#include +#include +#include /* NULL */ +#include +#include /* malloc */ +#include /* memset */ + +#if defined(_WIN32) +# include /* malloc */ +#else +# include /* if_nametoindex */ +#endif + + +typedef struct { + uv_malloc_func local_malloc; + uv_realloc_func local_realloc; + uv_calloc_func local_calloc; + uv_free_func local_free; +} uv__allocator_t; + +static uv__allocator_t uv__allocator = { + malloc, + realloc, + calloc, + free, +}; + +char* uv__strdup(const char* s) { + size_t len = strlen(s) + 1; + char* m = uv__malloc(len); + if (m == NULL) + return NULL; + return memcpy(m, s, len); +} + +char* uv__strndup(const char* s, size_t n) { + char* m; + size_t len = strlen(s); + if (n < len) + len = n; + m = uv__malloc(len + 1); + if (m == NULL) + return NULL; + m[len] = '\0'; + return memcpy(m, s, len); +} + +void* uv__malloc(size_t size) { + return uv__allocator.local_malloc(size); +} + +void uv__free(void* ptr) { + int saved_errno; + + /* Libuv expects that free() does not clobber errno. The system allocator + * honors that assumption but custom allocators may not be so careful. + */ + saved_errno = errno; + uv__allocator.local_free(ptr); + errno = saved_errno; +} + +void* uv__calloc(size_t count, size_t size) { + return uv__allocator.local_calloc(count, size); +} + +void* uv__realloc(void* ptr, size_t size) { + return uv__allocator.local_realloc(ptr, size); +} + +int uv_replace_allocator(uv_malloc_func malloc_func, + uv_realloc_func realloc_func, + uv_calloc_func calloc_func, + uv_free_func free_func) { + if (malloc_func == NULL || realloc_func == NULL || + calloc_func == NULL || free_func == NULL) { + return UV_EINVAL; + } + + uv__allocator.local_malloc = malloc_func; + uv__allocator.local_realloc = realloc_func; + uv__allocator.local_calloc = calloc_func; + uv__allocator.local_free = free_func; + + return 0; +} + +#define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t); + +size_t uv_handle_size(uv_handle_type type) { + switch (type) { + UV_HANDLE_TYPE_MAP(XX) + default: + return -1; + } +} + +size_t uv_req_size(uv_req_type type) { + switch(type) { + UV_REQ_TYPE_MAP(XX) + default: + return -1; + } +} + +#undef XX + + +size_t uv_loop_size(void) { + return sizeof(uv_loop_t); +} + + +uv_buf_t uv_buf_init(char* base, unsigned int len) { + uv_buf_t buf; + buf.base = base; + buf.len = len; + return buf; +} + + +static const char* uv__unknown_err_code(int err) { + char buf[32]; + char* copy; + + snprintf(buf, sizeof(buf), "Unknown system error %d", err); + copy = uv__strdup(buf); + + return copy != NULL ? copy : "Unknown system error"; +} + + +#define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name; +const char* uv_err_name(int err) { + switch (err) { + UV_ERRNO_MAP(UV_ERR_NAME_GEN) + } + return uv__unknown_err_code(err); +} +#undef UV_ERR_NAME_GEN + + +#define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg; +const char* uv_strerror(int err) { + switch (err) { + UV_ERRNO_MAP(UV_STRERROR_GEN) + } + return uv__unknown_err_code(err); +} +#undef UV_STRERROR_GEN + + +int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) { + memset(addr, 0, sizeof(*addr)); + addr->sin_family = AF_INET; + addr->sin_port = htons(port); + return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr)); +} + + +int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) { + char address_part[40]; + size_t address_part_size; + const char* zone_index; + + memset(addr, 0, sizeof(*addr)); + addr->sin6_family = AF_INET6; + addr->sin6_port = htons(port); + + zone_index = strchr(ip, '%'); + if (zone_index != NULL) { + address_part_size = zone_index - ip; + if (address_part_size >= sizeof(address_part)) + address_part_size = sizeof(address_part) - 1; + + memcpy(address_part, ip, address_part_size); + address_part[address_part_size] = '\0'; + ip = address_part; + + zone_index++; /* skip '%' */ + /* NOTE: unknown interface (id=0) is silently ignored */ +#ifdef _WIN32 + addr->sin6_scope_id = atoi(zone_index); +#else + addr->sin6_scope_id = if_nametoindex(zone_index); +#endif + } + + return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr); +} + + +int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size) { + return uv_inet_ntop(AF_INET, &src->sin_addr, dst, size); +} + + +int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) { + return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size); +} + + +int uv_tcp_bind(uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int flags) { + unsigned int addrlen; + + if (handle->type != UV_TCP) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (addr->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return UV_EINVAL; + + return uv__tcp_bind(handle, addr, addrlen, flags); +} + + +int uv_udp_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int flags) { + unsigned int addrlen; + + if (handle->type != UV_UDP) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (addr->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return UV_EINVAL; + + return uv__udp_bind(handle, addr, addrlen, flags); +} + + +int uv_tcp_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + uv_connect_cb cb) { + unsigned int addrlen; + + if (handle->type != UV_TCP) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (addr->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return UV_EINVAL; + + return uv__tcp_connect(req, handle, addr, addrlen, cb); +} + + +int uv_udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + uv_udp_send_cb send_cb) { + unsigned int addrlen; + + if (handle->type != UV_UDP) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (addr->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return UV_EINVAL; + + return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb); +} + + +int uv_udp_try_send(uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr) { + unsigned int addrlen; + + if (handle->type != UV_UDP) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (addr->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return UV_EINVAL; + + return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen); +} + + +int uv_udp_recv_start(uv_udp_t* handle, + uv_alloc_cb alloc_cb, + uv_udp_recv_cb recv_cb) { + if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL) + return UV_EINVAL; + else + return uv__udp_recv_start(handle, alloc_cb, recv_cb); +} + + +int uv_udp_recv_stop(uv_udp_t* handle) { + if (handle->type != UV_UDP) + return UV_EINVAL; + else + return uv__udp_recv_stop(handle); +} + + +void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) { + QUEUE queue; + QUEUE* q; + uv_handle_t* h; + + QUEUE_MOVE(&loop->handle_queue, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + h = QUEUE_DATA(q, uv_handle_t, handle_queue); + + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&loop->handle_queue, q); + + if (h->flags & UV__HANDLE_INTERNAL) continue; + walk_cb(h, arg); + } +} + + +static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) { + const char* type; + QUEUE* q; + uv_handle_t* h; + + if (loop == NULL) + loop = uv_default_loop(); + + QUEUE_FOREACH(q, &loop->handle_queue) { + h = QUEUE_DATA(q, uv_handle_t, handle_queue); + + if (only_active && !uv__is_active(h)) + continue; + + switch (h->type) { +#define X(uc, lc) case UV_##uc: type = #lc; break; + UV_HANDLE_TYPE_MAP(X) +#undef X + default: type = ""; + } + + fprintf(stream, + "[%c%c%c] %-8s %p\n", + "R-"[!(h->flags & UV__HANDLE_REF)], + "A-"[!(h->flags & UV__HANDLE_ACTIVE)], + "I-"[!(h->flags & UV__HANDLE_INTERNAL)], + type, + (void*)h); + } +} + + +void uv_print_all_handles(uv_loop_t* loop, FILE* stream) { + uv__print_handles(loop, 0, stream); +} + + +void uv_print_active_handles(uv_loop_t* loop, FILE* stream) { + uv__print_handles(loop, 1, stream); +} + + +void uv_ref(uv_handle_t* handle) { + uv__handle_ref(handle); +} + + +void uv_unref(uv_handle_t* handle) { + uv__handle_unref(handle); +} + + +int uv_has_ref(const uv_handle_t* handle) { + return uv__has_ref(handle); +} + + +void uv_stop(uv_loop_t* loop) { + loop->stop_flag = 1; +} + + +uint64_t uv_now(const uv_loop_t* loop) { + return loop->time; +} + + + +size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) { + unsigned int i; + size_t bytes; + + bytes = 0; + for (i = 0; i < nbufs; i++) + bytes += (size_t) bufs[i].len; + + return bytes; +} + +int uv_recv_buffer_size(uv_handle_t* handle, int* value) { + return uv__socket_sockopt(handle, SO_RCVBUF, value); +} + +int uv_send_buffer_size(uv_handle_t* handle, int *value) { + return uv__socket_sockopt(handle, SO_SNDBUF, value); +} + +int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) { + size_t required_len; + + if (!uv__is_active(handle)) { + *size = 0; + return UV_EINVAL; + } + + required_len = strlen(handle->path); + if (required_len >= *size) { + *size = required_len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, handle->path, required_len); + *size = required_len; + buffer[required_len] = '\0'; + + return 0; +} + +/* The windows implementation does not have the same structure layout as + * the unix implementation (nbufs is not directly inside req but is + * contained in a nested union/struct) so this function locates it. +*/ +static unsigned int* uv__get_nbufs(uv_fs_t* req) { +#ifdef _WIN32 + return &req->fs.info.nbufs; +#else + return &req->nbufs; +#endif +} + +/* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows + * systems. So, the memory should be released using free(). On Windows, + * uv__malloc() is used, so use uv__free() to free memory. +*/ +#ifdef _WIN32 +# define uv__fs_scandir_free uv__free +#else +# define uv__fs_scandir_free free +#endif + +void uv__fs_scandir_cleanup(uv_fs_t* req) { + uv__dirent_t** dents; + + unsigned int* nbufs = uv__get_nbufs(req); + + dents = req->ptr; + if (*nbufs > 0 && *nbufs != (unsigned int) req->result) + (*nbufs)--; + for (; *nbufs < (unsigned int) req->result; (*nbufs)++) + uv__fs_scandir_free(dents[*nbufs]); + + uv__fs_scandir_free(req->ptr); + req->ptr = NULL; +} + + +int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) { + uv__dirent_t** dents; + uv__dirent_t* dent; + + unsigned int* nbufs = uv__get_nbufs(req); + + dents = req->ptr; + + /* Free previous entity */ + if (*nbufs > 0) + uv__fs_scandir_free(dents[*nbufs - 1]); + + /* End was already reached */ + if (*nbufs == (unsigned int) req->result) { + uv__fs_scandir_free(dents); + req->ptr = NULL; + return UV_EOF; + } + + dent = dents[(*nbufs)++]; + + ent->name = dent->d_name; +#ifdef HAVE_DIRENT_TYPES + switch (dent->d_type) { + case UV__DT_DIR: + ent->type = UV_DIRENT_DIR; + break; + case UV__DT_FILE: + ent->type = UV_DIRENT_FILE; + break; + case UV__DT_LINK: + ent->type = UV_DIRENT_LINK; + break; + case UV__DT_FIFO: + ent->type = UV_DIRENT_FIFO; + break; + case UV__DT_SOCKET: + ent->type = UV_DIRENT_SOCKET; + break; + case UV__DT_CHAR: + ent->type = UV_DIRENT_CHAR; + break; + case UV__DT_BLOCK: + ent->type = UV_DIRENT_BLOCK; + break; + default: + ent->type = UV_DIRENT_UNKNOWN; + } +#else + ent->type = UV_DIRENT_UNKNOWN; +#endif + + return 0; +} + + +int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) { + va_list ap; + int err; + + va_start(ap, option); + /* Any platform-agnostic options should be handled here. */ + err = uv__loop_configure(loop, option, ap); + va_end(ap); + + return err; +} + + +static uv_loop_t default_loop_struct; +static uv_loop_t* default_loop_ptr; + + +uv_loop_t* uv_default_loop(void) { + if (default_loop_ptr != NULL) + return default_loop_ptr; + + if (uv_loop_init(&default_loop_struct)) + return NULL; + + default_loop_ptr = &default_loop_struct; + return default_loop_ptr; +} + + +uv_loop_t* uv_loop_new(void) { + uv_loop_t* loop; + + loop = uv__malloc(sizeof(*loop)); + if (loop == NULL) + return NULL; + + if (uv_loop_init(loop)) { + uv__free(loop); + return NULL; + } + + return loop; +} + + +int uv_loop_close(uv_loop_t* loop) { + QUEUE* q; + uv_handle_t* h; + void* saved_data; + + if (!QUEUE_EMPTY(&(loop)->active_reqs)) + return UV_EBUSY; + + QUEUE_FOREACH(q, &loop->handle_queue) { + h = QUEUE_DATA(q, uv_handle_t, handle_queue); + if (!(h->flags & UV__HANDLE_INTERNAL)) + return UV_EBUSY; + } + + uv__loop_close(loop); + +#ifndef NDEBUG + saved_data = loop->data; + memset(loop, -1, sizeof(*loop)); + loop->data = saved_data; +#endif + if (loop == default_loop_ptr) + default_loop_ptr = NULL; + + return 0; +} + + +void uv_loop_delete(uv_loop_t* loop) { + uv_loop_t* default_loop; + int err; + + default_loop = default_loop_ptr; + + err = uv_loop_close(loop); + (void) err; /* Squelch compiler warnings. */ + assert(err == 0); + if (loop != default_loop) + uv__free(loop); +} diff --git a/src/uv-common.h b/src/uv-common.h new file mode 100644 index 0000000..27902fd --- /dev/null +++ b/src/uv-common.h @@ -0,0 +1,227 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +/* + * This file is private to libuv. It provides common functionality to both + * Windows and Unix backends. + */ + +#ifndef UV_COMMON_H_ +#define UV_COMMON_H_ + +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#include "uv.h" +#include "tree.h" +#include "queue.h" + +#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900 +extern int snprintf(char*, size_t, const char*, ...); +#endif + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#define container_of(ptr, type, member) \ + ((type *) ((char *) (ptr) - offsetof(type, member))) + +#define STATIC_ASSERT(expr) \ + void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)]) + +#ifndef _WIN32 +enum { + UV__HANDLE_INTERNAL = 0x8000, + UV__HANDLE_ACTIVE = 0x4000, + UV__HANDLE_REF = 0x2000, + UV__HANDLE_CLOSING = 0 /* no-op on unix */ +}; +#else +# define UV__HANDLE_INTERNAL 0x80 +# define UV__HANDLE_ACTIVE 0x40 +# define UV__HANDLE_REF 0x20 +# define UV__HANDLE_CLOSING 0x01 +#endif + +int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap); + +void uv__loop_close(uv_loop_t* loop); + +int uv__tcp_bind(uv_tcp_t* tcp, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags); + +int uv__tcp_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + uv_connect_cb cb); + +int uv__udp_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags); + +int uv__udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen, + uv_udp_send_cb send_cb); + +int uv__udp_try_send(uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen); + +int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb, + uv_udp_recv_cb recv_cb); + +int uv__udp_recv_stop(uv_udp_t* handle); + +void uv__fs_poll_close(uv_fs_poll_t* handle); + +int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */ + +void uv__work_submit(uv_loop_t* loop, + struct uv__work *w, + void (*work)(struct uv__work *w), + void (*done)(struct uv__work *w, int status)); + +void uv__work_done(uv_async_t* handle); + +size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs); + +int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value); + +void uv__fs_scandir_cleanup(uv_fs_t* req); + +#define uv__has_active_reqs(loop) \ + (QUEUE_EMPTY(&(loop)->active_reqs) == 0) + +#define uv__req_register(loop, req) \ + do { \ + QUEUE_INSERT_TAIL(&(loop)->active_reqs, &(req)->active_queue); \ + } \ + while (0) + +#define uv__req_unregister(loop, req) \ + do { \ + assert(uv__has_active_reqs(loop)); \ + QUEUE_REMOVE(&(req)->active_queue); \ + } \ + while (0) + +#define uv__has_active_handles(loop) \ + ((loop)->active_handles > 0) + +#define uv__active_handle_add(h) \ + do { \ + (h)->loop->active_handles++; \ + } \ + while (0) + +#define uv__active_handle_rm(h) \ + do { \ + (h)->loop->active_handles--; \ + } \ + while (0) + +#define uv__is_active(h) \ + (((h)->flags & UV__HANDLE_ACTIVE) != 0) + +#define uv__is_closing(h) \ + (((h)->flags & (UV_CLOSING | UV_CLOSED)) != 0) + +#define uv__handle_start(h) \ + do { \ + assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \ + if (((h)->flags & UV__HANDLE_ACTIVE) != 0) break; \ + (h)->flags |= UV__HANDLE_ACTIVE; \ + if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_add(h); \ + } \ + while (0) + +#define uv__handle_stop(h) \ + do { \ + assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \ + if (((h)->flags & UV__HANDLE_ACTIVE) == 0) break; \ + (h)->flags &= ~UV__HANDLE_ACTIVE; \ + if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_rm(h); \ + } \ + while (0) + +#define uv__handle_ref(h) \ + do { \ + if (((h)->flags & UV__HANDLE_REF) != 0) break; \ + (h)->flags |= UV__HANDLE_REF; \ + if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \ + if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \ + } \ + while (0) + +#define uv__handle_unref(h) \ + do { \ + if (((h)->flags & UV__HANDLE_REF) == 0) break; \ + (h)->flags &= ~UV__HANDLE_REF; \ + if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \ + if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \ + } \ + while (0) + +#define uv__has_ref(h) \ + (((h)->flags & UV__HANDLE_REF) != 0) + +#if defined(_WIN32) +# define uv__handle_platform_init(h) ((h)->u.fd = -1) +#else +# define uv__handle_platform_init(h) ((h)->next_closing = NULL) +#endif + +#define uv__handle_init(loop_, h, type_) \ + do { \ + (h)->loop = (loop_); \ + (h)->type = (type_); \ + (h)->flags = UV__HANDLE_REF; /* Ref the loop when active. */ \ + QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \ + uv__handle_platform_init(h); \ + } \ + while (0) + + +/* Allocator prototypes */ +void *uv__calloc(size_t count, size_t size); +char *uv__strdup(const char* s); +char *uv__strndup(const char* s, size_t n); +void* uv__malloc(size_t size); +void uv__free(void* ptr); +void* uv__realloc(void* ptr, size_t size); + +#endif /* UV_COMMON_H_ */ diff --git a/src/version.c b/src/version.c new file mode 100644 index 0000000..686dedd --- /dev/null +++ b/src/version.c @@ -0,0 +1,45 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" + +#define UV_STRINGIFY(v) UV_STRINGIFY_HELPER(v) +#define UV_STRINGIFY_HELPER(v) #v + +#define UV_VERSION_STRING_BASE UV_STRINGIFY(UV_VERSION_MAJOR) "." \ + UV_STRINGIFY(UV_VERSION_MINOR) "." \ + UV_STRINGIFY(UV_VERSION_PATCH) + +#if UV_VERSION_IS_RELEASE +# define UV_VERSION_STRING UV_VERSION_STRING_BASE +#else +# define UV_VERSION_STRING UV_VERSION_STRING_BASE "-" UV_VERSION_SUFFIX +#endif + + +unsigned int uv_version(void) { + return UV_VERSION_HEX; +} + + +const char* uv_version_string(void) { + return UV_VERSION_STRING; +} diff --git a/src/win/async.c b/src/win/async.c new file mode 100644 index 0000000..ad240ab --- /dev/null +++ b/src/win/async.c @@ -0,0 +1,99 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include + +#include "uv.h" +#include "internal.h" +#include "atomicops-inl.h" +#include "handle-inl.h" +#include "req-inl.h" + + +void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) { + if (handle->flags & UV__HANDLE_CLOSING && + !handle->async_sent) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); + } +} + + +int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { + uv_req_t* req; + + uv__handle_init(loop, (uv_handle_t*) handle, UV_ASYNC); + handle->async_sent = 0; + handle->async_cb = async_cb; + + req = &handle->async_req; + uv_req_init(loop, req); + req->type = UV_WAKEUP; + req->data = handle; + + uv__handle_start(handle); + + return 0; +} + + +void uv_async_close(uv_loop_t* loop, uv_async_t* handle) { + if (!((uv_async_t*)handle)->async_sent) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + + uv__handle_closing(handle); +} + + +int uv_async_send(uv_async_t* handle) { + uv_loop_t* loop = handle->loop; + + if (handle->type != UV_ASYNC) { + /* Can't set errno because that's not thread-safe. */ + return -1; + } + + /* The user should make sure never to call uv_async_send to a closing */ + /* or closed handle. */ + assert(!(handle->flags & UV__HANDLE_CLOSING)); + + if (!uv__atomic_exchange_set(&handle->async_sent)) { + POST_COMPLETION_FOR_REQ(loop, &handle->async_req); + } + + return 0; +} + + +void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, + uv_req_t* req) { + assert(handle->type == UV_ASYNC); + assert(req->type == UV_WAKEUP); + + handle->async_sent = 0; + + if (handle->flags & UV__HANDLE_CLOSING) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } else if (handle->async_cb != NULL) { + handle->async_cb(handle); + } +} diff --git a/src/win/atomicops-inl.h b/src/win/atomicops-inl.h new file mode 100644 index 0000000..61e0060 --- /dev/null +++ b/src/win/atomicops-inl.h @@ -0,0 +1,56 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_WIN_ATOMICOPS_INL_H_ +#define UV_WIN_ATOMICOPS_INL_H_ + +#include "uv.h" + + +/* Atomic set operation on char */ +#ifdef _MSC_VER /* MSVC */ + +/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */ +/* efficient than InterlockedExchange, but InterlockedExchange8 does not */ +/* exist, and interlocked operations on larger targets might require the */ +/* target to be aligned. */ +#pragma intrinsic(_InterlockedOr8) + +static char __declspec(inline) uv__atomic_exchange_set(char volatile* target) { + return _InterlockedOr8(target, 1); +} + +#else /* GCC */ + +/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */ +static inline char uv__atomic_exchange_set(char volatile* target) { + const char one = 1; + char old_value; + __asm__ __volatile__ ("lock xchgb %0, %1\n\t" + : "=r"(old_value), "=m"(*target) + : "0"(one), "m"(*target) + : "memory"); + return old_value; +} + +#endif + +#endif /* UV_WIN_ATOMICOPS_INL_H_ */ diff --git a/src/win/core.c b/src/win/core.c new file mode 100644 index 0000000..9d00afc --- /dev/null +++ b/src/win/core.c @@ -0,0 +1,602 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) +#include +#endif + +#include "uv.h" +#include "internal.h" +#include "queue.h" +#include "handle-inl.h" +#include "req-inl.h" + + +static uv_loop_t default_loop_struct; +static uv_loop_t* default_loop_ptr; + +/* uv_once initialization guards */ +static uv_once_t uv_init_guard_ = UV_ONCE_INIT; + + +#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)) +/* Our crt debug report handler allows us to temporarily disable asserts + * just for the current thread. + */ + +UV_THREAD_LOCAL int uv__crt_assert_enabled = TRUE; + +static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) { + if (uv__crt_assert_enabled || report_type != _CRT_ASSERT) + return FALSE; + + if (ret_val) { + /* Set ret_val to 0 to continue with normal execution. + * Set ret_val to 1 to trigger a breakpoint. + */ + + if(IsDebuggerPresent()) + *ret_val = 1; + else + *ret_val = 0; + } + + /* Don't call _CrtDbgReport. */ + return TRUE; +} +#else +UV_THREAD_LOCAL int uv__crt_assert_enabled = FALSE; +#endif + + +#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800 +static void uv__crt_invalid_parameter_handler(const wchar_t* expression, + const wchar_t* function, const wchar_t * file, unsigned int line, + uintptr_t reserved) { + /* No-op. */ +} +#endif + +static uv_loop_t** uv__loops; +static int uv__loops_size; +static int uv__loops_capacity; +#define UV__LOOPS_CHUNK_SIZE 8 +static uv_mutex_t uv__loops_lock; + +static void uv__loops_init() { + uv_mutex_init(&uv__loops_lock); + uv__loops = uv__calloc(UV__LOOPS_CHUNK_SIZE, sizeof(uv_loop_t*)); + if (!uv__loops) + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + uv__loops_size = 0; + uv__loops_capacity = UV__LOOPS_CHUNK_SIZE; +} + +static int uv__loops_add(uv_loop_t* loop) { + uv_loop_t** new_loops; + int new_capacity, i; + + uv_mutex_lock(&uv__loops_lock); + + if (uv__loops_size == uv__loops_capacity) { + new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE; + new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity); + if (!new_loops) + goto failed_loops_realloc; + uv__loops = new_loops; + for (i = uv__loops_capacity; i < new_capacity; ++i) + uv__loops[i] = NULL; + uv__loops_capacity = new_capacity; + } + uv__loops[uv__loops_size] = loop; + ++uv__loops_size; + + uv_mutex_unlock(&uv__loops_lock); + return 0; + +failed_loops_realloc: + uv_mutex_unlock(&uv__loops_lock); + return ERROR_OUTOFMEMORY; +} + +static void uv__loops_remove(uv_loop_t* loop) { + int loop_index; + int smaller_capacity; + uv_loop_t** new_loops; + + uv_mutex_lock(&uv__loops_lock); + + for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) { + if (uv__loops[loop_index] == loop) + break; + } + /* If loop was not found, ignore */ + if (loop_index == uv__loops_size) + goto loop_removed; + + uv__loops[loop_index] = uv__loops[uv__loops_size - 1]; + uv__loops[uv__loops_size - 1] = NULL; + --uv__loops_size; + + /* If we didn't grow to big skip downsizing */ + if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE) + goto loop_removed; + + /* Downsize only if more than half of buffer is free */ + smaller_capacity = uv__loops_capacity / 2; + if (uv__loops_size >= smaller_capacity) + goto loop_removed; + new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity); + if (!new_loops) + goto loop_removed; + uv__loops = new_loops; + uv__loops_capacity = smaller_capacity; + +loop_removed: + uv_mutex_unlock(&uv__loops_lock); +} + +void uv__wake_all_loops() { + int i; + uv_loop_t* loop; + + uv_mutex_lock(&uv__loops_lock); + for (i = 0; i < uv__loops_size; ++i) { + loop = uv__loops[i]; + assert(loop); + if (loop->iocp != INVALID_HANDLE_VALUE) + PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL); + } + uv_mutex_unlock(&uv__loops_lock); +} + +static void uv_init(void) { + /* Tell Windows that we will handle critical errors. */ + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX); + + /* Tell the CRT to not exit the application when an invalid parameter is + * passed. The main issue is that invalid FDs will trigger this behavior. + */ +#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800 + _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler); +#endif + + /* We also need to setup our debug report handler because some CRT + * functions (eg _get_osfhandle) raise an assert when called with invalid + * FDs even though they return the proper error code in the release build. + */ +#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)) + _CrtSetReportHook(uv__crt_dbg_report_handler); +#endif + + /* Initialize tracking of all uv loops */ + uv__loops_init(); + + /* Fetch winapi function pointers. This must be done first because other + * initialization code might need these function pointers to be loaded. + */ + uv_winapi_init(); + + /* Initialize winsock */ + uv_winsock_init(); + + /* Initialize FS */ + uv_fs_init(); + + /* Initialize signal stuff */ + uv_signals_init(); + + /* Initialize console */ + uv_console_init(); + + /* Initialize utilities */ + uv__util_init(); + + /* Initialize system wakeup detection */ + uv__init_detect_system_wakeup(); +} + + +int uv_loop_init(uv_loop_t* loop) { + int err; + + /* Initialize libuv itself first */ + uv__once_init(); + + /* Create an I/O completion port */ + loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); + if (loop->iocp == NULL) + return uv_translate_sys_error(GetLastError()); + + /* To prevent uninitialized memory access, loop->time must be initialized + * to zero before calling uv_update_time for the first time. + */ + loop->time = 0; + uv_update_time(loop); + + QUEUE_INIT(&loop->wq); + QUEUE_INIT(&loop->handle_queue); + QUEUE_INIT(&loop->active_reqs); + loop->active_handles = 0; + + loop->pending_reqs_tail = NULL; + + loop->endgame_handles = NULL; + + RB_INIT(&loop->timers); + + loop->check_handles = NULL; + loop->prepare_handles = NULL; + loop->idle_handles = NULL; + + loop->next_prepare_handle = NULL; + loop->next_check_handle = NULL; + loop->next_idle_handle = NULL; + + memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets); + + loop->active_tcp_streams = 0; + loop->active_udp_streams = 0; + + loop->timer_counter = 0; + loop->stop_flag = 0; + + err = uv_mutex_init(&loop->wq_mutex); + if (err) + goto fail_mutex_init; + + err = uv_async_init(loop, &loop->wq_async, uv__work_done); + if (err) + goto fail_async_init; + + uv__handle_unref(&loop->wq_async); + loop->wq_async.flags |= UV__HANDLE_INTERNAL; + + err = uv__loops_add(loop); + if (err) + goto fail_async_init; + + return 0; + +fail_async_init: + uv_mutex_destroy(&loop->wq_mutex); + +fail_mutex_init: + CloseHandle(loop->iocp); + loop->iocp = INVALID_HANDLE_VALUE; + + return err; +} + + +void uv__once_init(void) { + uv_once(&uv_init_guard_, uv_init); +} + + +void uv__loop_close(uv_loop_t* loop) { + size_t i; + + uv__loops_remove(loop); + + /* close the async handle without needing an extra loop iteration */ + assert(!loop->wq_async.async_sent); + loop->wq_async.close_cb = NULL; + uv__handle_closing(&loop->wq_async); + uv__handle_close(&loop->wq_async); + + for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) { + SOCKET sock = loop->poll_peer_sockets[i]; + if (sock != 0 && sock != INVALID_SOCKET) + closesocket(sock); + } + + uv_mutex_lock(&loop->wq_mutex); + assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!"); + assert(!uv__has_active_reqs(loop)); + uv_mutex_unlock(&loop->wq_mutex); + uv_mutex_destroy(&loop->wq_mutex); + + CloseHandle(loop->iocp); +} + + +int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) { + return UV_ENOSYS; +} + + +int uv_backend_fd(const uv_loop_t* loop) { + return -1; +} + + +int uv_backend_timeout(const uv_loop_t* loop) { + if (loop->stop_flag != 0) + return 0; + + if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop)) + return 0; + + if (loop->pending_reqs_tail) + return 0; + + if (loop->endgame_handles) + return 0; + + if (loop->idle_handles) + return 0; + + return uv__next_timeout(loop); +} + + +static void uv_poll(uv_loop_t* loop, DWORD timeout) { + DWORD bytes; + ULONG_PTR key; + OVERLAPPED* overlapped; + uv_req_t* req; + int repeat; + uint64_t timeout_time; + + timeout_time = loop->time + timeout; + + for (repeat = 0; ; repeat++) { + GetQueuedCompletionStatus(loop->iocp, + &bytes, + &key, + &overlapped, + timeout); + + if (overlapped) { + /* Package was dequeued */ + req = uv_overlapped_to_req(overlapped); + uv_insert_pending_req(loop, req); + + /* Some time might have passed waiting for I/O, + * so update the loop time here. + */ + uv_update_time(loop); + } else if (GetLastError() != WAIT_TIMEOUT) { + /* Serious error */ + uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); + } else if (timeout > 0) { + /* GetQueuedCompletionStatus can occasionally return a little early. + * Make sure that the desired timeout target time is reached. + */ + uv_update_time(loop); + if (timeout_time > loop->time) { + timeout = (DWORD)(timeout_time - loop->time); + /* The first call to GetQueuedCompletionStatus should return very + * close to the target time and the second should reach it, but + * this is not stated in the documentation. To make sure a busy + * loop cannot happen, the timeout is increased exponentially + * starting on the third round. + */ + timeout += repeat ? (1 << (repeat - 1)) : 0; + continue; + } + } + break; + } +} + + +static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { + BOOL success; + uv_req_t* req; + OVERLAPPED_ENTRY overlappeds[128]; + ULONG count; + ULONG i; + int repeat; + uint64_t timeout_time; + + timeout_time = loop->time + timeout; + + for (repeat = 0; ; repeat++) { + success = pGetQueuedCompletionStatusEx(loop->iocp, + overlappeds, + ARRAY_SIZE(overlappeds), + &count, + timeout, + FALSE); + + if (success) { + for (i = 0; i < count; i++) { + /* Package was dequeued, but see if it is not a empty package + * meant only to wake us up. + */ + if (overlappeds[i].lpOverlapped) { + req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); + uv_insert_pending_req(loop, req); + } + } + + /* Some time might have passed waiting for I/O, + * so update the loop time here. + */ + uv_update_time(loop); + } else if (GetLastError() != WAIT_TIMEOUT) { + /* Serious error */ + uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx"); + } else if (timeout > 0) { + /* GetQueuedCompletionStatus can occasionally return a little early. + * Make sure that the desired timeout target time is reached. + */ + uv_update_time(loop); + if (timeout_time > loop->time) { + timeout = (DWORD)(timeout_time - loop->time); + /* The first call to GetQueuedCompletionStatus should return very + * close to the target time and the second should reach it, but + * this is not stated in the documentation. To make sure a busy + * loop cannot happen, the timeout is increased exponentially + * starting on the third round. + */ + timeout += repeat ? (1 << (repeat - 1)) : 0; + continue; + } + } + break; + } +} + + +static int uv__loop_alive(const uv_loop_t* loop) { + return loop->active_handles > 0 || + !QUEUE_EMPTY(&loop->active_reqs) || + loop->endgame_handles != NULL; +} + + +int uv_loop_alive(const uv_loop_t* loop) { + return uv__loop_alive(loop); +} + + +int uv_run(uv_loop_t *loop, uv_run_mode mode) { + DWORD timeout; + int r; + int ran_pending; + void (*poll)(uv_loop_t* loop, DWORD timeout); + + if (pGetQueuedCompletionStatusEx) + poll = &uv_poll_ex; + else + poll = &uv_poll; + + r = uv__loop_alive(loop); + if (!r) + uv_update_time(loop); + + while (r != 0 && loop->stop_flag == 0) { + uv_update_time(loop); + uv_process_timers(loop); + + ran_pending = uv_process_reqs(loop); + uv_idle_invoke(loop); + uv_prepare_invoke(loop); + + timeout = 0; + if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) + timeout = uv_backend_timeout(loop); + + (*poll)(loop, timeout); + + uv_check_invoke(loop); + uv_process_endgames(loop); + + if (mode == UV_RUN_ONCE) { + /* UV_RUN_ONCE implies forward progress: at least one callback must have + * been invoked when it returns. uv__io_poll() can return without doing + * I/O (meaning: no callbacks) when its timeout expires - which means we + * have pending timers that satisfy the forward progress constraint. + * + * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from + * the check. + */ + uv_process_timers(loop); + } + + r = uv__loop_alive(loop); + if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT) + break; + } + + /* The if statement lets the compiler compile it to a conditional store. + * Avoids dirtying a cache line. + */ + if (loop->stop_flag != 0) + loop->stop_flag = 0; + + return r; +} + + +int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) { + uv_os_fd_t fd_out; + + switch (handle->type) { + case UV_TCP: + fd_out = (uv_os_fd_t)((uv_tcp_t*) handle)->socket; + break; + + case UV_NAMED_PIPE: + fd_out = ((uv_pipe_t*) handle)->handle; + break; + + case UV_TTY: + fd_out = ((uv_tty_t*) handle)->handle; + break; + + case UV_UDP: + fd_out = (uv_os_fd_t)((uv_udp_t*) handle)->socket; + break; + + case UV_POLL: + fd_out = (uv_os_fd_t)((uv_poll_t*) handle)->socket; + break; + + default: + return UV_EINVAL; + } + + if (uv_is_closing(handle) || fd_out == INVALID_HANDLE_VALUE) + return UV_EBADF; + + *fd = fd_out; + return 0; +} + + +int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { + int r; + int len; + SOCKET socket; + + if (handle == NULL || value == NULL) + return UV_EINVAL; + + if (handle->type == UV_TCP) + socket = ((uv_tcp_t*) handle)->socket; + else if (handle->type == UV_UDP) + socket = ((uv_udp_t*) handle)->socket; + else + return UV_ENOTSUP; + + len = sizeof(*value); + + if (*value == 0) + r = getsockopt(socket, SOL_SOCKET, optname, (char*) value, &len); + else + r = setsockopt(socket, SOL_SOCKET, optname, (const char*) value, len); + + if (r == SOCKET_ERROR) + return uv_translate_sys_error(WSAGetLastError()); + + return 0; +} diff --git a/src/win/detect-wakeup.c b/src/win/detect-wakeup.c new file mode 100644 index 0000000..a12179f --- /dev/null +++ b/src/win/detect-wakeup.c @@ -0,0 +1,35 @@ +#include "uv.h" +#include "internal.h" +#include "winapi.h" + +static void uv__register_system_resume_callback(); + +void uv__init_detect_system_wakeup() { + /* Try registering system power event callback. This is the cleanest + * method, but it will only work on Win8 and above. + */ + uv__register_system_resume_callback(); +} + +static ULONG CALLBACK uv__system_resume_callback(PVOID Context, + ULONG Type, + PVOID Setting) { + if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC) + uv__wake_all_loops(); + + return 0; +} + +static void uv__register_system_resume_callback() { + _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient; + _HPOWERNOTIFY registration_handle; + + if (pPowerRegisterSuspendResumeNotification == NULL) + return; + + recipient.Callback = uv__system_resume_callback; + recipient.Context = NULL; + (*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK, + &recipient, + ®istration_handle); +} diff --git a/src/win/dl.c b/src/win/dl.c new file mode 100644 index 0000000..39e400a --- /dev/null +++ b/src/win/dl.c @@ -0,0 +1,118 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +static int uv__dlerror(uv_lib_t* lib, int errorno); + + +int uv_dlopen(const char* filename, uv_lib_t* lib) { + WCHAR filename_w[32768]; + + lib->handle = NULL; + lib->errmsg = NULL; + + if (!MultiByteToWideChar(CP_UTF8, + 0, + filename, + -1, + filename_w, + ARRAY_SIZE(filename_w))) { + return uv__dlerror(lib, GetLastError()); + } + + lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (lib->handle == NULL) { + return uv__dlerror(lib, GetLastError()); + } + + return 0; +} + + +void uv_dlclose(uv_lib_t* lib) { + if (lib->errmsg) { + LocalFree((void*)lib->errmsg); + lib->errmsg = NULL; + } + + if (lib->handle) { + /* Ignore errors. No good way to signal them without leaking memory. */ + FreeLibrary(lib->handle); + lib->handle = NULL; + } +} + + +int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) { + *ptr = (void*) GetProcAddress(lib->handle, name); + return uv__dlerror(lib, *ptr ? 0 : GetLastError()); +} + + +const char* uv_dlerror(const uv_lib_t* lib) { + return lib->errmsg ? lib->errmsg : "no error"; +} + + +static void uv__format_fallback_error(uv_lib_t* lib, int errorno){ + DWORD_PTR args[1] = { (DWORD_PTR) errorno }; + LPSTR fallback_error = "error: %1!d!"; + + FormatMessageA(FORMAT_MESSAGE_FROM_STRING | + FORMAT_MESSAGE_ARGUMENT_ARRAY | + FORMAT_MESSAGE_ALLOCATE_BUFFER, + fallback_error, 0, 0, + (LPSTR) &lib->errmsg, + 0, (va_list*) args); +} + + + +static int uv__dlerror(uv_lib_t* lib, int errorno) { + DWORD res; + + if (lib->errmsg) { + LocalFree((void*)lib->errmsg); + lib->errmsg = NULL; + } + + if (errorno) { + res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + (LPSTR) &lib->errmsg, 0, NULL); + if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) { + res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, + 0, (LPSTR) &lib->errmsg, 0, NULL); + } + + if (!res) { + uv__format_fallback_error(lib, errorno); + } + } + + return errorno ? -1 : 0; +} diff --git a/src/win/error.c b/src/win/error.c new file mode 100644 index 0000000..c512f35 --- /dev/null +++ b/src/win/error.c @@ -0,0 +1,170 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" + + +/* + * Display an error message and abort the event loop. + */ +void uv_fatal_error(const int errorno, const char* syscall) { + char* buf = NULL; + const char* errmsg; + + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL); + + if (buf) { + errmsg = buf; + } else { + errmsg = "Unknown error"; + } + + /* FormatMessage messages include a newline character already, */ + /* so don't add another. */ + if (syscall) { + fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg); + } else { + fprintf(stderr, "(%d) %s", errorno, errmsg); + } + + if (buf) { + LocalFree(buf); + } + + *((char*)NULL) = 0xff; /* Force debug break */ + abort(); +} + + +int uv_translate_sys_error(int sys_errno) { + if (sys_errno <= 0) { + return sys_errno; /* If < 0 then it's already a libuv error. */ + } + + switch (sys_errno) { + case ERROR_NOACCESS: return UV_EACCES; + case WSAEACCES: return UV_EACCES; + case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE; + case WSAEADDRINUSE: return UV_EADDRINUSE; + case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL; + case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT; + case WSAEWOULDBLOCK: return UV_EAGAIN; + case WSAEALREADY: return UV_EALREADY; + case ERROR_INVALID_FLAGS: return UV_EBADF; + case ERROR_INVALID_HANDLE: return UV_EBADF; + case ERROR_LOCK_VIOLATION: return UV_EBUSY; + case ERROR_PIPE_BUSY: return UV_EBUSY; + case ERROR_SHARING_VIOLATION: return UV_EBUSY; + case ERROR_OPERATION_ABORTED: return UV_ECANCELED; + case WSAEINTR: return UV_ECANCELED; + case ERROR_NO_UNICODE_TRANSLATION: return UV_ECHARSET; + case ERROR_CONNECTION_ABORTED: return UV_ECONNABORTED; + case WSAECONNABORTED: return UV_ECONNABORTED; + case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED; + case WSAECONNREFUSED: return UV_ECONNREFUSED; + case ERROR_NETNAME_DELETED: return UV_ECONNRESET; + case WSAECONNRESET: return UV_ECONNRESET; + case ERROR_ALREADY_EXISTS: return UV_EEXIST; + case ERROR_FILE_EXISTS: return UV_EEXIST; + case ERROR_BUFFER_OVERFLOW: return UV_EFAULT; + case WSAEFAULT: return UV_EFAULT; + case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH; + case WSAEHOSTUNREACH: return UV_EHOSTUNREACH; + case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL; + case ERROR_INVALID_DATA: return UV_EINVAL; + case ERROR_INVALID_PARAMETER: return UV_EINVAL; + case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL; + case WSAEINVAL: return UV_EINVAL; + case WSAEPFNOSUPPORT: return UV_EINVAL; + case WSAESOCKTNOSUPPORT: return UV_EINVAL; + case ERROR_BEGINNING_OF_MEDIA: return UV_EIO; + case ERROR_BUS_RESET: return UV_EIO; + case ERROR_CRC: return UV_EIO; + case ERROR_DEVICE_DOOR_OPEN: return UV_EIO; + case ERROR_DEVICE_REQUIRES_CLEANING: return UV_EIO; + case ERROR_DISK_CORRUPT: return UV_EIO; + case ERROR_EOM_OVERFLOW: return UV_EIO; + case ERROR_FILEMARK_DETECTED: return UV_EIO; + case ERROR_GEN_FAILURE: return UV_EIO; + case ERROR_INVALID_BLOCK_LENGTH: return UV_EIO; + case ERROR_IO_DEVICE: return UV_EIO; + case ERROR_NO_DATA_DETECTED: return UV_EIO; + case ERROR_NO_SIGNAL_SENT: return UV_EIO; + case ERROR_OPEN_FAILED: return UV_EIO; + case ERROR_SETMARK_DETECTED: return UV_EIO; + case ERROR_SIGNAL_REFUSED: return UV_EIO; + case WSAEISCONN: return UV_EISCONN; + case ERROR_CANT_RESOLVE_FILENAME: return UV_ELOOP; + case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE; + case WSAEMFILE: return UV_EMFILE; + case WSAEMSGSIZE: return UV_EMSGSIZE; + case ERROR_FILENAME_EXCED_RANGE: return UV_ENAMETOOLONG; + case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH; + case WSAENETUNREACH: return UV_ENETUNREACH; + case WSAENOBUFS: return UV_ENOBUFS; + case ERROR_BAD_PATHNAME: return UV_ENOENT; + case ERROR_DIRECTORY: return UV_ENOENT; + case ERROR_FILE_NOT_FOUND: return UV_ENOENT; + case ERROR_INVALID_NAME: return UV_ENOENT; + case ERROR_INVALID_DRIVE: return UV_ENOENT; + case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT; + case ERROR_MOD_NOT_FOUND: return UV_ENOENT; + case ERROR_PATH_NOT_FOUND: return UV_ENOENT; + case WSAHOST_NOT_FOUND: return UV_ENOENT; + case WSANO_DATA: return UV_ENOENT; + case ERROR_NOT_ENOUGH_MEMORY: return UV_ENOMEM; + case ERROR_OUTOFMEMORY: return UV_ENOMEM; + case ERROR_CANNOT_MAKE: return UV_ENOSPC; + case ERROR_DISK_FULL: return UV_ENOSPC; + case ERROR_EA_TABLE_FULL: return UV_ENOSPC; + case ERROR_END_OF_MEDIA: return UV_ENOSPC; + case ERROR_HANDLE_DISK_FULL: return UV_ENOSPC; + case ERROR_NOT_CONNECTED: return UV_ENOTCONN; + case WSAENOTCONN: return UV_ENOTCONN; + case ERROR_DIR_NOT_EMPTY: return UV_ENOTEMPTY; + case WSAENOTSOCK: return UV_ENOTSOCK; + case ERROR_NOT_SUPPORTED: return UV_ENOTSUP; + case ERROR_BROKEN_PIPE: return UV_EOF; + case ERROR_ACCESS_DENIED: return UV_EPERM; + case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM; + case ERROR_BAD_PIPE: return UV_EPIPE; + case ERROR_NO_DATA: return UV_EPIPE; + case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE; + case WSAESHUTDOWN: return UV_EPIPE; + case WSAEPROTONOSUPPORT: return UV_EPROTONOSUPPORT; + case ERROR_WRITE_PROTECT: return UV_EROFS; + case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT; + case WSAETIMEDOUT: return UV_ETIMEDOUT; + case ERROR_NOT_SAME_DEVICE: return UV_EXDEV; + case ERROR_INVALID_FUNCTION: return UV_EISDIR; + case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG; + default: return UV_UNKNOWN; + } +} diff --git a/src/win/fs-event.c b/src/win/fs-event.c new file mode 100644 index 0000000..03e4adc --- /dev/null +++ b/src/win/fs-event.c @@ -0,0 +1,545 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +const unsigned int uv_directory_watcher_buffer_size = 4096; + + +static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop, + uv_fs_event_t* handle) { + assert(handle->dir_handle != INVALID_HANDLE_VALUE); + assert(!handle->req_pending); + + memset(&(handle->req.u.io.overlapped), 0, + sizeof(handle->req.u.io.overlapped)); + if (!ReadDirectoryChangesW(handle->dir_handle, + handle->buffer, + uv_directory_watcher_buffer_size, + (handle->flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE, + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_SECURITY, + NULL, + &handle->req.u.io.overlapped, + NULL)) { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(&handle->req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)&handle->req); + } + + handle->req_pending = 1; +} + +static void uv_relative_path(const WCHAR* filename, + const WCHAR* dir, + WCHAR** relpath) { + size_t relpathlen; + size_t filenamelen = wcslen(filename); + size_t dirlen = wcslen(dir); + if (dirlen > 0 && dir[dirlen - 1] == '\\') + dirlen--; + relpathlen = filenamelen - dirlen - 1; + *relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR)); + if (!*relpath) + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + wcsncpy(*relpath, filename + dirlen + 1, relpathlen); + (*relpath)[relpathlen] = L'\0'; +} + +static int uv_split_path(const WCHAR* filename, WCHAR** dir, + WCHAR** file) { + int len = wcslen(filename); + int i = len; + while (i > 0 && filename[--i] != '\\' && filename[i] != '/'); + + if (i == 0) { + if (dir) { + *dir = (WCHAR*)uv__malloc((MAX_PATH + 1) * sizeof(WCHAR)); + if (!*dir) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (!GetCurrentDirectoryW(MAX_PATH, *dir)) { + uv__free(*dir); + *dir = NULL; + return -1; + } + } + + *file = wcsdup(filename); + } else { + if (dir) { + *dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR)); + if (!*dir) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + wcsncpy(*dir, filename, i + 1); + (*dir)[i + 1] = L'\0'; + } + + *file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR)); + if (!*file) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + wcsncpy(*file, filename + i + 1, len - i - 1); + (*file)[len - i - 1] = L'\0'; + } + + return 0; +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + uv__handle_init(loop, (uv_handle_t*) handle, UV_FS_EVENT); + handle->dir_handle = INVALID_HANDLE_VALUE; + handle->buffer = NULL; + handle->req_pending = 0; + handle->filew = NULL; + handle->short_filew = NULL; + handle->dirw = NULL; + + uv_req_init(loop, (uv_req_t*)&handle->req); + handle->req.type = UV_FS_EVENT_REQ; + handle->req.data = handle; + + return 0; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* path, + unsigned int flags) { + int name_size, is_path_dir; + DWORD attr, last_error; + WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL; + WCHAR short_path[MAX_PATH]; + + if (uv__is_active(handle)) + return UV_EINVAL; + + handle->cb = cb; + handle->path = uv__strdup(path); + if (!handle->path) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + uv__handle_start(handle); + + /* Convert name to UTF16. */ + + name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) * + sizeof(WCHAR); + pathw = (WCHAR*)uv__malloc(name_size); + if (!pathw) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + path, + -1, + pathw, + name_size / sizeof(WCHAR))) { + return uv_translate_sys_error(GetLastError()); + } + + /* Determine whether path is a file or a directory. */ + attr = GetFileAttributesW(pathw); + if (attr == INVALID_FILE_ATTRIBUTES) { + last_error = GetLastError(); + goto error; + } + + is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0; + + if (is_path_dir) { + /* path is a directory, so that's the directory that we will watch. */ + handle->dirw = pathw; + dir_to_watch = pathw; + } else { + /* + * path is a file. So we split path into dir & file parts, and + * watch the dir directory. + */ + + /* Convert to short path. */ + if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) { + last_error = GetLastError(); + goto error; + } + + if (uv_split_path(pathw, &dir, &handle->filew) != 0) { + last_error = GetLastError(); + goto error; + } + + if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) { + last_error = GetLastError(); + goto error; + } + + dir_to_watch = dir; + uv__free(pathw); + pathw = NULL; + } + + handle->dir_handle = CreateFileW(dir_to_watch, + FILE_LIST_DIRECTORY, + FILE_SHARE_READ | FILE_SHARE_DELETE | + FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OVERLAPPED, + NULL); + + if (dir) { + uv__free(dir); + dir = NULL; + } + + if (handle->dir_handle == INVALID_HANDLE_VALUE) { + last_error = GetLastError(); + goto error; + } + + if (CreateIoCompletionPort(handle->dir_handle, + handle->loop->iocp, + (ULONG_PTR)handle, + 0) == NULL) { + last_error = GetLastError(); + goto error; + } + + if (!handle->buffer) { + handle->buffer = (char*)uv__malloc(uv_directory_watcher_buffer_size); + } + if (!handle->buffer) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + memset(&(handle->req.u.io.overlapped), 0, + sizeof(handle->req.u.io.overlapped)); + + if (!ReadDirectoryChangesW(handle->dir_handle, + handle->buffer, + uv_directory_watcher_buffer_size, + (flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE, + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_SECURITY, + NULL, + &handle->req.u.io.overlapped, + NULL)) { + last_error = GetLastError(); + goto error; + } + + handle->req_pending = 1; + return 0; + +error: + if (handle->path) { + uv__free(handle->path); + handle->path = NULL; + } + + if (handle->filew) { + uv__free(handle->filew); + handle->filew = NULL; + } + + if (handle->short_filew) { + uv__free(handle->short_filew); + handle->short_filew = NULL; + } + + uv__free(pathw); + + if (handle->dir_handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle->dir_handle); + handle->dir_handle = INVALID_HANDLE_VALUE; + } + + if (handle->buffer) { + uv__free(handle->buffer); + handle->buffer = NULL; + } + + return uv_translate_sys_error(last_error); +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + if (!uv__is_active(handle)) + return 0; + + if (handle->dir_handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle->dir_handle); + handle->dir_handle = INVALID_HANDLE_VALUE; + } + + uv__handle_stop(handle); + + if (handle->filew) { + uv__free(handle->filew); + handle->filew = NULL; + } + + if (handle->short_filew) { + uv__free(handle->short_filew); + handle->short_filew = NULL; + } + + if (handle->path) { + uv__free(handle->path); + handle->path = NULL; + } + + if (handle->dirw) { + uv__free(handle->dirw); + handle->dirw = NULL; + } + + return 0; +} + + +static int file_info_cmp(WCHAR* str, WCHAR* file_name, int file_name_len) { + int str_len; + + str_len = wcslen(str); + + /* + Since we only care about equality, return early if the strings + aren't the same length + */ + if (str_len != (file_name_len / sizeof(WCHAR))) + return -1; + + return _wcsnicmp(str, file_name, str_len); +} + + +void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, + uv_fs_event_t* handle) { + FILE_NOTIFY_INFORMATION* file_info; + int err, sizew, size; + char* filename = NULL; + WCHAR* filenamew = NULL; + WCHAR* long_filenamew = NULL; + DWORD offset = 0; + + assert(req->type == UV_FS_EVENT_REQ); + assert(handle->req_pending); + handle->req_pending = 0; + + /* Don't report any callbacks if: + * - We're closing, just push the handle onto the endgame queue + * - We are not active, just ignore the callback + */ + if (!uv__is_active(handle)) { + if (handle->flags & UV__HANDLE_CLOSING) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + return; + } + + file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset); + + if (REQ_SUCCESS(req)) { + if (req->u.io.overlapped.InternalHigh > 0) { + do { + file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset); + assert(!filename); + assert(!filenamew); + assert(!long_filenamew); + + /* + * Fire the event only if we were asked to watch a directory, + * or if the filename filter matches. + */ + if (handle->dirw || + file_info_cmp(handle->filew, + file_info->FileName, + file_info->FileNameLength) == 0 || + file_info_cmp(handle->short_filew, + file_info->FileName, + file_info->FileNameLength) == 0) { + + if (handle->dirw) { + /* + * We attempt to resolve the long form of the file name explicitly. + * We only do this for file names that might still exist on disk. + * If this fails, we use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. + */ + if (file_info->Action != FILE_ACTION_REMOVED && + file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) { + /* Construct a full path to the file. */ + size = wcslen(handle->dirw) + + file_info->FileNameLength / sizeof(WCHAR) + 2; + + filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR)); + if (!filenamew) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + _snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw, + file_info->FileNameLength / (DWORD)sizeof(WCHAR), + file_info->FileName); + + filenamew[size - 1] = L'\0'; + + /* Convert to long name. */ + size = GetLongPathNameW(filenamew, NULL, 0); + + if (size) { + long_filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR)); + if (!long_filenamew) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + size = GetLongPathNameW(filenamew, long_filenamew, size); + if (size) { + long_filenamew[size] = '\0'; + } else { + uv__free(long_filenamew); + long_filenamew = NULL; + } + } + + uv__free(filenamew); + + if (long_filenamew) { + /* Get the file name out of the long path. */ + uv_relative_path(long_filenamew, + handle->dirw, + &filenamew); + uv__free(long_filenamew); + long_filenamew = filenamew; + sizew = -1; + } else { + /* We couldn't get the long filename, use the one reported. */ + filenamew = file_info->FileName; + sizew = file_info->FileNameLength / sizeof(WCHAR); + } + } else { + /* + * Removed or renamed events cannot be resolved to the long form. + * We therefore use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. + */ + filenamew = file_info->FileName; + sizew = file_info->FileNameLength / sizeof(WCHAR); + } + } else { + /* We already have the long name of the file, so just use it. */ + filenamew = handle->filew; + sizew = -1; + } + + /* Convert the filename to utf8. */ + uv__convert_utf16_to_utf8(filenamew, sizew, &filename); + + switch (file_info->Action) { + case FILE_ACTION_ADDED: + case FILE_ACTION_REMOVED: + case FILE_ACTION_RENAMED_OLD_NAME: + case FILE_ACTION_RENAMED_NEW_NAME: + handle->cb(handle, filename, UV_RENAME, 0); + break; + + case FILE_ACTION_MODIFIED: + handle->cb(handle, filename, UV_CHANGE, 0); + break; + } + + uv__free(filename); + filename = NULL; + uv__free(long_filenamew); + long_filenamew = NULL; + filenamew = NULL; + } + + offset = file_info->NextEntryOffset; + } while (offset && !(handle->flags & UV__HANDLE_CLOSING)); + } else { + handle->cb(handle, NULL, UV_CHANGE, 0); + } + } else { + err = GET_REQ_ERROR(req); + handle->cb(handle, NULL, 0, uv_translate_sys_error(err)); + } + + if (!(handle->flags & UV__HANDLE_CLOSING)) { + uv_fs_event_queue_readdirchanges(loop, handle); + } else { + uv_want_endgame(loop, (uv_handle_t*)handle); + } +} + + +void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) { + uv_fs_event_stop(handle); + + uv__handle_closing(handle); + + if (!handle->req_pending) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } + +} + + +void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) { + if ((handle->flags & UV__HANDLE_CLOSING) && !handle->req_pending) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + if (handle->buffer) { + uv__free(handle->buffer); + handle->buffer = NULL; + } + + uv__handle_close(handle); + } +} diff --git a/src/win/fs.c b/src/win/fs.c new file mode 100644 index 0000000..6a4157b --- /dev/null +++ b/src/win/fs.c @@ -0,0 +1,2491 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "req-inl.h" +#include "handle-inl.h" + +#include + + +#define UV_FS_FREE_PATHS 0x0002 +#define UV_FS_FREE_PTR 0x0008 +#define UV_FS_CLEANEDUP 0x0010 + + +#define QUEUE_FS_TP_JOB(loop, req) \ + do { \ + uv__req_register(loop, req); \ + uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \ + } while (0) + +#define SET_REQ_RESULT(req, result_value) \ + do { \ + req->result = (result_value); \ + if (req->result == -1) { \ + req->sys_errno_ = _doserrno; \ + req->result = uv_translate_sys_error(req->sys_errno_); \ + } \ + } while (0) + +#define SET_REQ_WIN32_ERROR(req, sys_errno) \ + do { \ + req->sys_errno_ = (sys_errno); \ + req->result = uv_translate_sys_error(req->sys_errno_); \ + } while (0) + +#define SET_REQ_UV_ERROR(req, uv_errno, sys_errno) \ + do { \ + req->result = (uv_errno); \ + req->sys_errno_ = (sys_errno); \ + } while (0) + +#define VERIFY_FD(fd, req) \ + if (fd == -1) { \ + req->result = UV_EBADF; \ + req->sys_errno_ = ERROR_INVALID_HANDLE; \ + return; \ + } + +#define FILETIME_TO_UINT(filetime) \ + (*((uint64_t*) &(filetime)) - 116444736000000000ULL) + +#define FILETIME_TO_TIME_T(filetime) \ + (FILETIME_TO_UINT(filetime) / 10000000ULL) + +#define FILETIME_TO_TIME_NS(filetime, secs) \ + ((FILETIME_TO_UINT(filetime) - (secs * 10000000ULL)) * 100) + +#define FILETIME_TO_TIMESPEC(ts, filetime) \ + do { \ + (ts).tv_sec = (long) FILETIME_TO_TIME_T(filetime); \ + (ts).tv_nsec = (long) FILETIME_TO_TIME_NS(filetime, (ts).tv_sec); \ + } while(0) + +#define TIME_T_TO_FILETIME(time, filetime_ptr) \ + do { \ + uint64_t bigtime = ((uint64_t) ((time) * 10000000ULL)) + \ + 116444736000000000ULL; \ + (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \ + (filetime_ptr)->dwHighDateTime = bigtime >> 32; \ + } while(0) + +#define IS_SLASH(c) ((c) == L'\\' || (c) == L'/') +#define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \ + ((c) >= L'A' && (c) <= L'Z')) + +const WCHAR JUNCTION_PREFIX[] = L"\\??\\"; +const WCHAR JUNCTION_PREFIX_LEN = 4; + +const WCHAR LONG_PATH_PREFIX[] = L"\\\\?\\"; +const WCHAR LONG_PATH_PREFIX_LEN = 4; + +const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\"; +const WCHAR UNC_PATH_PREFIX_LEN = 8; + + +void uv_fs_init() { + _fmode = _O_BINARY; +} + + +INLINE static int fs__capture_path(uv_fs_t* req, const char* path, + const char* new_path, const int copy_path) { + char* buf; + char* pos; + ssize_t buf_sz = 0, path_len, pathw_len = 0, new_pathw_len = 0; + + /* new_path can only be set if path is also set. */ + assert(new_path == NULL || path != NULL); + + if (path != NULL) { + pathw_len = MultiByteToWideChar(CP_UTF8, + 0, + path, + -1, + NULL, + 0); + if (pathw_len == 0) { + return GetLastError(); + } + + buf_sz += pathw_len * sizeof(WCHAR); + } + + if (path != NULL && copy_path) { + path_len = 1 + strlen(path); + buf_sz += path_len; + } + + if (new_path != NULL) { + new_pathw_len = MultiByteToWideChar(CP_UTF8, + 0, + new_path, + -1, + NULL, + 0); + if (new_pathw_len == 0) { + return GetLastError(); + } + + buf_sz += new_pathw_len * sizeof(WCHAR); + } + + + if (buf_sz == 0) { + req->file.pathw = NULL; + req->fs.info.new_pathw = NULL; + req->path = NULL; + return 0; + } + + buf = (char*) uv__malloc(buf_sz); + if (buf == NULL) { + return ERROR_OUTOFMEMORY; + } + + pos = buf; + + if (path != NULL) { + DWORD r = MultiByteToWideChar(CP_UTF8, + 0, + path, + -1, + (WCHAR*) pos, + pathw_len); + assert(r == (DWORD) pathw_len); + req->file.pathw = (WCHAR*) pos; + pos += r * sizeof(WCHAR); + } else { + req->file.pathw = NULL; + } + + if (new_path != NULL) { + DWORD r = MultiByteToWideChar(CP_UTF8, + 0, + new_path, + -1, + (WCHAR*) pos, + new_pathw_len); + assert(r == (DWORD) new_pathw_len); + req->fs.info.new_pathw = (WCHAR*) pos; + pos += r * sizeof(WCHAR); + } else { + req->fs.info.new_pathw = NULL; + } + + req->path = path; + if (path != NULL && copy_path) { + memcpy(pos, path, path_len); + assert(path_len == buf_sz - (pos - buf)); + req->path = pos; + } + + req->flags |= UV_FS_FREE_PATHS; + + return 0; +} + + + +INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, + uv_fs_type fs_type, const uv_fs_cb cb) { + uv_req_init(loop, (uv_req_t*) req); + + req->type = UV_FS; + req->loop = loop; + req->flags = 0; + req->fs_type = fs_type; + req->result = 0; + req->ptr = NULL; + req->path = NULL; + req->cb = cb; +} + + +static int fs__wide_to_utf8(WCHAR* w_source_ptr, + DWORD w_source_len, + char** target_ptr, + uint64_t* target_len_ptr) { + int r; + int target_len; + char* target; + target_len = WideCharToMultiByte(CP_UTF8, + 0, + w_source_ptr, + w_source_len, + NULL, + 0, + NULL, + NULL); + + if (target_len == 0) { + return -1; + } + + if (target_len_ptr != NULL) { + *target_len_ptr = target_len; + } + + if (target_ptr == NULL) { + return 0; + } + + target = uv__malloc(target_len + 1); + if (target == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return -1; + } + + r = WideCharToMultiByte(CP_UTF8, + 0, + w_source_ptr, + w_source_len, + target, + target_len, + NULL, + NULL); + assert(r == target_len); + target[target_len] = '\0'; + *target_ptr = target; + return 0; +} + + +INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, + uint64_t* target_len_ptr) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer; + WCHAR* w_target; + DWORD w_target_len; + DWORD bytes; + + if (!DeviceIoControl(handle, + FSCTL_GET_REPARSE_POINT, + NULL, + 0, + buffer, + sizeof buffer, + &bytes, + NULL)) { + return -1; + } + + if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + /* Real symlink */ + w_target = reparse_data->SymbolicLinkReparseBuffer.PathBuffer + + (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset / + sizeof(WCHAR)); + w_target_len = + reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / + sizeof(WCHAR); + + /* Real symlinks can contain pretty much everything, but the only thing */ + /* we really care about is undoing the implicit conversion to an NT */ + /* namespaced path that CreateSymbolicLink will perform on absolute */ + /* paths. If the path is win32-namespaced then the user must have */ + /* explicitly made it so, and we better just return the unmodified */ + /* reparse data. */ + if (w_target_len >= 4 && + w_target[0] == L'\\' && + w_target[1] == L'?' && + w_target[2] == L'?' && + w_target[3] == L'\\') { + /* Starts with \??\ */ + if (w_target_len >= 6 && + ((w_target[4] >= L'A' && w_target[4] <= L'Z') || + (w_target[4] >= L'a' && w_target[4] <= L'z')) && + w_target[5] == L':' && + (w_target_len == 6 || w_target[6] == L'\\')) { + /* \??\:\ */ + w_target += 4; + w_target_len -= 4; + + } else if (w_target_len >= 8 && + (w_target[4] == L'U' || w_target[4] == L'u') && + (w_target[5] == L'N' || w_target[5] == L'n') && + (w_target[6] == L'C' || w_target[6] == L'c') && + w_target[7] == L'\\') { + /* \??\UNC\\\ - make sure the final path looks like */ + /* \\\\ */ + w_target += 6; + w_target[0] = L'\\'; + w_target_len -= 6; + } + } + + } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + /* Junction. */ + w_target = reparse_data->MountPointReparseBuffer.PathBuffer + + (reparse_data->MountPointReparseBuffer.SubstituteNameOffset / + sizeof(WCHAR)); + w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength / + sizeof(WCHAR); + + /* Only treat junctions that look like \??\:\ as symlink. */ + /* Junctions can also be used as mount points, like \??\Volume{}, */ + /* but that's confusing for programs since they wouldn't be able to */ + /* actually understand such a path when returned by uv_readlink(). */ + /* UNC paths are never valid for junctions so we don't care about them. */ + if (!(w_target_len >= 6 && + w_target[0] == L'\\' && + w_target[1] == L'?' && + w_target[2] == L'?' && + w_target[3] == L'\\' && + ((w_target[4] >= L'A' && w_target[4] <= L'Z') || + (w_target[4] >= L'a' && w_target[4] <= L'z')) && + w_target[5] == L':' && + (w_target_len == 6 || w_target[6] == L'\\'))) { + SetLastError(ERROR_SYMLINK_NOT_SUPPORTED); + return -1; + } + + /* Remove leading \??\ */ + w_target += 4; + w_target_len -= 4; + + } else { + /* Reparse tag does not indicate a symlink. */ + SetLastError(ERROR_SYMLINK_NOT_SUPPORTED); + return -1; + } + + return fs__wide_to_utf8(w_target, w_target_len, target_ptr, target_len_ptr); +} + + +void fs__open(uv_fs_t* req) { + DWORD access; + DWORD share; + DWORD disposition; + DWORD attributes = 0; + HANDLE file; + int fd, current_umask; + int flags = req->fs.info.file_flags; + + /* Obtain the active umask. umask() never fails and returns the previous */ + /* umask. */ + current_umask = umask(0); + umask(current_umask); + + /* convert flags and mode to CreateFile parameters */ + switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { + case _O_RDONLY: + access = FILE_GENERIC_READ; + attributes |= FILE_FLAG_BACKUP_SEMANTICS; + break; + case _O_WRONLY: + access = FILE_GENERIC_WRITE; + break; + case _O_RDWR: + access = FILE_GENERIC_READ | FILE_GENERIC_WRITE; + break; + default: + goto einval; + } + + if (flags & _O_APPEND) { + access &= ~FILE_WRITE_DATA; + access |= FILE_APPEND_DATA; + attributes &= ~FILE_FLAG_BACKUP_SEMANTICS; + } + + /* + * Here is where we deviate significantly from what CRT's _open() + * does. We indiscriminately use all the sharing modes, to match + * UNIX semantics. In particular, this ensures that the file can + * be deleted even whilst it's open, fixing issue #1449. + */ + share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + + switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) { + case 0: + case _O_EXCL: + disposition = OPEN_EXISTING; + break; + case _O_CREAT: + disposition = OPEN_ALWAYS; + break; + case _O_CREAT | _O_EXCL: + case _O_CREAT | _O_TRUNC | _O_EXCL: + disposition = CREATE_NEW; + break; + case _O_TRUNC: + case _O_TRUNC | _O_EXCL: + disposition = TRUNCATE_EXISTING; + break; + case _O_CREAT | _O_TRUNC: + disposition = CREATE_ALWAYS; + break; + default: + goto einval; + } + + attributes |= FILE_ATTRIBUTE_NORMAL; + if (flags & _O_CREAT) { + if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) { + attributes |= FILE_ATTRIBUTE_READONLY; + } + } + + if (flags & _O_TEMPORARY ) { + attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY; + access |= DELETE; + } + + if (flags & _O_SHORT_LIVED) { + attributes |= FILE_ATTRIBUTE_TEMPORARY; + } + + switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) { + case 0: + break; + case _O_SEQUENTIAL: + attributes |= FILE_FLAG_SEQUENTIAL_SCAN; + break; + case _O_RANDOM: + attributes |= FILE_FLAG_RANDOM_ACCESS; + break; + default: + goto einval; + } + + /* Setting this flag makes it possible to open a directory. */ + attributes |= FILE_FLAG_BACKUP_SEMANTICS; + + file = CreateFileW(req->file.pathw, + access, + share, + NULL, + disposition, + attributes, + NULL); + if (file == INVALID_HANDLE_VALUE) { + DWORD error = GetLastError(); + if (error == ERROR_FILE_EXISTS && (flags & _O_CREAT) && + !(flags & _O_EXCL)) { + /* Special case: when ERROR_FILE_EXISTS happens and O_CREAT was */ + /* specified, it means the path referred to a directory. */ + SET_REQ_UV_ERROR(req, UV_EISDIR, error); + } else { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } + return; + } + + fd = _open_osfhandle((intptr_t) file, flags); + if (fd < 0) { + /* The only known failure mode for _open_osfhandle() is EMFILE, in which + * case GetLastError() will return zero. However we'll try to handle other + * errors as well, should they ever occur. + */ + if (errno == EMFILE) + SET_REQ_UV_ERROR(req, UV_EMFILE, ERROR_TOO_MANY_OPEN_FILES); + else if (GetLastError() != ERROR_SUCCESS) + SET_REQ_WIN32_ERROR(req, GetLastError()); + else + SET_REQ_WIN32_ERROR(req, UV_UNKNOWN); + CloseHandle(file); + return; + } + + SET_REQ_RESULT(req, fd); + return; + + einval: + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER); +} + +void fs__close(uv_fs_t* req) { + int fd = req->file.fd; + int result; + + VERIFY_FD(fd, req); + + if (fd > 2) + result = _close(fd); + else + result = 0; + + /* _close doesn't set _doserrno on failure, but it does always set errno + * to EBADF on failure. + */ + if (result == -1) { + assert(errno == EBADF); + SET_REQ_UV_ERROR(req, UV_EBADF, ERROR_INVALID_HANDLE); + } else { + req->result = 0; + } +} + + +void fs__read(uv_fs_t* req) { + int fd = req->file.fd; + int64_t offset = req->fs.info.offset; + HANDLE handle; + OVERLAPPED overlapped, *overlapped_ptr; + LARGE_INTEGER offset_; + DWORD bytes; + DWORD error; + int result; + unsigned int index; + + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); + return; + } + + if (offset != -1) { + memset(&overlapped, 0, sizeof overlapped); + overlapped_ptr = &overlapped; + } else { + overlapped_ptr = NULL; + } + + index = 0; + bytes = 0; + do { + DWORD incremental_bytes; + + if (offset != -1) { + offset_.QuadPart = offset + bytes; + overlapped.Offset = offset_.LowPart; + overlapped.OffsetHigh = offset_.HighPart; + } + + result = ReadFile(handle, + req->fs.info.bufs[index].base, + req->fs.info.bufs[index].len, + &incremental_bytes, + overlapped_ptr); + bytes += incremental_bytes; + ++index; + } while (result && index < req->fs.info.nbufs); + + if (result || bytes > 0) { + SET_REQ_RESULT(req, bytes); + } else { + error = GetLastError(); + if (error == ERROR_HANDLE_EOF) { + SET_REQ_RESULT(req, bytes); + } else { + SET_REQ_WIN32_ERROR(req, error); + } + } +} + + +void fs__write(uv_fs_t* req) { + int fd = req->file.fd; + int64_t offset = req->fs.info.offset; + HANDLE handle; + OVERLAPPED overlapped, *overlapped_ptr; + LARGE_INTEGER offset_; + DWORD bytes; + int result; + unsigned int index; + + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); + return; + } + + if (offset != -1) { + memset(&overlapped, 0, sizeof overlapped); + overlapped_ptr = &overlapped; + } else { + overlapped_ptr = NULL; + } + + index = 0; + bytes = 0; + do { + DWORD incremental_bytes; + + if (offset != -1) { + offset_.QuadPart = offset + bytes; + overlapped.Offset = offset_.LowPart; + overlapped.OffsetHigh = offset_.HighPart; + } + + result = WriteFile(handle, + req->fs.info.bufs[index].base, + req->fs.info.bufs[index].len, + &incremental_bytes, + overlapped_ptr); + bytes += incremental_bytes; + ++index; + } while (result && index < req->fs.info.nbufs); + + if (result || bytes > 0) { + SET_REQ_RESULT(req, bytes); + } else { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } +} + + +void fs__rmdir(uv_fs_t* req) { + int result = _wrmdir(req->file.pathw); + SET_REQ_RESULT(req, result); +} + + +void fs__unlink(uv_fs_t* req) { + const WCHAR* pathw = req->file.pathw; + HANDLE handle; + BY_HANDLE_FILE_INFORMATION info; + FILE_DISPOSITION_INFORMATION disposition; + IO_STATUS_BLOCK iosb; + NTSTATUS status; + + handle = CreateFileW(pathw, + FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (!GetFileInformationByHandle(handle, &info)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); + return; + } + + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + /* Do not allow deletion of directories, unless it is a symlink. When */ + /* the path refers to a non-symlink directory, report EPERM as mandated */ + /* by POSIX.1. */ + + /* Check if it is a reparse point. If it's not, it's a normal directory. */ + if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { + SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED); + CloseHandle(handle); + return; + } + + /* Read the reparse point and check if it is a valid symlink. */ + /* If not, don't unlink. */ + if (fs__readlink_handle(handle, NULL, NULL) < 0) { + DWORD error = GetLastError(); + if (error == ERROR_SYMLINK_NOT_SUPPORTED) + error = ERROR_ACCESS_DENIED; + SET_REQ_WIN32_ERROR(req, error); + CloseHandle(handle); + return; + } + } + + if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + /* Remove read-only attribute */ + FILE_BASIC_INFORMATION basic = { 0 }; + + basic.FileAttributes = info.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY); + + status = pNtSetInformationFile(handle, + &iosb, + &basic, + sizeof basic, + FileBasicInformation); + if (!NT_SUCCESS(status)) { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + CloseHandle(handle); + return; + } + } + + /* Try to set the delete flag. */ + disposition.DeleteFile = TRUE; + status = pNtSetInformationFile(handle, + &iosb, + &disposition, + sizeof disposition, + FileDispositionInformation); + if (NT_SUCCESS(status)) { + SET_REQ_SUCCESS(req); + } else { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + } + + CloseHandle(handle); +} + + +void fs__mkdir(uv_fs_t* req) { + /* TODO: use req->mode. */ + int result = _wmkdir(req->file.pathw); + SET_REQ_RESULT(req, result); +} + + +/* OpenBSD original: lib/libc/stdio/mktemp.c */ +void fs__mkdtemp(uv_fs_t* req) { + static const WCHAR *tempchars = + L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + static const size_t num_chars = 62; + static const size_t num_x = 6; + WCHAR *cp, *ep; + unsigned int tries, i; + size_t len; + HCRYPTPROV h_crypt_prov; + uint64_t v; + BOOL released; + + len = wcslen(req->file.pathw); + ep = req->file.pathw + len; + if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) { + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER); + return; + } + + if (!CryptAcquireContext(&h_crypt_prov, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + tries = TMP_MAX; + do { + if (!CryptGenRandom(h_crypt_prov, sizeof(v), (BYTE*) &v)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + break; + } + + cp = ep - num_x; + for (i = 0; i < num_x; i++) { + *cp++ = tempchars[v % num_chars]; + v /= num_chars; + } + + if (_wmkdir(req->file.pathw) == 0) { + len = strlen(req->path); + wcstombs((char*) req->path + len - num_x, ep - num_x, num_x); + SET_REQ_RESULT(req, 0); + break; + } else if (errno != EEXIST) { + SET_REQ_RESULT(req, -1); + break; + } + } while (--tries); + + released = CryptReleaseContext(h_crypt_prov, 0); + assert(released); + if (tries == 0) { + SET_REQ_RESULT(req, -1); + } +} + + +void fs__scandir(uv_fs_t* req) { + static const size_t dirents_initial_size = 32; + + HANDLE dir_handle = INVALID_HANDLE_VALUE; + + uv__dirent_t** dirents = NULL; + size_t dirents_size = 0; + size_t dirents_used = 0; + + IO_STATUS_BLOCK iosb; + NTSTATUS status; + + /* Buffer to hold directory entries returned by NtQueryDirectoryFile. + * It's important that this buffer can hold at least one entry, regardless + * of the length of the file names present in the enumerated directory. + * A file name is at most 256 WCHARs long. + * According to MSDN, the buffer must be aligned at an 8-byte boundary. + */ +#if _MSC_VER + __declspec(align(8)) char buffer[8192]; +#else + __attribute__ ((aligned (8))) char buffer[8192]; +#endif + + STATIC_ASSERT(sizeof buffer >= + sizeof(FILE_DIRECTORY_INFORMATION) + 256 * sizeof(WCHAR)); + + /* Open the directory. */ + dir_handle = + CreateFileW(req->file.pathw, + FILE_LIST_DIRECTORY | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (dir_handle == INVALID_HANDLE_VALUE) + goto win32_error; + + /* Read the first chunk. */ + status = pNtQueryDirectoryFile(dir_handle, + NULL, + NULL, + NULL, + &iosb, + &buffer, + sizeof buffer, + FileDirectoryInformation, + FALSE, + NULL, + TRUE); + + /* If the handle is not a directory, we'll get STATUS_INVALID_PARAMETER. + * This should be reported back as UV_ENOTDIR. + */ + if (status == STATUS_INVALID_PARAMETER) + goto not_a_directory_error; + + while (NT_SUCCESS(status)) { + char* position = buffer; + size_t next_entry_offset = 0; + + do { + FILE_DIRECTORY_INFORMATION* info; + uv__dirent_t* dirent; + + size_t wchar_len; + size_t utf8_len; + + /* Obtain a pointer to the current directory entry. */ + position += next_entry_offset; + info = (FILE_DIRECTORY_INFORMATION*) position; + + /* Fetch the offset to the next directory entry. */ + next_entry_offset = info->NextEntryOffset; + + /* Compute the length of the filename in WCHARs. */ + wchar_len = info->FileNameLength / sizeof info->FileName[0]; + + /* Skip over '.' and '..' entries. It has been reported that + * the SharePoint driver includes the terminating zero byte in + * the filename length. Strip those first. + */ + while (wchar_len > 0 && info->FileName[wchar_len - 1] == L'\0') + wchar_len -= 1; + + if (wchar_len == 0) + continue; + if (wchar_len == 1 && info->FileName[0] == L'.') + continue; + if (wchar_len == 2 && info->FileName[0] == L'.' && + info->FileName[1] == L'.') + continue; + + /* Compute the space required to store the filename as UTF-8. */ + utf8_len = WideCharToMultiByte( + CP_UTF8, 0, &info->FileName[0], wchar_len, NULL, 0, NULL, NULL); + if (utf8_len == 0) + goto win32_error; + + /* Resize the dirent array if needed. */ + if (dirents_used >= dirents_size) { + size_t new_dirents_size = + dirents_size == 0 ? dirents_initial_size : dirents_size << 1; + uv__dirent_t** new_dirents = + uv__realloc(dirents, new_dirents_size * sizeof *dirents); + + if (new_dirents == NULL) + goto out_of_memory_error; + + dirents_size = new_dirents_size; + dirents = new_dirents; + } + + /* Allocate space for the uv dirent structure. The dirent structure + * includes room for the first character of the filename, but `utf8_len` + * doesn't count the NULL terminator at this point. + */ + dirent = uv__malloc(sizeof *dirent + utf8_len); + if (dirent == NULL) + goto out_of_memory_error; + + dirents[dirents_used++] = dirent; + + /* Convert file name to UTF-8. */ + if (WideCharToMultiByte(CP_UTF8, + 0, + &info->FileName[0], + wchar_len, + &dirent->d_name[0], + utf8_len, + NULL, + NULL) == 0) + goto win32_error; + + /* Add a null terminator to the filename. */ + dirent->d_name[utf8_len] = '\0'; + + /* Fill out the type field. */ + if (info->FileAttributes & FILE_ATTRIBUTE_DEVICE) + dirent->d_type = UV__DT_CHAR; + else if (info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + dirent->d_type = UV__DT_LINK; + else if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + dirent->d_type = UV__DT_DIR; + else + dirent->d_type = UV__DT_FILE; + } while (next_entry_offset != 0); + + /* Read the next chunk. */ + status = pNtQueryDirectoryFile(dir_handle, + NULL, + NULL, + NULL, + &iosb, + &buffer, + sizeof buffer, + FileDirectoryInformation, + FALSE, + NULL, + FALSE); + + /* After the first pNtQueryDirectoryFile call, the function may return + * STATUS_SUCCESS even if the buffer was too small to hold at least one + * directory entry. + */ + if (status == STATUS_SUCCESS && iosb.Information == 0) + status = STATUS_BUFFER_OVERFLOW; + } + + if (status != STATUS_NO_MORE_FILES) + goto nt_error; + + CloseHandle(dir_handle); + + /* Store the result in the request object. */ + req->ptr = dirents; + if (dirents != NULL) + req->flags |= UV_FS_FREE_PTR; + + SET_REQ_RESULT(req, dirents_used); + + /* `nbufs` will be used as index by uv_fs_scandir_next. */ + req->fs.info.nbufs = 0; + + return; + +nt_error: + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + goto cleanup; + +win32_error: + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto cleanup; + +not_a_directory_error: + SET_REQ_UV_ERROR(req, UV_ENOTDIR, ERROR_DIRECTORY); + goto cleanup; + +out_of_memory_error: + SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); + goto cleanup; + +cleanup: + if (dir_handle != INVALID_HANDLE_VALUE) + CloseHandle(dir_handle); + while (dirents_used > 0) + uv__free(dirents[--dirents_used]); + if (dirents != NULL) + uv__free(dirents); +} + + +INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) { + FILE_ALL_INFORMATION file_info; + FILE_FS_VOLUME_INFORMATION volume_info; + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + + nt_status = pNtQueryInformationFile(handle, + &io_status, + &file_info, + sizeof file_info, + FileAllInformation); + + /* Buffer overflow (a warning status code) is expected here. */ + if (NT_ERROR(nt_status)) { + SetLastError(pRtlNtStatusToDosError(nt_status)); + return -1; + } + + nt_status = pNtQueryVolumeInformationFile(handle, + &io_status, + &volume_info, + sizeof volume_info, + FileFsVolumeInformation); + + /* Buffer overflow (a warning status code) is expected here. */ + if (io_status.Status == STATUS_NOT_IMPLEMENTED) { + statbuf->st_dev = 0; + } else if (NT_ERROR(nt_status)) { + SetLastError(pRtlNtStatusToDosError(nt_status)); + return -1; + } else { + statbuf->st_dev = volume_info.VolumeSerialNumber; + } + + /* Todo: st_mode should probably always be 0666 for everyone. We might also + * want to report 0777 if the file is a .exe or a directory. + * + * Currently it's based on whether the 'readonly' attribute is set, which + * makes little sense because the semantics are so different: the 'read-only' + * flag is just a way for a user to protect against accidental deletion, and + * serves no security purpose. Windows uses ACLs for that. + * + * Also people now use uv_fs_chmod() to take away the writable bit for good + * reasons. Windows however just makes the file read-only, which makes it + * impossible to delete the file afterwards, since read-only files can't be + * deleted. + * + * IOW it's all just a clusterfuck and we should think of something that + * makes slightly more sense. + * + * And uv_fs_chmod should probably just fail on windows or be a total no-op. + * There's nothing sensible it can do anyway. + */ + statbuf->st_mode = 0; + + if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + /* + * It is possible for a file to have FILE_ATTRIBUTE_REPARSE_POINT but not have + * any link data. In that case DeviceIoControl() in fs__readlink_handle() sets + * the last error to ERROR_NOT_A_REPARSE_POINT. Then the stat result mode + * calculated below will indicate a normal directory or file, as if + * FILE_ATTRIBUTE_REPARSE_POINT was not present. + */ + if (fs__readlink_handle(handle, NULL, &statbuf->st_size) == 0) { + statbuf->st_mode |= S_IFLNK; + } else if (GetLastError() != ERROR_NOT_A_REPARSE_POINT) { + return -1; + } + } + + if (statbuf->st_mode == 0) { + if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + statbuf->st_mode |= _S_IFDIR; + statbuf->st_size = 0; + } else { + statbuf->st_mode |= _S_IFREG; + statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart; + } + } + + if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY) + statbuf->st_mode |= _S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6); + else + statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) | + ((_S_IREAD | _S_IWRITE) >> 6); + + FILETIME_TO_TIMESPEC(statbuf->st_atim, file_info.BasicInformation.LastAccessTime); + FILETIME_TO_TIMESPEC(statbuf->st_ctim, file_info.BasicInformation.ChangeTime); + FILETIME_TO_TIMESPEC(statbuf->st_mtim, file_info.BasicInformation.LastWriteTime); + FILETIME_TO_TIMESPEC(statbuf->st_birthtim, file_info.BasicInformation.CreationTime); + + statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart; + + /* st_blocks contains the on-disk allocation size in 512-byte units. */ + statbuf->st_blocks = + file_info.StandardInformation.AllocationSize.QuadPart >> 9ULL; + + statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks; + + /* The st_blksize is supposed to be the 'optimal' number of bytes for reading + * and writing to the disk. That is, for any definition of 'optimal' - it's + * supposed to at least avoid read-update-write behavior when writing to the + * disk. + * + * However nobody knows this and even fewer people actually use this value, + * and in order to fill it out we'd have to make another syscall to query the + * volume for FILE_FS_SECTOR_SIZE_INFORMATION. + * + * Therefore we'll just report a sensible value that's quite commonly okay + * on modern hardware. + */ + statbuf->st_blksize = 2048; + + /* Todo: set st_flags to something meaningful. Also provide a wrapper for + * chattr(2). + */ + statbuf->st_flags = 0; + + /* Windows has nothing sensible to say about these values, so they'll just + * remain empty. + */ + statbuf->st_gid = 0; + statbuf->st_uid = 0; + statbuf->st_rdev = 0; + statbuf->st_gen = 0; + + return 0; +} + + +INLINE static void fs__stat_prepare_path(WCHAR* pathw) { + size_t len = wcslen(pathw); + + /* TODO: ignore namespaced paths. */ + if (len > 1 && pathw[len - 2] != L':' && + (pathw[len - 1] == L'\\' || pathw[len - 1] == L'/')) { + pathw[len - 1] = '\0'; + } +} + + +INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) { + HANDLE handle; + DWORD flags; + + flags = FILE_FLAG_BACKUP_SEMANTICS; + if (do_lstat) { + flags |= FILE_FLAG_OPEN_REPARSE_POINT; + } + + handle = CreateFileW(req->file.pathw, + FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + flags, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (fs__stat_handle(handle, &req->statbuf) != 0) { + DWORD error = GetLastError(); + if (do_lstat && error == ERROR_SYMLINK_NOT_SUPPORTED) { + /* We opened a reparse point but it was not a symlink. Try again. */ + fs__stat_impl(req, 0); + + } else { + /* Stat failed. */ + SET_REQ_WIN32_ERROR(req, GetLastError()); + } + + CloseHandle(handle); + return; + } + + req->ptr = &req->statbuf; + req->result = 0; + CloseHandle(handle); +} + + +static void fs__stat(uv_fs_t* req) { + fs__stat_prepare_path(req->file.pathw); + fs__stat_impl(req, 0); +} + + +static void fs__lstat(uv_fs_t* req) { + fs__stat_prepare_path(req->file.pathw); + fs__stat_impl(req, 1); +} + + +static void fs__fstat(uv_fs_t* req) { + int fd = req->file.fd; + HANDLE handle; + + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); + return; + } + + if (fs__stat_handle(handle, &req->statbuf) != 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + req->ptr = &req->statbuf; + req->result = 0; +} + + +static void fs__rename(uv_fs_t* req) { + if (!MoveFileExW(req->file.pathw, req->fs.info.new_pathw, MOVEFILE_REPLACE_EXISTING)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + SET_REQ_RESULT(req, 0); +} + + +INLINE static void fs__sync_impl(uv_fs_t* req) { + int fd = req->file.fd; + int result; + + VERIFY_FD(fd, req); + + result = FlushFileBuffers(uv__get_osfhandle(fd)) ? 0 : -1; + if (result == -1) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } else { + SET_REQ_RESULT(req, result); + } +} + + +static void fs__fsync(uv_fs_t* req) { + fs__sync_impl(req); +} + + +static void fs__fdatasync(uv_fs_t* req) { + fs__sync_impl(req); +} + + +static void fs__ftruncate(uv_fs_t* req) { + int fd = req->file.fd; + HANDLE handle; + NTSTATUS status; + IO_STATUS_BLOCK io_status; + FILE_END_OF_FILE_INFORMATION eof_info; + + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + + eof_info.EndOfFile.QuadPart = req->fs.info.offset; + + status = pNtSetInformationFile(handle, + &io_status, + &eof_info, + sizeof eof_info, + FileEndOfFileInformation); + + if (NT_SUCCESS(status)) { + SET_REQ_RESULT(req, 0); + } else { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + } +} + + +static void fs__sendfile(uv_fs_t* req) { + int fd_in = req->file.fd, fd_out = req->fs.info.fd_out; + size_t length = req->fs.info.bufsml[0].len; + int64_t offset = req->fs.info.offset; + const size_t max_buf_size = 65536; + size_t buf_size = length < max_buf_size ? length : max_buf_size; + int n, result = 0; + int64_t result_offset = 0; + char* buf = (char*) uv__malloc(buf_size); + if (!buf) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (offset != -1) { + result_offset = _lseeki64(fd_in, offset, SEEK_SET); + } + + if (result_offset == -1) { + result = -1; + } else { + while (length > 0) { + n = _read(fd_in, buf, length < buf_size ? length : buf_size); + if (n == 0) { + break; + } else if (n == -1) { + result = -1; + break; + } + + length -= n; + + n = _write(fd_out, buf, n); + if (n == -1) { + result = -1; + break; + } + + result += n; + } + } + + uv__free(buf); + + SET_REQ_RESULT(req, result); +} + + +static void fs__access(uv_fs_t* req) { + DWORD attr = GetFileAttributesW(req->file.pathw); + + if (attr == INVALID_FILE_ATTRIBUTES) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + /* + * Access is possible if + * - write access wasn't requested, + * - or the file isn't read-only, + * - or it's a directory. + * (Directories cannot be read-only on Windows.) + */ + if (!(req->flags & W_OK) || + !(attr & FILE_ATTRIBUTE_READONLY) || + (attr & FILE_ATTRIBUTE_DIRECTORY)) { + SET_REQ_RESULT(req, 0); + } else { + SET_REQ_WIN32_ERROR(req, UV_EPERM); + } + +} + + +static void fs__chmod(uv_fs_t* req) { + int result = _wchmod(req->file.pathw, req->fs.info.mode); + SET_REQ_RESULT(req, result); +} + + +static void fs__fchmod(uv_fs_t* req) { + int fd = req->file.fd; + HANDLE handle; + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_BASIC_INFORMATION file_info; + + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + + nt_status = pNtQueryInformationFile(handle, + &io_status, + &file_info, + sizeof file_info, + FileBasicInformation); + + if (!NT_SUCCESS(nt_status)) { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); + return; + } + + if (req->fs.info.mode & _S_IWRITE) { + file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; + } else { + file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; + } + + nt_status = pNtSetInformationFile(handle, + &io_status, + &file_info, + sizeof file_info, + FileBasicInformation); + + if (!NT_SUCCESS(nt_status)) { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); + return; + } + + SET_REQ_SUCCESS(req); +} + + +INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) { + FILETIME filetime_a, filetime_m; + + TIME_T_TO_FILETIME(atime, &filetime_a); + TIME_T_TO_FILETIME(mtime, &filetime_m); + + if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) { + return -1; + } + + return 0; +} + + +static void fs__utime(uv_fs_t* req) { + HANDLE handle; + + handle = CreateFileW(req->file.pathw, + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); + return; + } + + CloseHandle(handle); + + req->result = 0; +} + + +static void fs__futime(uv_fs_t* req) { + int fd = req->file.fd; + HANDLE handle; + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); + return; + } + + if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + req->result = 0; +} + + +static void fs__link(uv_fs_t* req) { + DWORD r = CreateHardLinkW(req->fs.info.new_pathw, req->file.pathw, NULL); + if (r == 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } else { + req->result = 0; + } +} + + +static void fs__create_junction(uv_fs_t* req, const WCHAR* path, + const WCHAR* new_path) { + HANDLE handle = INVALID_HANDLE_VALUE; + REPARSE_DATA_BUFFER *buffer = NULL; + int created = 0; + int target_len; + int is_absolute, is_long_path; + int needed_buf_size, used_buf_size, used_data_size, path_buf_len; + int start, len, i; + int add_slash; + DWORD bytes; + WCHAR* path_buf; + + target_len = wcslen(path); + is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0; + + if (is_long_path) { + is_absolute = 1; + } else { + is_absolute = target_len >= 3 && IS_LETTER(path[0]) && + path[1] == L':' && IS_SLASH(path[2]); + } + + if (!is_absolute) { + /* Not supporting relative paths */ + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_NOT_SUPPORTED); + return; + } + + /* Do a pessimistic calculation of the required buffer size */ + needed_buf_size = + FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) + + JUNCTION_PREFIX_LEN * sizeof(WCHAR) + + 2 * (target_len + 2) * sizeof(WCHAR); + + /* Allocate the buffer */ + buffer = (REPARSE_DATA_BUFFER*)uv__malloc(needed_buf_size); + if (!buffer) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + /* Grab a pointer to the part of the buffer where filenames go */ + path_buf = (WCHAR*)&(buffer->MountPointReparseBuffer.PathBuffer); + path_buf_len = 0; + + /* Copy the substitute (internal) target path */ + start = path_buf_len; + + wcsncpy((WCHAR*)&path_buf[path_buf_len], JUNCTION_PREFIX, + JUNCTION_PREFIX_LEN); + path_buf_len += JUNCTION_PREFIX_LEN; + + add_slash = 0; + for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) { + if (IS_SLASH(path[i])) { + add_slash = 1; + continue; + } + + if (add_slash) { + path_buf[path_buf_len++] = L'\\'; + add_slash = 0; + } + + path_buf[path_buf_len++] = path[i]; + } + path_buf[path_buf_len++] = L'\\'; + len = path_buf_len - start; + + /* Set the info about the substitute name */ + buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(WCHAR); + buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR); + + /* Insert null terminator */ + path_buf[path_buf_len++] = L'\0'; + + /* Copy the print name of the target path */ + start = path_buf_len; + add_slash = 0; + for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) { + if (IS_SLASH(path[i])) { + add_slash = 1; + continue; + } + + if (add_slash) { + path_buf[path_buf_len++] = L'\\'; + add_slash = 0; + } + + path_buf[path_buf_len++] = path[i]; + } + len = path_buf_len - start; + if (len == 2) { + path_buf[path_buf_len++] = L'\\'; + len++; + } + + /* Set the info about the print name */ + buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(WCHAR); + buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(WCHAR); + + /* Insert another null terminator */ + path_buf[path_buf_len++] = L'\0'; + + /* Calculate how much buffer space was actually used */ + used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) + + path_buf_len * sizeof(WCHAR); + used_data_size = used_buf_size - + FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer); + + /* Put general info in the data buffer */ + buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + buffer->ReparseDataLength = used_data_size; + buffer->Reserved = 0; + + /* Create a new directory */ + if (!CreateDirectoryW(new_path, NULL)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + created = 1; + + /* Open the directory */ + handle = CreateFileW(new_path, + GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + + /* Create the actual reparse point */ + if (!DeviceIoControl(handle, + FSCTL_SET_REPARSE_POINT, + buffer, + used_buf_size, + NULL, + 0, + &bytes, + NULL)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + + /* Clean up */ + CloseHandle(handle); + uv__free(buffer); + + SET_REQ_RESULT(req, 0); + return; + +error: + uv__free(buffer); + + if (handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle); + } + + if (created) { + RemoveDirectoryW(new_path); + } +} + + +static void fs__symlink(uv_fs_t* req) { + WCHAR* pathw = req->file.pathw; + WCHAR* new_pathw = req->fs.info.new_pathw; + int flags = req->fs.info.file_flags; + int result; + + + if (flags & UV_FS_SYMLINK_JUNCTION) { + fs__create_junction(req, pathw, new_pathw); + } else if (pCreateSymbolicLinkW) { + result = pCreateSymbolicLinkW(new_pathw, + pathw, + flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1; + if (result == -1) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } else { + SET_REQ_RESULT(req, result); + } + } else { + SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); + } +} + + +static void fs__readlink(uv_fs_t* req) { + HANDLE handle; + + handle = CreateFileW(req->file.pathw, + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); + return; + } + + req->flags |= UV_FS_FREE_PTR; + SET_REQ_RESULT(req, 0); + + CloseHandle(handle); +} + + +static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { + int r; + DWORD w_realpath_len; + WCHAR* w_realpath_ptr = NULL; + WCHAR* w_realpath_buf; + + w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); + if (w_realpath_len == 0) { + return -1; + } + + w_realpath_buf = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR)); + if (w_realpath_buf == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return -1; + } + w_realpath_ptr = w_realpath_buf; + + if (pGetFinalPathNameByHandleW(handle, + w_realpath_ptr, + w_realpath_len, + VOLUME_NAME_DOS) == 0) { + uv__free(w_realpath_buf); + SetLastError(ERROR_INVALID_HANDLE); + return -1; + } + + /* convert UNC path to long path */ + if (wcsncmp(w_realpath_ptr, + UNC_PATH_PREFIX, + UNC_PATH_PREFIX_LEN) == 0) { + w_realpath_ptr += 6; + *w_realpath_ptr = L'\\'; + w_realpath_len -= 6; + } else if (wcsncmp(w_realpath_ptr, + LONG_PATH_PREFIX, + LONG_PATH_PREFIX_LEN) == 0) { + w_realpath_ptr += 4; + w_realpath_len -= 4; + } else { + uv__free(w_realpath_buf); + SetLastError(ERROR_INVALID_HANDLE); + return -1; + } + + r = fs__wide_to_utf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL); + uv__free(w_realpath_buf); + return r; +} + +static void fs__realpath(uv_fs_t* req) { + HANDLE handle; + + if (!pGetFinalPathNameByHandleW) { + SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); + return; + } + + handle = CreateFileW(req->file.pathw, + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (fs__realpath_handle(handle, (char**) &req->ptr) == -1) { + CloseHandle(handle); + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + CloseHandle(handle); + req->flags |= UV_FS_FREE_PTR; + SET_REQ_RESULT(req, 0); +} + + +static void fs__chown(uv_fs_t* req) { + req->result = 0; +} + + +static void fs__fchown(uv_fs_t* req) { + req->result = 0; +} + + +static void uv__fs_work(struct uv__work* w) { + uv_fs_t* req; + + req = container_of(w, uv_fs_t, work_req); + assert(req->type == UV_FS); + +#define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break; + switch (req->fs_type) { + XX(OPEN, open) + XX(CLOSE, close) + XX(READ, read) + XX(WRITE, write) + XX(SENDFILE, sendfile) + XX(STAT, stat) + XX(LSTAT, lstat) + XX(FSTAT, fstat) + XX(FTRUNCATE, ftruncate) + XX(UTIME, utime) + XX(FUTIME, futime) + XX(ACCESS, access) + XX(CHMOD, chmod) + XX(FCHMOD, fchmod) + XX(FSYNC, fsync) + XX(FDATASYNC, fdatasync) + XX(UNLINK, unlink) + XX(RMDIR, rmdir) + XX(MKDIR, mkdir) + XX(MKDTEMP, mkdtemp) + XX(RENAME, rename) + XX(SCANDIR, scandir) + XX(LINK, link) + XX(SYMLINK, symlink) + XX(READLINK, readlink) + XX(REALPATH, realpath) + XX(CHOWN, chown) + XX(FCHOWN, fchown); + default: + assert(!"bad uv_fs_type"); + } +} + + +static void uv__fs_done(struct uv__work* w, int status) { + uv_fs_t* req; + + req = container_of(w, uv_fs_t, work_req); + uv__req_unregister(req->loop, req); + + if (status == UV_ECANCELED) { + assert(req->result == 0); + req->result = UV_ECANCELED; + } + + req->cb(req); +} + + +void uv_fs_req_cleanup(uv_fs_t* req) { + if (req->flags & UV_FS_CLEANEDUP) + return; + + if (req->flags & UV_FS_FREE_PATHS) + uv__free(req->file.pathw); + + if (req->flags & UV_FS_FREE_PTR) { + if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL) + uv__fs_scandir_cleanup(req); + else + uv__free(req->ptr); + } + + req->path = NULL; + req->file.pathw = NULL; + req->fs.info.new_pathw = NULL; + req->ptr = NULL; + + req->flags |= UV_FS_CLEANEDUP; +} + + +int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, + int mode, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_OPEN, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.file_flags = flags; + req->fs.info.mode = mode; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__open(req); + return req->result; + } +} + + +int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_CLOSE, cb); + req->file.fd = fd; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__close(req); + return req->result; + } +} + + +int uv_fs_read(uv_loop_t* loop, + uv_fs_t* req, + uv_file fd, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t offset, + uv_fs_cb cb) { + if (bufs == NULL || nbufs == 0) + return UV_EINVAL; + + uv_fs_req_init(loop, req, UV_FS_READ, cb); + + req->file.fd = fd; + + req->fs.info.nbufs = nbufs; + req->fs.info.bufs = req->fs.info.bufsml; + if (nbufs > ARRAY_SIZE(req->fs.info.bufsml)) + req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs)); + + if (req->fs.info.bufs == NULL) + return UV_ENOMEM; + + memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs)); + + req->fs.info.offset = offset; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__read(req); + return req->result; + } +} + + +int uv_fs_write(uv_loop_t* loop, + uv_fs_t* req, + uv_file fd, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t offset, + uv_fs_cb cb) { + if (bufs == NULL || nbufs == 0) + return UV_EINVAL; + + uv_fs_req_init(loop, req, UV_FS_WRITE, cb); + + req->file.fd = fd; + + req->fs.info.nbufs = nbufs; + req->fs.info.bufs = req->fs.info.bufsml; + if (nbufs > ARRAY_SIZE(req->fs.info.bufsml)) + req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs)); + + if (req->fs.info.bufs == NULL) + return UV_ENOMEM; + + memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs)); + + req->fs.info.offset = offset; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__write(req); + return req->result; + } +} + + +int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_UNLINK, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__unlink(req); + return req->result; + } +} + + +int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_MKDIR, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.mode = mode; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__mkdir(req); + return req->result; + } +} + + +int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_MKDTEMP, cb); + + err = fs__capture_path(req, tpl, NULL, TRUE); + if (err) + return uv_translate_sys_error(err); + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__mkdtemp(req); + return req->result; + } +} + + +int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_RMDIR, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__rmdir(req); + return req->result; + } +} + + +int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_SCANDIR, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.file_flags = flags; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__scandir(req); + return req->result; + } +} + + +int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, + const char* new_path, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_LINK, cb); + + err = fs__capture_path(req, path, new_path, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__link(req); + return req->result; + } +} + + +int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + const char* new_path, int flags, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_SYMLINK, cb); + + err = fs__capture_path(req, path, new_path, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.file_flags = flags; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__symlink(req); + return req->result; + } +} + + +int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_READLINK, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__readlink(req); + return req->result; + } +} + + +int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + if (!req || !path) { + return UV_EINVAL; + } + + uv_fs_req_init(loop, req, UV_FS_REALPATH, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__realpath(req); + return req->result; + } +} + + +int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, + uv_gid_t gid, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_CHOWN, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__chown(req); + return req->result; + } +} + + +int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid, + uv_gid_t gid, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FCHOWN, cb); + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__fchown(req); + return req->result; + } +} + + +int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_STAT, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__stat(req); + return req->result; + } +} + + +int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_LSTAT, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__lstat(req); + return req->result; + } +} + + +int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FSTAT, cb); + req->file.fd = fd; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__fstat(req); + return req->result; + } +} + + +int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, + const char* new_path, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_RENAME, cb); + + err = fs__capture_path(req, path, new_path, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__rename(req); + return req->result; + } +} + + +int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FSYNC, cb); + req->file.fd = fd; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__fsync(req); + return req->result; + } +} + + +int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FDATASYNC, cb); + req->file.fd = fd; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__fdatasync(req); + return req->result; + } +} + + +int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd, + int64_t offset, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FTRUNCATE, cb); + + req->file.fd = fd; + req->fs.info.offset = offset; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__ftruncate(req); + return req->result; + } +} + + + +int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out, + uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_SENDFILE, cb); + + req->file.fd = fd_in; + req->fs.info.fd_out = fd_out; + req->fs.info.offset = in_offset; + req->fs.info.bufsml[0].len = length; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__sendfile(req); + return req->result; + } +} + + +int uv_fs_access(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_ACCESS, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) + return uv_translate_sys_error(err); + + req->flags = flags; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } + + fs__access(req); + return req->result; +} + + +int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_CHMOD, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.mode = mode; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__chmod(req); + return req->result; + } +} + + +int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode, + uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FCHMOD, cb); + + req->file.fd = fd; + req->fs.info.mode = mode; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__fchmod(req); + return req->result; + } +} + + +int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, + double mtime, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_UTIME, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.time.atime = atime; + req->fs.time.mtime = mtime; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__utime(req); + return req->result; + } +} + + +int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime, + double mtime, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FUTIME, cb); + + req->file.fd = fd; + req->fs.time.atime = atime; + req->fs.time.mtime = mtime; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__futime(req); + return req->result; + } +} diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c new file mode 100644 index 0000000..744f8e0 --- /dev/null +++ b/src/win/getaddrinfo.c @@ -0,0 +1,385 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include + +#include "uv.h" +#include "internal.h" +#include "req-inl.h" + +/* EAI_* constants. */ +#include + + +int uv__getaddrinfo_translate_error(int sys_err) { + switch (sys_err) { + case 0: return 0; + case WSATRY_AGAIN: return UV_EAI_AGAIN; + case WSAEINVAL: return UV_EAI_BADFLAGS; + case WSANO_RECOVERY: return UV_EAI_FAIL; + case WSAEAFNOSUPPORT: return UV_EAI_FAMILY; + case WSA_NOT_ENOUGH_MEMORY: return UV_EAI_MEMORY; + case WSAHOST_NOT_FOUND: return UV_EAI_NONAME; + case WSATYPE_NOT_FOUND: return UV_EAI_SERVICE; + case WSAESOCKTNOSUPPORT: return UV_EAI_SOCKTYPE; + default: return uv_translate_sys_error(sys_err); + } +} + + +/* + * MinGW is missing this + */ +#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR) + typedef struct addrinfoW { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + WCHAR* ai_canonname; + struct sockaddr* ai_addr; + struct addrinfoW* ai_next; + } ADDRINFOW, *PADDRINFOW; + + DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node, + const WCHAR* service, + const ADDRINFOW* hints, + PADDRINFOW* result); + + DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo); +#endif + + +/* adjust size value to be multiple of 4. Use to keep pointer aligned */ +/* Do we need different versions of this for different architectures? */ +#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2) + + +static void uv__getaddrinfo_work(struct uv__work* w) { + uv_getaddrinfo_t* req; + struct addrinfoW* hints; + int err; + + req = container_of(w, uv_getaddrinfo_t, work_req); + hints = req->addrinfow; + req->addrinfow = NULL; + err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow); + req->retcode = uv__getaddrinfo_translate_error(err); +} + + +/* + * Called from uv_run when complete. Call user specified callback + * then free returned addrinfo + * Returned addrinfo strings are converted from UTF-16 to UTF-8. + * + * To minimize allocation we calculate total size required, + * and copy all structs and referenced strings into the one block. + * Each size calculation is adjusted to avoid unaligned pointers. + */ +static void uv__getaddrinfo_done(struct uv__work* w, int status) { + uv_getaddrinfo_t* req; + int addrinfo_len = 0; + int name_len = 0; + size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo)); + struct addrinfoW* addrinfow_ptr; + struct addrinfo* addrinfo_ptr; + char* alloc_ptr = NULL; + char* cur_ptr = NULL; + + req = container_of(w, uv_getaddrinfo_t, work_req); + + /* release input parameter memory */ + uv__free(req->alloc); + req->alloc = NULL; + + if (status == UV_ECANCELED) { + assert(req->retcode == 0); + req->retcode = UV_EAI_CANCELED; + goto complete; + } + + if (req->retcode == 0) { + /* convert addrinfoW to addrinfo */ + /* first calculate required length */ + addrinfow_ptr = req->addrinfow; + while (addrinfow_ptr != NULL) { + addrinfo_len += addrinfo_struct_len + + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); + if (addrinfow_ptr->ai_canonname != NULL) { + name_len = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + NULL, + 0, + NULL, + NULL); + if (name_len == 0) { + req->retcode = uv_translate_sys_error(GetLastError()); + goto complete; + } + addrinfo_len += ALIGNED_SIZE(name_len); + } + addrinfow_ptr = addrinfow_ptr->ai_next; + } + + /* allocate memory for addrinfo results */ + alloc_ptr = (char*)uv__malloc(addrinfo_len); + + /* do conversions */ + if (alloc_ptr != NULL) { + cur_ptr = alloc_ptr; + addrinfow_ptr = req->addrinfow; + + while (addrinfow_ptr != NULL) { + /* copy addrinfo struct data */ + assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len); + addrinfo_ptr = (struct addrinfo*)cur_ptr; + addrinfo_ptr->ai_family = addrinfow_ptr->ai_family; + addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype; + addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol; + addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags; + addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen; + addrinfo_ptr->ai_canonname = NULL; + addrinfo_ptr->ai_addr = NULL; + addrinfo_ptr->ai_next = NULL; + + cur_ptr += addrinfo_struct_len; + + /* copy sockaddr */ + if (addrinfo_ptr->ai_addrlen > 0) { + assert(cur_ptr + addrinfo_ptr->ai_addrlen <= + alloc_ptr + addrinfo_len); + memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen); + addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr; + cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen); + } + + /* convert canonical name to UTF-8 */ + if (addrinfow_ptr->ai_canonname != NULL) { + name_len = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + NULL, + 0, + NULL, + NULL); + assert(name_len > 0); + assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len); + name_len = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + cur_ptr, + name_len, + NULL, + NULL); + assert(name_len > 0); + addrinfo_ptr->ai_canonname = cur_ptr; + cur_ptr += ALIGNED_SIZE(name_len); + } + assert(cur_ptr <= alloc_ptr + addrinfo_len); + + /* set next ptr */ + addrinfow_ptr = addrinfow_ptr->ai_next; + if (addrinfow_ptr != NULL) { + addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr; + } + } + req->addrinfo = (struct addrinfo*)alloc_ptr; + } else { + req->retcode = UV_EAI_MEMORY; + } + } + + /* return memory to system */ + if (req->addrinfow != NULL) { + FreeAddrInfoW(req->addrinfow); + req->addrinfow = NULL; + } + +complete: + uv__req_unregister(req->loop, req); + + /* finally do callback with converted result */ + if (req->getaddrinfo_cb) + req->getaddrinfo_cb(req, req->retcode, req->addrinfo); +} + + +void uv_freeaddrinfo(struct addrinfo* ai) { + char* alloc_ptr = (char*)ai; + + /* release copied result memory */ + uv__free(alloc_ptr); +} + + +/* + * Entry point for getaddrinfo + * we convert the UTF-8 strings to UNICODE + * and save the UNICODE string pointers in the req + * We also copy hints so that caller does not need to keep memory until the + * callback. + * return 0 if a callback will be made + * return error code if validation fails + * + * To minimize allocation we calculate total size required, + * and copy all structs and referenced strings into the one block. + * Each size calculation is adjusted to avoid unaligned pointers. + */ +int uv_getaddrinfo(uv_loop_t* loop, + uv_getaddrinfo_t* req, + uv_getaddrinfo_cb getaddrinfo_cb, + const char* node, + const char* service, + const struct addrinfo* hints) { + int nodesize = 0; + int servicesize = 0; + int hintssize = 0; + char* alloc_ptr = NULL; + int err; + + if (req == NULL || (node == NULL && service == NULL)) { + err = WSAEINVAL; + goto error; + } + + uv_req_init(loop, (uv_req_t*)req); + + req->getaddrinfo_cb = getaddrinfo_cb; + req->addrinfo = NULL; + req->type = UV_GETADDRINFO; + req->loop = loop; + req->retcode = 0; + + /* calculate required memory size for all input values */ + if (node != NULL) { + nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) * + sizeof(WCHAR)); + if (nodesize == 0) { + err = GetLastError(); + goto error; + } + } + + if (service != NULL) { + servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, + 0, + service, + -1, + NULL, + 0) * + sizeof(WCHAR)); + if (servicesize == 0) { + err = GetLastError(); + goto error; + } + } + if (hints != NULL) { + hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW)); + } + + /* allocate memory for inputs, and partition it as needed */ + alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize); + if (!alloc_ptr) { + err = WSAENOBUFS; + goto error; + } + + /* save alloc_ptr now so we can free if error */ + req->alloc = (void*)alloc_ptr; + + /* convert node string to UTF16 into allocated memory and save pointer in */ + /* the request. */ + if (node != NULL) { + req->node = (WCHAR*)alloc_ptr; + if (MultiByteToWideChar(CP_UTF8, + 0, + node, + -1, + (WCHAR*) alloc_ptr, + nodesize / sizeof(WCHAR)) == 0) { + err = GetLastError(); + goto error; + } + alloc_ptr += nodesize; + } else { + req->node = NULL; + } + + /* convert service string to UTF16 into allocated memory and save pointer */ + /* in the req. */ + if (service != NULL) { + req->service = (WCHAR*)alloc_ptr; + if (MultiByteToWideChar(CP_UTF8, + 0, + service, + -1, + (WCHAR*) alloc_ptr, + servicesize / sizeof(WCHAR)) == 0) { + err = GetLastError(); + goto error; + } + alloc_ptr += servicesize; + } else { + req->service = NULL; + } + + /* copy hints to allocated memory and save pointer in req */ + if (hints != NULL) { + req->addrinfow = (struct addrinfoW*)alloc_ptr; + req->addrinfow->ai_family = hints->ai_family; + req->addrinfow->ai_socktype = hints->ai_socktype; + req->addrinfow->ai_protocol = hints->ai_protocol; + req->addrinfow->ai_flags = hints->ai_flags; + req->addrinfow->ai_addrlen = 0; + req->addrinfow->ai_canonname = NULL; + req->addrinfow->ai_addr = NULL; + req->addrinfow->ai_next = NULL; + } else { + req->addrinfow = NULL; + } + + uv__req_register(loop, req); + + if (getaddrinfo_cb) { + uv__work_submit(loop, + &req->work_req, + uv__getaddrinfo_work, + uv__getaddrinfo_done); + return 0; + } else { + uv__getaddrinfo_work(&req->work_req); + uv__getaddrinfo_done(&req->work_req, 0); + return req->retcode; + } + +error: + if (req != NULL) { + uv__free(req->alloc); + req->alloc = NULL; + } + return uv_translate_sys_error(err); +} diff --git a/src/win/getnameinfo.c b/src/win/getnameinfo.c new file mode 100644 index 0000000..66b64b8 --- /dev/null +++ b/src/win/getnameinfo.c @@ -0,0 +1,150 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. +* +* 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. +*/ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "req-inl.h" + +#ifndef GetNameInfo +int WSAAPI GetNameInfoW( + const SOCKADDR *pSockaddr, + socklen_t SockaddrLength, + PWCHAR pNodeBuffer, + DWORD NodeBufferSize, + PWCHAR pServiceBuffer, + DWORD ServiceBufferSize, + INT Flags +); +#endif + +static void uv__getnameinfo_work(struct uv__work* w) { + uv_getnameinfo_t* req; + WCHAR host[NI_MAXHOST]; + WCHAR service[NI_MAXSERV]; + int ret = 0; + + req = container_of(w, uv_getnameinfo_t, work_req); + if (GetNameInfoW((struct sockaddr*)&req->storage, + sizeof(req->storage), + host, + ARRAY_SIZE(host), + service, + ARRAY_SIZE(service), + req->flags)) { + ret = WSAGetLastError(); + } + req->retcode = uv__getaddrinfo_translate_error(ret); + + /* convert results to UTF-8 */ + WideCharToMultiByte(CP_UTF8, + 0, + host, + -1, + req->host, + sizeof(req->host), + NULL, + NULL); + + WideCharToMultiByte(CP_UTF8, + 0, + service, + -1, + req->service, + sizeof(req->service), + NULL, + NULL); +} + + +/* +* Called from uv_run when complete. +*/ +static void uv__getnameinfo_done(struct uv__work* w, int status) { + uv_getnameinfo_t* req; + char* host; + char* service; + + req = container_of(w, uv_getnameinfo_t, work_req); + uv__req_unregister(req->loop, req); + host = service = NULL; + + if (status == UV_ECANCELED) { + assert(req->retcode == 0); + req->retcode = UV_EAI_CANCELED; + } else if (req->retcode == 0) { + host = req->host; + service = req->service; + } + + if (req->getnameinfo_cb) + req->getnameinfo_cb(req, req->retcode, host, service); +} + + +/* +* Entry point for getnameinfo +* return 0 if a callback will be made +* return error code if validation fails +*/ +int uv_getnameinfo(uv_loop_t* loop, + uv_getnameinfo_t* req, + uv_getnameinfo_cb getnameinfo_cb, + const struct sockaddr* addr, + int flags) { + if (req == NULL || addr == NULL) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) { + memcpy(&req->storage, + addr, + sizeof(struct sockaddr_in)); + } else if (addr->sa_family == AF_INET6) { + memcpy(&req->storage, + addr, + sizeof(struct sockaddr_in6)); + } else { + return UV_EINVAL; + } + + uv_req_init(loop, (uv_req_t*)req); + uv__req_register(loop, req); + + req->getnameinfo_cb = getnameinfo_cb; + req->flags = flags; + req->type = UV_GETNAMEINFO; + req->loop = loop; + req->retcode = 0; + + if (getnameinfo_cb) { + uv__work_submit(loop, + &req->work_req, + uv__getnameinfo_work, + uv__getnameinfo_done); + return 0; + } else { + uv__getnameinfo_work(&req->work_req); + uv__getnameinfo_done(&req->work_req, 0); + return req->retcode; + } +} diff --git a/src/win/handle-inl.h b/src/win/handle-inl.h new file mode 100644 index 0000000..8d0334c --- /dev/null +++ b/src/win/handle-inl.h @@ -0,0 +1,179 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_WIN_HANDLE_INL_H_ +#define UV_WIN_HANDLE_INL_H_ + +#include +#include + +#include "uv.h" +#include "internal.h" + + +#define DECREASE_ACTIVE_COUNT(loop, handle) \ + do { \ + if (--(handle)->activecnt == 0 && \ + !((handle)->flags & UV__HANDLE_CLOSING)) { \ + uv__handle_stop((handle)); \ + } \ + assert((handle)->activecnt >= 0); \ + } while (0) + + +#define INCREASE_ACTIVE_COUNT(loop, handle) \ + do { \ + if ((handle)->activecnt++ == 0) { \ + uv__handle_start((handle)); \ + } \ + assert((handle)->activecnt > 0); \ + } while (0) + + +#define DECREASE_PENDING_REQ_COUNT(handle) \ + do { \ + assert(handle->reqs_pending > 0); \ + handle->reqs_pending--; \ + \ + if (handle->flags & UV__HANDLE_CLOSING && \ + handle->reqs_pending == 0) { \ + uv_want_endgame(loop, (uv_handle_t*)handle); \ + } \ + } while (0) + + +#define uv__handle_closing(handle) \ + do { \ + assert(!((handle)->flags & UV__HANDLE_CLOSING)); \ + \ + if (!(((handle)->flags & UV__HANDLE_ACTIVE) && \ + ((handle)->flags & UV__HANDLE_REF))) \ + uv__active_handle_add((uv_handle_t*) (handle)); \ + \ + (handle)->flags |= UV__HANDLE_CLOSING; \ + (handle)->flags &= ~UV__HANDLE_ACTIVE; \ + } while (0) + + +#define uv__handle_close(handle) \ + do { \ + QUEUE_REMOVE(&(handle)->handle_queue); \ + uv__active_handle_rm((uv_handle_t*) (handle)); \ + \ + (handle)->flags |= UV_HANDLE_CLOSED; \ + \ + if ((handle)->close_cb) \ + (handle)->close_cb((uv_handle_t*) (handle)); \ + } while (0) + + +INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) { + if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) { + handle->flags |= UV_HANDLE_ENDGAME_QUEUED; + + handle->endgame_next = loop->endgame_handles; + loop->endgame_handles = handle; + } +} + + +INLINE static void uv_process_endgames(uv_loop_t* loop) { + uv_handle_t* handle; + + while (loop->endgame_handles) { + handle = loop->endgame_handles; + loop->endgame_handles = handle->endgame_next; + + handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED; + + switch (handle->type) { + case UV_TCP: + uv_tcp_endgame(loop, (uv_tcp_t*) handle); + break; + + case UV_NAMED_PIPE: + uv_pipe_endgame(loop, (uv_pipe_t*) handle); + break; + + case UV_TTY: + uv_tty_endgame(loop, (uv_tty_t*) handle); + break; + + case UV_UDP: + uv_udp_endgame(loop, (uv_udp_t*) handle); + break; + + case UV_POLL: + uv_poll_endgame(loop, (uv_poll_t*) handle); + break; + + case UV_TIMER: + uv_timer_endgame(loop, (uv_timer_t*) handle); + break; + + case UV_PREPARE: + case UV_CHECK: + case UV_IDLE: + uv_loop_watcher_endgame(loop, handle); + break; + + case UV_ASYNC: + uv_async_endgame(loop, (uv_async_t*) handle); + break; + + case UV_SIGNAL: + uv_signal_endgame(loop, (uv_signal_t*) handle); + break; + + case UV_PROCESS: + uv_process_endgame(loop, (uv_process_t*) handle); + break; + + case UV_FS_EVENT: + uv_fs_event_endgame(loop, (uv_fs_event_t*) handle); + break; + + case UV_FS_POLL: + uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle); + break; + + default: + assert(0); + break; + } + } +} + +INLINE static HANDLE uv__get_osfhandle(int fd) +{ + /* _get_osfhandle() raises an assert in debug builds if the FD is invalid. */ + /* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE */ + /* for invalid FDs in release builds (or if you let the assert continue). */ + /* So this wrapper function disables asserts when calling _get_osfhandle. */ + + HANDLE handle; + UV_BEGIN_DISABLE_CRT_ASSERT(); + handle = (HANDLE) _get_osfhandle(fd); + UV_END_DISABLE_CRT_ASSERT(); + return handle; +} + +#endif /* UV_WIN_HANDLE_INL_H_ */ diff --git a/src/win/handle.c b/src/win/handle.c new file mode 100644 index 0000000..72b49d9 --- /dev/null +++ b/src/win/handle.c @@ -0,0 +1,154 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" + + +uv_handle_type uv_guess_handle(uv_file file) { + HANDLE handle; + DWORD mode; + + if (file < 0) { + return UV_UNKNOWN_HANDLE; + } + + handle = uv__get_osfhandle(file); + + switch (GetFileType(handle)) { + case FILE_TYPE_CHAR: + if (GetConsoleMode(handle, &mode)) { + return UV_TTY; + } else { + return UV_FILE; + } + + case FILE_TYPE_PIPE: + return UV_NAMED_PIPE; + + case FILE_TYPE_DISK: + return UV_FILE; + + default: + return UV_UNKNOWN_HANDLE; + } +} + + +int uv_is_active(const uv_handle_t* handle) { + return (handle->flags & UV__HANDLE_ACTIVE) && + !(handle->flags & UV__HANDLE_CLOSING); +} + + +void uv_close(uv_handle_t* handle, uv_close_cb cb) { + uv_loop_t* loop = handle->loop; + + if (handle->flags & UV__HANDLE_CLOSING) { + assert(0); + return; + } + + handle->close_cb = cb; + + /* Handle-specific close actions */ + switch (handle->type) { + case UV_TCP: + uv_tcp_close(loop, (uv_tcp_t*)handle); + return; + + case UV_NAMED_PIPE: + uv_pipe_close(loop, (uv_pipe_t*) handle); + return; + + case UV_TTY: + uv_tty_close((uv_tty_t*) handle); + return; + + case UV_UDP: + uv_udp_close(loop, (uv_udp_t*) handle); + return; + + case UV_POLL: + uv_poll_close(loop, (uv_poll_t*) handle); + return; + + case UV_TIMER: + uv_timer_stop((uv_timer_t*)handle); + uv__handle_closing(handle); + uv_want_endgame(loop, handle); + return; + + case UV_PREPARE: + uv_prepare_stop((uv_prepare_t*)handle); + uv__handle_closing(handle); + uv_want_endgame(loop, handle); + return; + + case UV_CHECK: + uv_check_stop((uv_check_t*)handle); + uv__handle_closing(handle); + uv_want_endgame(loop, handle); + return; + + case UV_IDLE: + uv_idle_stop((uv_idle_t*)handle); + uv__handle_closing(handle); + uv_want_endgame(loop, handle); + return; + + case UV_ASYNC: + uv_async_close(loop, (uv_async_t*) handle); + return; + + case UV_SIGNAL: + uv_signal_close(loop, (uv_signal_t*) handle); + return; + + case UV_PROCESS: + uv_process_close(loop, (uv_process_t*) handle); + return; + + case UV_FS_EVENT: + uv_fs_event_close(loop, (uv_fs_event_t*) handle); + return; + + case UV_FS_POLL: + uv__fs_poll_close((uv_fs_poll_t*) handle); + uv__handle_closing(handle); + uv_want_endgame(loop, handle); + return; + + default: + /* Not supported */ + abort(); + } +} + + +int uv_is_closing(const uv_handle_t* handle) { + return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED)); +} diff --git a/src/win/internal.h b/src/win/internal.h new file mode 100644 index 0000000..b8cfde9 --- /dev/null +++ b/src/win/internal.h @@ -0,0 +1,394 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_WIN_INTERNAL_H_ +#define UV_WIN_INTERNAL_H_ + +#include "uv.h" +#include "../uv-common.h" + +#include "tree.h" +#include "winapi.h" +#include "winsock.h" + +#ifdef _MSC_VER +# define INLINE __inline +# define UV_THREAD_LOCAL __declspec( thread ) +#else +# define INLINE inline +# define UV_THREAD_LOCAL __thread +#endif + + +#ifdef _DEBUG + +extern UV_THREAD_LOCAL int uv__crt_assert_enabled; + +#define UV_BEGIN_DISABLE_CRT_ASSERT() \ + { \ + int uv__saved_crt_assert_enabled = uv__crt_assert_enabled; \ + uv__crt_assert_enabled = FALSE; + + +#define UV_END_DISABLE_CRT_ASSERT() \ + uv__crt_assert_enabled = uv__saved_crt_assert_enabled; \ + } + +#else +#define UV_BEGIN_DISABLE_CRT_ASSERT() +#define UV_END_DISABLE_CRT_ASSERT() +#endif + +/* + * Handles + * (also see handle-inl.h) + */ + +/* Used by all handles. */ +#define UV_HANDLE_CLOSED 0x00000002 +#define UV_HANDLE_ENDGAME_QUEUED 0x00000008 + +/* uv-common.h: #define UV__HANDLE_CLOSING 0x00000001 */ +/* uv-common.h: #define UV__HANDLE_ACTIVE 0x00000040 */ +/* uv-common.h: #define UV__HANDLE_REF 0x00000020 */ +/* uv-common.h: #define UV_HANDLE_INTERNAL 0x00000080 */ + +/* Used by streams and UDP handles. */ +#define UV_HANDLE_READING 0x00000100 +#define UV_HANDLE_BOUND 0x00000200 +#define UV_HANDLE_LISTENING 0x00000800 +#define UV_HANDLE_CONNECTION 0x00001000 +#define UV_HANDLE_READABLE 0x00008000 +#define UV_HANDLE_WRITABLE 0x00010000 +#define UV_HANDLE_READ_PENDING 0x00020000 +#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00040000 +#define UV_HANDLE_ZERO_READ 0x00080000 +#define UV_HANDLE_EMULATE_IOCP 0x00100000 +#define UV_HANDLE_BLOCKING_WRITES 0x00200000 +#define UV_HANDLE_CANCELLATION_PENDING 0x00400000 + +/* Used by uv_tcp_t and uv_udp_t handles */ +#define UV_HANDLE_IPV6 0x01000000 + +/* Only used by uv_tcp_t handles. */ +#define UV_HANDLE_TCP_NODELAY 0x02000000 +#define UV_HANDLE_TCP_KEEPALIVE 0x04000000 +#define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000 +#define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000 +#define UV_HANDLE_TCP_SOCKET_CLOSED 0x20000000 +#define UV_HANDLE_SHARED_TCP_SOCKET 0x40000000 + +/* Only used by uv_pipe_t handles. */ +#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000 +#define UV_HANDLE_PIPESERVER 0x02000000 +#define UV_HANDLE_PIPE_READ_CANCELABLE 0x04000000 + +/* Only used by uv_tty_t handles. */ +#define UV_HANDLE_TTY_READABLE 0x01000000 +#define UV_HANDLE_TTY_RAW 0x02000000 +#define UV_HANDLE_TTY_SAVED_POSITION 0x04000000 +#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x08000000 + +/* Only used by uv_poll_t handles. */ +#define UV_HANDLE_POLL_SLOW 0x02000000 + + +/* + * Requests: see req-inl.h + */ + + +/* + * Streams: see stream-inl.h + */ + + +/* + * TCP + */ + +typedef struct { + WSAPROTOCOL_INFOW socket_info; + int delayed_error; +} uv__ipc_socket_info_ex; + +int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb); +int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client); +int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb); +int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle, + const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); +int uv__tcp_try_write(uv_tcp_t* handle, const uv_buf_t bufs[], + unsigned int nbufs); + +void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req); +void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_write_t* req); +void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_req_t* req); +void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_connect_t* req); + +void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp); +void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); + +int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex, + int tcp_connection); + +int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, + LPWSAPROTOCOL_INFOW protocol_info); + + +/* + * UDP + */ +void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req); +void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, + uv_udp_send_t* req); + +void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle); +void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle); + + +/* + * Pipes + */ +int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, + char* name, size_t nameSize); + +int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); +int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client); +int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb); +int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle, + const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); +int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle, + const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, + uv_write_cb cb); +void uv__pipe_pause_read(uv_pipe_t* handle); +void uv__pipe_unpause_read(uv_pipe_t* handle); +void uv__pipe_stop_read(uv_pipe_t* handle); + +void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_req_t* req); +void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_write_t* req); +void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_req_t* raw_req); +void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_connect_t* req); +void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_shutdown_t* req); + +void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle); +void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle); +void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle); + + +/* + * TTY + */ +void uv_console_init(); + +int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb); +int uv_tty_read_stop(uv_tty_t* handle); +int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle, + const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); +int uv__tty_try_write(uv_tty_t* handle, const uv_buf_t bufs[], + unsigned int nbufs); +void uv_tty_close(uv_tty_t* handle); + +void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* req); +void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, + uv_write_t* req); +/* TODO: remove me */ +void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* raw_req); +/* TODO: remove me */ +void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, + uv_connect_t* req); + +void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle); + + +/* + * Poll watchers + */ +void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, + uv_req_t* req); + +int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle); +void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle); + + +/* + * Timers + */ +void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); + +DWORD uv__next_timeout(const uv_loop_t* loop); +void uv_process_timers(uv_loop_t* loop); + + +/* + * Loop watchers + */ +void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle); + +void uv_prepare_invoke(uv_loop_t* loop); +void uv_check_invoke(uv_loop_t* loop); +void uv_idle_invoke(uv_loop_t* loop); + +void uv__once_init(); + + +/* + * Async watcher + */ +void uv_async_close(uv_loop_t* loop, uv_async_t* handle); +void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle); + +void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, + uv_req_t* req); + + +/* + * Signal watcher + */ +void uv_signals_init(); +int uv__signal_dispatch(int signum); + +void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle); +void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle); + +void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, + uv_req_t* req); + + +/* + * Spawn + */ +void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle); +void uv_process_close(uv_loop_t* loop, uv_process_t* handle); +void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle); + + +/* + * Error + */ +int uv_translate_sys_error(int sys_errno); + + +/* + * FS + */ +void uv_fs_init(); + + +/* + * FS Event + */ +void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, + uv_fs_event_t* handle); +void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle); +void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle); + + +/* + * Stat poller. + */ +void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle); + + +/* + * Utilities. + */ +void uv__util_init(); + +uint64_t uv__hrtime(double scale); +int uv_parent_pid(); +int uv_current_pid(); +__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); +int uv__getpwuid_r(uv_passwd_t* pwd); +int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8); + + +/* + * Process stdio handles. + */ +int uv__stdio_create(uv_loop_t* loop, + const uv_process_options_t* options, + BYTE** buffer_ptr); +void uv__stdio_destroy(BYTE* buffer); +void uv__stdio_noinherit(BYTE* buffer); +int uv__stdio_verify(BYTE* buffer, WORD size); +WORD uv__stdio_size(BYTE* buffer); +HANDLE uv__stdio_handle(BYTE* buffer, int fd); + + +/* + * Winapi and ntapi utility functions + */ +void uv_winapi_init(); + + +/* + * Winsock utility functions + */ +void uv_winsock_init(); + +int uv_ntstatus_to_winsock_error(NTSTATUS status); + +BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target); +BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target); + +int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers, + DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); +int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, + DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr, + int* addr_len, WSAOVERLAPPED *overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); + +int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, + AFD_POLL_INFO* info_out, OVERLAPPED* overlapped); + +/* Whether there are any non-IFS LSPs stacked on TCP */ +extern int uv_tcp_non_ifs_lsp_ipv4; +extern int uv_tcp_non_ifs_lsp_ipv6; + +/* Ip address used to bind to any port at any interface */ +extern struct sockaddr_in uv_addr_ip4_any_; +extern struct sockaddr_in6 uv_addr_ip6_any_; + +/* + * Wake all loops with fake message + */ +void uv__wake_all_loops(); + +/* + * Init system wake-up detection + */ +void uv__init_detect_system_wakeup(); + +#endif /* UV_WIN_INTERNAL_H_ */ diff --git a/src/win/loop-watcher.c b/src/win/loop-watcher.c new file mode 100644 index 0000000..20e4509 --- /dev/null +++ b/src/win/loop-watcher.c @@ -0,0 +1,122 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" + + +void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { + if (handle->flags & UV__HANDLE_CLOSING) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + handle->flags |= UV_HANDLE_CLOSED; + uv__handle_close(handle); + } +} + + +#define UV_LOOP_WATCHER_DEFINE(name, NAME) \ + int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \ + uv__handle_init(loop, (uv_handle_t*) handle, UV_##NAME); \ + \ + return 0; \ + } \ + \ + \ + int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \ + uv_loop_t* loop = handle->loop; \ + uv_##name##_t* old_head; \ + \ + assert(handle->type == UV_##NAME); \ + \ + if (uv__is_active(handle)) \ + return 0; \ + \ + if (cb == NULL) \ + return UV_EINVAL; \ + \ + old_head = loop->name##_handles; \ + \ + handle->name##_next = old_head; \ + handle->name##_prev = NULL; \ + \ + if (old_head) { \ + old_head->name##_prev = handle; \ + } \ + \ + loop->name##_handles = handle; \ + \ + handle->name##_cb = cb; \ + uv__handle_start(handle); \ + \ + return 0; \ + } \ + \ + \ + int uv_##name##_stop(uv_##name##_t* handle) { \ + uv_loop_t* loop = handle->loop; \ + \ + assert(handle->type == UV_##NAME); \ + \ + if (!uv__is_active(handle)) \ + return 0; \ + \ + /* Update loop head if needed */ \ + if (loop->name##_handles == handle) { \ + loop->name##_handles = handle->name##_next; \ + } \ + \ + /* Update the iterator-next pointer of needed */ \ + if (loop->next_##name##_handle == handle) { \ + loop->next_##name##_handle = handle->name##_next; \ + } \ + \ + if (handle->name##_prev) { \ + handle->name##_prev->name##_next = handle->name##_next; \ + } \ + if (handle->name##_next) { \ + handle->name##_next->name##_prev = handle->name##_prev; \ + } \ + \ + uv__handle_stop(handle); \ + \ + return 0; \ + } \ + \ + \ + void uv_##name##_invoke(uv_loop_t* loop) { \ + uv_##name##_t* handle; \ + \ + (loop)->next_##name##_handle = (loop)->name##_handles; \ + \ + while ((loop)->next_##name##_handle != NULL) { \ + handle = (loop)->next_##name##_handle; \ + (loop)->next_##name##_handle = handle->name##_next; \ + \ + handle->name##_cb(handle); \ + } \ + } + +UV_LOOP_WATCHER_DEFINE(prepare, PREPARE) +UV_LOOP_WATCHER_DEFINE(check, CHECK) +UV_LOOP_WATCHER_DEFINE(idle, IDLE) diff --git a/src/win/pipe.c b/src/win/pipe.c new file mode 100644 index 0000000..2442be7 --- /dev/null +++ b/src/win/pipe.c @@ -0,0 +1,2130 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" + +typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t; + +struct uv__ipc_queue_item_s { + /* + * NOTE: It is important for socket_info_ex to be the first field, + * because we will we assigning it to the pending_ipc_info.socket_info + */ + uv__ipc_socket_info_ex socket_info_ex; + QUEUE member; + int tcp_connection; +}; + +/* A zero-size buffer for use by uv_pipe_read */ +static char uv_zero_[] = ""; + +/* Null uv_buf_t */ +static const uv_buf_t uv_null_buf_ = { 0, NULL }; + +/* The timeout that the pipe will wait for the remote end to write data */ +/* when the local ends wants to shut it down. */ +static const int64_t eof_timeout = 50; /* ms */ + +static const int default_pending_pipe_instances = 4; + +/* Pipe prefix */ +static char pipe_prefix[] = "\\\\?\\pipe"; +static const int pipe_prefix_len = sizeof(pipe_prefix) - 1; + +/* IPC protocol flags. */ +#define UV_IPC_RAW_DATA 0x0001 +#define UV_IPC_TCP_SERVER 0x0002 +#define UV_IPC_TCP_CONNECTION 0x0004 + +/* IPC frame header. */ +typedef struct { + int flags; + uint64_t raw_data_length; +} uv_ipc_frame_header_t; + +/* IPC frame, which contains an imported TCP socket stream. */ +typedef struct { + uv_ipc_frame_header_t header; + uv__ipc_socket_info_ex socket_info_ex; +} uv_ipc_frame_uv_stream; + +static void eof_timer_init(uv_pipe_t* pipe); +static void eof_timer_start(uv_pipe_t* pipe); +static void eof_timer_stop(uv_pipe_t* pipe); +static void eof_timer_cb(uv_timer_t* timer); +static void eof_timer_destroy(uv_pipe_t* pipe); +static void eof_timer_close_cb(uv_handle_t* handle); + + +static void uv_unique_pipe_name(char* ptr, char* name, size_t size) { + snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId()); +} + + +int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { + uv_stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); + + handle->reqs_pending = 0; + handle->handle = INVALID_HANDLE_VALUE; + handle->name = NULL; + handle->pipe.conn.ipc_pid = 0; + handle->pipe.conn.remaining_ipc_rawdata_bytes = 0; + QUEUE_INIT(&handle->pipe.conn.pending_ipc_info.queue); + handle->pipe.conn.pending_ipc_info.queue_len = 0; + handle->ipc = ipc; + handle->pipe.conn.non_overlapped_writes_tail = NULL; + handle->pipe.conn.readfile_thread = NULL; + + uv_req_init(loop, (uv_req_t*) &handle->pipe.conn.ipc_header_write_req); + + return 0; +} + + +static void uv_pipe_connection_init(uv_pipe_t* handle) { + uv_connection_init((uv_stream_t*) handle); + handle->read_req.data = handle; + handle->pipe.conn.eof_timer = NULL; + assert(!(handle->flags & UV_HANDLE_PIPESERVER)); + if (pCancelSynchronousIo && + handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + uv_mutex_init(&handle->pipe.conn.readfile_mutex); + handle->flags |= UV_HANDLE_PIPE_READ_CANCELABLE; + } +} + + +static HANDLE open_named_pipe(const WCHAR* name, DWORD* duplex_flags) { + HANDLE pipeHandle; + + /* + * Assume that we have a duplex pipe first, so attempt to + * connect with GENERIC_READ | GENERIC_WRITE. + */ + pipeHandle = CreateFileW(name, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + if (pipeHandle != INVALID_HANDLE_VALUE) { + *duplex_flags = UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + return pipeHandle; + } + + /* + * If the pipe is not duplex CreateFileW fails with + * ERROR_ACCESS_DENIED. In that case try to connect + * as a read-only or write-only. + */ + if (GetLastError() == ERROR_ACCESS_DENIED) { + pipeHandle = CreateFileW(name, + GENERIC_READ | FILE_WRITE_ATTRIBUTES, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + + if (pipeHandle != INVALID_HANDLE_VALUE) { + *duplex_flags = UV_HANDLE_READABLE; + return pipeHandle; + } + } + + if (GetLastError() == ERROR_ACCESS_DENIED) { + pipeHandle = CreateFileW(name, + GENERIC_WRITE | FILE_READ_ATTRIBUTES, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + + if (pipeHandle != INVALID_HANDLE_VALUE) { + *duplex_flags = UV_HANDLE_WRITABLE; + return pipeHandle; + } + } + + return INVALID_HANDLE_VALUE; +} + + +static void close_pipe(uv_pipe_t* pipe) { + assert(pipe->u.fd == -1 || pipe->u.fd > 2); + if (pipe->u.fd == -1) + CloseHandle(pipe->handle); + else + close(pipe->u.fd); + + pipe->u.fd = -1; + pipe->handle = INVALID_HANDLE_VALUE; +} + + +int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, + char* name, size_t nameSize) { + HANDLE pipeHandle; + int err; + char* ptr = (char*)handle; + + for (;;) { + uv_unique_pipe_name(ptr, name, nameSize); + + pipeHandle = CreateNamedPipeA(name, + access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0, + NULL); + + if (pipeHandle != INVALID_HANDLE_VALUE) { + /* No name collisions. We're done. */ + break; + } + + err = GetLastError(); + if (err != ERROR_PIPE_BUSY && err != ERROR_ACCESS_DENIED) { + goto error; + } + + /* Pipe name collision. Increment the pointer and try again. */ + ptr++; + } + + if (CreateIoCompletionPort(pipeHandle, + loop->iocp, + (ULONG_PTR)handle, + 0) == NULL) { + err = GetLastError(); + goto error; + } + + uv_pipe_connection_init(handle); + handle->handle = pipeHandle; + + return 0; + + error: + if (pipeHandle != INVALID_HANDLE_VALUE) { + CloseHandle(pipeHandle); + } + + return err; +} + + +static int uv_set_pipe_handle(uv_loop_t* loop, + uv_pipe_t* handle, + HANDLE pipeHandle, + int fd, + DWORD duplex_flags) { + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_MODE_INFORMATION mode_info; + DWORD mode = PIPE_READMODE_BYTE | PIPE_WAIT; + DWORD current_mode = 0; + DWORD err = 0; + + if (!(handle->flags & UV_HANDLE_PIPESERVER) && + handle->handle != INVALID_HANDLE_VALUE) + return UV_EBUSY; + + if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) { + err = GetLastError(); + if (err == ERROR_ACCESS_DENIED) { + /* + * SetNamedPipeHandleState can fail if the handle doesn't have either + * GENERIC_WRITE or FILE_WRITE_ATTRIBUTES. + * But if the handle already has the desired wait and blocking modes + * we can continue. + */ + if (!GetNamedPipeHandleState(pipeHandle, ¤t_mode, NULL, NULL, + NULL, NULL, 0)) { + return -1; + } else if (current_mode & PIPE_NOWAIT) { + SetLastError(ERROR_ACCESS_DENIED); + return -1; + } + } else { + /* If this returns ERROR_INVALID_PARAMETER we probably opened + * something that is not a pipe. */ + if (err == ERROR_INVALID_PARAMETER) { + SetLastError(WSAENOTSOCK); + } + return -1; + } + } + + /* Check if the pipe was created with FILE_FLAG_OVERLAPPED. */ + nt_status = pNtQueryInformationFile(pipeHandle, + &io_status, + &mode_info, + sizeof(mode_info), + FileModeInformation); + if (nt_status != STATUS_SUCCESS) { + return -1; + } + + if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT || + mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) { + /* Non-overlapped pipe. */ + handle->flags |= UV_HANDLE_NON_OVERLAPPED_PIPE; + } else { + /* Overlapped pipe. Try to associate with IOCP. */ + if (CreateIoCompletionPort(pipeHandle, + loop->iocp, + (ULONG_PTR)handle, + 0) == NULL) { + handle->flags |= UV_HANDLE_EMULATE_IOCP; + } + } + + handle->handle = pipeHandle; + handle->u.fd = fd; + handle->flags |= duplex_flags; + + return 0; +} + + +static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) { + uv_loop_t* loop; + uv_pipe_t* handle; + uv_shutdown_t* req; + + req = (uv_shutdown_t*) parameter; + assert(req); + handle = (uv_pipe_t*) req->handle; + assert(handle); + loop = handle->loop; + assert(loop); + + FlushFileBuffers(handle->handle); + + /* Post completed */ + POST_COMPLETION_FOR_REQ(loop, req); + + return 0; +} + + +void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { + int err; + DWORD result; + uv_shutdown_t* req; + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_PIPE_LOCAL_INFORMATION pipe_info; + uv__ipc_queue_item_t* item; + + if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + handle->flags &= ~UV_HANDLE_PIPE_READ_CANCELABLE; + uv_mutex_destroy(&handle->pipe.conn.readfile_mutex); + } + + if ((handle->flags & UV_HANDLE_CONNECTION) && + handle->stream.conn.shutdown_req != NULL && + handle->stream.conn.write_reqs_pending == 0) { + req = handle->stream.conn.shutdown_req; + + /* Clear the shutdown_req field so we don't go here again. */ + handle->stream.conn.shutdown_req = NULL; + + if (handle->flags & UV__HANDLE_CLOSING) { + UNREGISTER_HANDLE_REQ(loop, handle, req); + + /* Already closing. Cancel the shutdown. */ + if (req->cb) { + req->cb(req, UV_ECANCELED); + } + + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + /* Try to avoid flushing the pipe buffer in the thread pool. */ + nt_status = pNtQueryInformationFile(handle->handle, + &io_status, + &pipe_info, + sizeof pipe_info, + FilePipeLocalInformation); + + if (nt_status != STATUS_SUCCESS) { + /* Failure */ + UNREGISTER_HANDLE_REQ(loop, handle, req); + + handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */ + if (req->cb) { + err = pRtlNtStatusToDosError(nt_status); + req->cb(req, uv_translate_sys_error(err)); + } + + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) { + /* Short-circuit, no need to call FlushFileBuffers. */ + uv_insert_pending_req(loop, (uv_req_t*) req); + return; + } + + /* Run FlushFileBuffers in the thread pool. */ + result = QueueUserWorkItem(pipe_shutdown_thread_proc, + req, + WT_EXECUTELONGFUNCTION); + if (result) { + return; + + } else { + /* Failure. */ + UNREGISTER_HANDLE_REQ(loop, handle, req); + + handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */ + if (req->cb) { + err = GetLastError(); + req->cb(req, uv_translate_sys_error(err)); + } + + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + } + + if (handle->flags & UV__HANDLE_CLOSING && + handle->reqs_pending == 0) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + if (handle->flags & UV_HANDLE_CONNECTION) { + /* Free pending sockets */ + while (!QUEUE_EMPTY(&handle->pipe.conn.pending_ipc_info.queue)) { + QUEUE* q; + SOCKET socket; + + q = QUEUE_HEAD(&handle->pipe.conn.pending_ipc_info.queue); + QUEUE_REMOVE(q); + item = QUEUE_DATA(q, uv__ipc_queue_item_t, member); + + /* Materialize socket and close it */ + socket = WSASocketW(FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + &item->socket_info_ex.socket_info, + 0, + WSA_FLAG_OVERLAPPED); + uv__free(item); + + if (socket != INVALID_SOCKET) + closesocket(socket); + } + handle->pipe.conn.pending_ipc_info.queue_len = 0; + + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(handle->read_req.wait_handle); + handle->read_req.wait_handle = INVALID_HANDLE_VALUE; + } + if (handle->read_req.event_handle) { + CloseHandle(handle->read_req.event_handle); + handle->read_req.event_handle = NULL; + } + } + } + + if (handle->flags & UV_HANDLE_PIPESERVER) { + assert(handle->pipe.serv.accept_reqs); + uv__free(handle->pipe.serv.accept_reqs); + handle->pipe.serv.accept_reqs = NULL; + } + + uv__handle_close(handle); + } +} + + +void uv_pipe_pending_instances(uv_pipe_t* handle, int count) { + if (handle->flags & UV_HANDLE_BOUND) + return; + handle->pipe.serv.pending_instances = count; + handle->flags |= UV_HANDLE_PIPESERVER; +} + + +/* Creates a pipe server. */ +int uv_pipe_bind(uv_pipe_t* handle, const char* name) { + uv_loop_t* loop = handle->loop; + int i, err, nameSize; + uv_pipe_accept_t* req; + + if (handle->flags & UV_HANDLE_BOUND) { + return UV_EINVAL; + } + + if (!name) { + return UV_EINVAL; + } + + if (!(handle->flags & UV_HANDLE_PIPESERVER)) { + handle->pipe.serv.pending_instances = default_pending_pipe_instances; + } + + handle->pipe.serv.accept_reqs = (uv_pipe_accept_t*) + uv__malloc(sizeof(uv_pipe_accept_t) * handle->pipe.serv.pending_instances); + if (!handle->pipe.serv.accept_reqs) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + for (i = 0; i < handle->pipe.serv.pending_instances; i++) { + req = &handle->pipe.serv.accept_reqs[i]; + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_ACCEPT; + req->data = handle; + req->pipeHandle = INVALID_HANDLE_VALUE; + req->next_pending = NULL; + } + + /* Convert name to UTF16. */ + nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); + handle->name = (WCHAR*)uv__malloc(nameSize); + if (!handle->name) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + name, + -1, + handle->name, + nameSize / sizeof(WCHAR))) { + err = GetLastError(); + goto error; + } + + /* + * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE. + * If this fails then there's already a pipe server for the given pipe name. + */ + handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | + FILE_FLAG_FIRST_PIPE_INSTANCE, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL); + + if (handle->pipe.serv.accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) { + err = GetLastError(); + if (err == ERROR_ACCESS_DENIED) { + err = WSAEADDRINUSE; /* Translates to UV_EADDRINUSE. */ + } else if (err == ERROR_PATH_NOT_FOUND || err == ERROR_INVALID_NAME) { + err = WSAEACCES; /* Translates to UV_EACCES. */ + } + goto error; + } + + if (uv_set_pipe_handle(loop, + handle, + handle->pipe.serv.accept_reqs[0].pipeHandle, + -1, + 0)) { + err = GetLastError(); + goto error; + } + + handle->pipe.serv.pending_accepts = NULL; + handle->flags |= UV_HANDLE_PIPESERVER; + handle->flags |= UV_HANDLE_BOUND; + + return 0; + +error: + if (handle->name) { + uv__free(handle->name); + handle->name = NULL; + } + + if (handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) { + CloseHandle(handle->pipe.serv.accept_reqs[0].pipeHandle); + handle->pipe.serv.accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE; + } + + return uv_translate_sys_error(err); +} + + +static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { + uv_loop_t* loop; + uv_pipe_t* handle; + uv_connect_t* req; + HANDLE pipeHandle = INVALID_HANDLE_VALUE; + DWORD duplex_flags; + + req = (uv_connect_t*) parameter; + assert(req); + handle = (uv_pipe_t*) req->handle; + assert(handle); + loop = handle->loop; + assert(loop); + + /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */ + /* We wait for the pipe to become available with WaitNamedPipe. */ + while (WaitNamedPipeW(handle->name, 30000)) { + /* The pipe is now available, try to connect. */ + pipeHandle = open_named_pipe(handle->name, &duplex_flags); + if (pipeHandle != INVALID_HANDLE_VALUE) { + break; + } + + SwitchToThread(); + } + + if (pipeHandle != INVALID_HANDLE_VALUE && + !uv_set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) { + SET_REQ_SUCCESS(req); + } else { + SET_REQ_ERROR(req, GetLastError()); + } + + /* Post completed */ + POST_COMPLETION_FOR_REQ(loop, req); + + return 0; +} + + +void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, + const char* name, uv_connect_cb cb) { + uv_loop_t* loop = handle->loop; + int err, nameSize; + HANDLE pipeHandle = INVALID_HANDLE_VALUE; + DWORD duplex_flags; + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_CONNECT; + req->handle = (uv_stream_t*) handle; + req->cb = cb; + + /* Convert name to UTF16. */ + nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); + handle->name = (WCHAR*)uv__malloc(nameSize); + if (!handle->name) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + name, + -1, + handle->name, + nameSize / sizeof(WCHAR))) { + err = GetLastError(); + goto error; + } + + pipeHandle = open_named_pipe(handle->name, &duplex_flags); + if (pipeHandle == INVALID_HANDLE_VALUE) { + if (GetLastError() == ERROR_PIPE_BUSY) { + /* Wait for the server to make a pipe instance available. */ + if (!QueueUserWorkItem(&pipe_connect_thread_proc, + req, + WT_EXECUTELONGFUNCTION)) { + err = GetLastError(); + goto error; + } + + REGISTER_HANDLE_REQ(loop, handle, req); + handle->reqs_pending++; + + return; + } + + err = GetLastError(); + goto error; + } + + assert(pipeHandle != INVALID_HANDLE_VALUE); + + if (uv_set_pipe_handle(loop, + (uv_pipe_t*) req->handle, + pipeHandle, + -1, + duplex_flags)) { + err = GetLastError(); + goto error; + } + + SET_REQ_SUCCESS(req); + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + return; + +error: + if (handle->name) { + uv__free(handle->name); + handle->name = NULL; + } + + if (pipeHandle != INVALID_HANDLE_VALUE) { + CloseHandle(pipeHandle); + } + + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, err); + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + return; +} + + +void uv__pipe_pause_read(uv_pipe_t* handle) { + if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + /* Pause the ReadFile task briefly, to work + around the Windows kernel bug that causes + any access to a NamedPipe to deadlock if + any process has called ReadFile */ + HANDLE h; + uv_mutex_lock(&handle->pipe.conn.readfile_mutex); + h = handle->pipe.conn.readfile_thread; + while (h) { + /* spinlock: we expect this to finish quickly, + or we are probably about to deadlock anyways + (in the kernel), so it doesn't matter */ + pCancelSynchronousIo(h); + SwitchToThread(); /* yield thread control briefly */ + h = handle->pipe.conn.readfile_thread; + } + } +} + + +void uv__pipe_unpause_read(uv_pipe_t* handle) { + if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + uv_mutex_unlock(&handle->pipe.conn.readfile_mutex); + } +} + + +void uv__pipe_stop_read(uv_pipe_t* handle) { + handle->flags &= ~UV_HANDLE_READING; + uv__pipe_pause_read((uv_pipe_t*)handle); + uv__pipe_unpause_read((uv_pipe_t*)handle); +} + + +/* Cleans up uv_pipe_t (server or connection) and all resources associated */ +/* with it. */ +void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) { + int i; + HANDLE pipeHandle; + + uv__pipe_stop_read(handle); + + if (handle->name) { + uv__free(handle->name); + handle->name = NULL; + } + + if (handle->flags & UV_HANDLE_PIPESERVER) { + for (i = 0; i < handle->pipe.serv.pending_instances; i++) { + pipeHandle = handle->pipe.serv.accept_reqs[i].pipeHandle; + if (pipeHandle != INVALID_HANDLE_VALUE) { + CloseHandle(pipeHandle); + handle->pipe.serv.accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE; + } + } + handle->handle = INVALID_HANDLE_VALUE; + } + + if (handle->flags & UV_HANDLE_CONNECTION) { + handle->flags &= ~UV_HANDLE_WRITABLE; + eof_timer_destroy(handle); + } + + if ((handle->flags & UV_HANDLE_CONNECTION) + && handle->handle != INVALID_HANDLE_VALUE) + close_pipe(handle); +} + + +void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) { + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + if (handle->flags & UV_HANDLE_LISTENING) { + handle->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + uv_pipe_cleanup(loop, handle); + + if (handle->reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + + handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); + uv__handle_closing(handle); +} + + +static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, + uv_pipe_accept_t* req, BOOL firstInstance) { + assert(handle->flags & UV_HANDLE_LISTENING); + + if (!firstInstance) { + assert(req->pipeHandle == INVALID_HANDLE_VALUE); + + req->pipeHandle = CreateNamedPipeW(handle->name, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL); + + if (req->pipeHandle == INVALID_HANDLE_VALUE) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + return; + } + + if (uv_set_pipe_handle(loop, handle, req->pipeHandle, -1, 0)) { + CloseHandle(req->pipeHandle); + req->pipeHandle = INVALID_HANDLE_VALUE; + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + return; + } + } + + assert(req->pipeHandle != INVALID_HANDLE_VALUE); + + /* Prepare the overlapped structure. */ + memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); + + if (!ConnectNamedPipe(req->pipeHandle, &req->u.io.overlapped) && + GetLastError() != ERROR_IO_PENDING) { + if (GetLastError() == ERROR_PIPE_CONNECTED) { + SET_REQ_SUCCESS(req); + } else { + CloseHandle(req->pipeHandle); + req->pipeHandle = INVALID_HANDLE_VALUE; + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, GetLastError()); + } + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + return; + } + + handle->reqs_pending++; +} + + +int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { + uv_loop_t* loop = server->loop; + uv_pipe_t* pipe_client; + uv_pipe_accept_t* req; + QUEUE* q; + uv__ipc_queue_item_t* item; + int err; + + if (server->ipc) { + if (QUEUE_EMPTY(&server->pipe.conn.pending_ipc_info.queue)) { + /* No valid pending sockets. */ + return WSAEWOULDBLOCK; + } + + q = QUEUE_HEAD(&server->pipe.conn.pending_ipc_info.queue); + QUEUE_REMOVE(q); + server->pipe.conn.pending_ipc_info.queue_len--; + item = QUEUE_DATA(q, uv__ipc_queue_item_t, member); + + err = uv_tcp_import((uv_tcp_t*)client, + &item->socket_info_ex, + item->tcp_connection); + if (err != 0) + return err; + + uv__free(item); + + } else { + pipe_client = (uv_pipe_t*)client; + + /* Find a connection instance that has been connected, but not yet */ + /* accepted. */ + req = server->pipe.serv.pending_accepts; + + if (!req) { + /* No valid connections found, so we error out. */ + return WSAEWOULDBLOCK; + } + + /* Initialize the client handle and copy the pipeHandle to the client */ + uv_pipe_connection_init(pipe_client); + pipe_client->handle = req->pipeHandle; + pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + + /* Prepare the req to pick up a new connection */ + server->pipe.serv.pending_accepts = req->next_pending; + req->next_pending = NULL; + req->pipeHandle = INVALID_HANDLE_VALUE; + + if (!(server->flags & UV__HANDLE_CLOSING)) { + uv_pipe_queue_accept(loop, server, req, FALSE); + } + } + + return 0; +} + + +/* Starts listening for connections for the given pipe. */ +int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { + uv_loop_t* loop = handle->loop; + int i; + + if (handle->flags & UV_HANDLE_LISTENING) { + handle->stream.serv.connection_cb = cb; + } + + if (!(handle->flags & UV_HANDLE_BOUND)) { + return WSAEINVAL; + } + + if (handle->flags & UV_HANDLE_READING) { + return WSAEISCONN; + } + + if (!(handle->flags & UV_HANDLE_PIPESERVER)) { + return ERROR_NOT_SUPPORTED; + } + + handle->flags |= UV_HANDLE_LISTENING; + INCREASE_ACTIVE_COUNT(loop, handle); + handle->stream.serv.connection_cb = cb; + + /* First pipe handle should have already been created in uv_pipe_bind */ + assert(handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE); + + for (i = 0; i < handle->pipe.serv.pending_instances; i++) { + uv_pipe_queue_accept(loop, handle, &handle->pipe.serv.accept_reqs[i], i == 0); + } + + return 0; +} + + +static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) { + int result; + DWORD bytes; + uv_read_t* req = (uv_read_t*) parameter; + uv_pipe_t* handle = (uv_pipe_t*) req->data; + uv_loop_t* loop = handle->loop; + HANDLE hThread = NULL; + DWORD err; + uv_mutex_t *m = &handle->pipe.conn.readfile_mutex; + + assert(req != NULL); + assert(req->type == UV_READ); + assert(handle->type == UV_NAMED_PIPE); + + if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + uv_mutex_lock(m); /* mutex controls *setting* of readfile_thread */ + if (DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), + GetCurrentProcess(), &hThread, + 0, TRUE, DUPLICATE_SAME_ACCESS)) { + handle->pipe.conn.readfile_thread = hThread; + } else { + hThread = NULL; + } + uv_mutex_unlock(m); + } +restart_readfile: + result = ReadFile(handle->handle, + &uv_zero_, + 0, + &bytes, + NULL); + if (!result) { + err = GetLastError(); + if (err == ERROR_OPERATION_ABORTED && + handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + if (handle->flags & UV_HANDLE_READING) { + /* just a brief break to do something else */ + handle->pipe.conn.readfile_thread = NULL; + /* resume after it is finished */ + uv_mutex_lock(m); + handle->pipe.conn.readfile_thread = hThread; + uv_mutex_unlock(m); + goto restart_readfile; + } else { + result = 1; /* successfully stopped reading */ + } + } + } + if (hThread) { + assert(hThread == handle->pipe.conn.readfile_thread); + /* mutex does not control clearing readfile_thread */ + handle->pipe.conn.readfile_thread = NULL; + uv_mutex_lock(m); + /* only when we hold the mutex lock is it safe to + open or close the handle */ + CloseHandle(hThread); + uv_mutex_unlock(m); + } + + if (!result) { + SET_REQ_ERROR(req, err); + } + + POST_COMPLETION_FOR_REQ(loop, req); + return 0; +} + + +static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) { + int result; + DWORD bytes; + uv_write_t* req = (uv_write_t*) parameter; + uv_pipe_t* handle = (uv_pipe_t*) req->handle; + uv_loop_t* loop = handle->loop; + + assert(req != NULL); + assert(req->type == UV_WRITE); + assert(handle->type == UV_NAMED_PIPE); + assert(req->write_buffer.base); + + result = WriteFile(handle->handle, + req->write_buffer.base, + req->write_buffer.len, + &bytes, + NULL); + + if (!result) { + SET_REQ_ERROR(req, GetLastError()); + } + + POST_COMPLETION_FOR_REQ(loop, req); + return 0; +} + + +static void CALLBACK post_completion_read_wait(void* context, BOOLEAN timed_out) { + uv_read_t* req; + uv_tcp_t* handle; + + req = (uv_read_t*) context; + assert(req != NULL); + handle = (uv_tcp_t*)req->data; + assert(handle != NULL); + assert(!timed_out); + + if (!PostQueuedCompletionStatus(handle->loop->iocp, + req->u.io.overlapped.InternalHigh, + 0, + &req->u.io.overlapped)) { + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); + } +} + + +static void CALLBACK post_completion_write_wait(void* context, BOOLEAN timed_out) { + uv_write_t* req; + uv_tcp_t* handle; + + req = (uv_write_t*) context; + assert(req != NULL); + handle = (uv_tcp_t*)req->handle; + assert(handle != NULL); + assert(!timed_out); + + if (!PostQueuedCompletionStatus(handle->loop->iocp, + req->u.io.overlapped.InternalHigh, + 0, + &req->u.io.overlapped)) { + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); + } +} + + +static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) { + uv_read_t* req; + int result; + + assert(handle->flags & UV_HANDLE_READING); + assert(!(handle->flags & UV_HANDLE_READ_PENDING)); + + assert(handle->handle != INVALID_HANDLE_VALUE); + + req = &handle->read_req; + + if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + if (!QueueUserWorkItem(&uv_pipe_zero_readfile_thread_proc, + req, + WT_EXECUTELONGFUNCTION)) { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, GetLastError()); + goto error; + } + } else { + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1); + } + + /* Do 0-read */ + result = ReadFile(handle->handle, + &uv_zero_, + 0, + NULL, + &req->u.io.overlapped); + + if (!result && GetLastError() != ERROR_IO_PENDING) { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, GetLastError()); + goto error; + } + + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (!req->event_handle) { + req->event_handle = CreateEvent(NULL, 0, 0, NULL); + if (!req->event_handle) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + } + if (req->wait_handle == INVALID_HANDLE_VALUE) { + if (!RegisterWaitForSingleObject(&req->wait_handle, + req->u.io.overlapped.hEvent, post_completion_read_wait, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD)) { + SET_REQ_ERROR(req, GetLastError()); + goto error; + } + } + } + } + + /* Start the eof timer if there is one */ + eof_timer_start(handle); + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + return; + +error: + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; +} + + +int uv_pipe_read_start(uv_pipe_t* handle, + uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { + uv_loop_t* loop = handle->loop; + + handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb = read_cb; + handle->alloc_cb = alloc_cb; + + /* If reading was stopped and then started again, there could still be a */ + /* read request pending. */ + if (!(handle->flags & UV_HANDLE_READ_PENDING)) + uv_pipe_queue_read(loop, handle); + + return 0; +} + + +static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle, + uv_write_t* req) { + req->next_req = NULL; + if (handle->pipe.conn.non_overlapped_writes_tail) { + req->next_req = + handle->pipe.conn.non_overlapped_writes_tail->next_req; + handle->pipe.conn.non_overlapped_writes_tail->next_req = (uv_req_t*)req; + handle->pipe.conn.non_overlapped_writes_tail = req; + } else { + req->next_req = (uv_req_t*)req; + handle->pipe.conn.non_overlapped_writes_tail = req; + } +} + + +static uv_write_t* uv_remove_non_overlapped_write_req(uv_pipe_t* handle) { + uv_write_t* req; + + if (handle->pipe.conn.non_overlapped_writes_tail) { + req = (uv_write_t*)handle->pipe.conn.non_overlapped_writes_tail->next_req; + + if (req == handle->pipe.conn.non_overlapped_writes_tail) { + handle->pipe.conn.non_overlapped_writes_tail = NULL; + } else { + handle->pipe.conn.non_overlapped_writes_tail->next_req = + req->next_req; + } + + return req; + } else { + /* queue empty */ + return NULL; + } +} + + +static void uv_queue_non_overlapped_write(uv_pipe_t* handle) { + uv_write_t* req = uv_remove_non_overlapped_write_req(handle); + if (req) { + if (!QueueUserWorkItem(&uv_pipe_writefile_thread_proc, + req, + WT_EXECUTELONGFUNCTION)) { + uv_fatal_error(GetLastError(), "QueueUserWorkItem"); + } + } +} + + +static int uv_pipe_write_impl(uv_loop_t* loop, + uv_write_t* req, + uv_pipe_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb) { + int err; + int result; + uv_tcp_t* tcp_send_handle; + uv_write_t* ipc_header_req = NULL; + uv_ipc_frame_uv_stream ipc_frame; + + if (nbufs != 1 && (nbufs != 0 || !send_handle)) { + return ERROR_NOT_SUPPORTED; + } + + /* Only TCP handles are supported for sharing. */ + if (send_handle && ((send_handle->type != UV_TCP) || + (!(send_handle->flags & UV_HANDLE_BOUND) && + !(send_handle->flags & UV_HANDLE_CONNECTION)))) { + return ERROR_NOT_SUPPORTED; + } + + assert(handle->handle != INVALID_HANDLE_VALUE); + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_WRITE; + req->handle = (uv_stream_t*) handle; + req->cb = cb; + req->ipc_header = 0; + req->event_handle = NULL; + req->wait_handle = INVALID_HANDLE_VALUE; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + + if (handle->ipc) { + assert(!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); + ipc_frame.header.flags = 0; + + /* Use the IPC framing protocol. */ + if (send_handle) { + tcp_send_handle = (uv_tcp_t*)send_handle; + + if (handle->pipe.conn.ipc_pid == 0) { + handle->pipe.conn.ipc_pid = uv_current_pid(); + } + + err = uv_tcp_duplicate_socket(tcp_send_handle, handle->pipe.conn.ipc_pid, + &ipc_frame.socket_info_ex.socket_info); + if (err) { + return err; + } + + ipc_frame.socket_info_ex.delayed_error = tcp_send_handle->delayed_error; + + ipc_frame.header.flags |= UV_IPC_TCP_SERVER; + + if (tcp_send_handle->flags & UV_HANDLE_CONNECTION) { + ipc_frame.header.flags |= UV_IPC_TCP_CONNECTION; + } + } + + if (nbufs == 1) { + ipc_frame.header.flags |= UV_IPC_RAW_DATA; + ipc_frame.header.raw_data_length = bufs[0].len; + } + + /* + * Use the provided req if we're only doing a single write. + * If we're doing multiple writes, use ipc_header_write_req to do + * the first write, and then use the provided req for the second write. + */ + if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) { + ipc_header_req = req; + } else { + /* + * Try to use the preallocated write req if it's available. + * Otherwise allocate a new one. + */ + if (handle->pipe.conn.ipc_header_write_req.type != UV_WRITE) { + ipc_header_req = (uv_write_t*)&handle->pipe.conn.ipc_header_write_req; + } else { + ipc_header_req = (uv_write_t*)uv__malloc(sizeof(uv_write_t)); + if (!ipc_header_req) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + } + + uv_req_init(loop, (uv_req_t*) ipc_header_req); + ipc_header_req->type = UV_WRITE; + ipc_header_req->handle = (uv_stream_t*) handle; + ipc_header_req->cb = NULL; + ipc_header_req->ipc_header = 1; + } + + /* Write the header or the whole frame. */ + memset(&ipc_header_req->u.io.overlapped, 0, + sizeof(ipc_header_req->u.io.overlapped)); + + /* Using overlapped IO, but wait for completion before returning. + This write is blocking because ipc_frame is on stack. */ + ipc_header_req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL); + if (!ipc_header_req->u.io.overlapped.hEvent) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + + result = WriteFile(handle->handle, + &ipc_frame, + ipc_frame.header.flags & UV_IPC_TCP_SERVER ? + sizeof(ipc_frame) : sizeof(ipc_frame.header), + NULL, + &ipc_header_req->u.io.overlapped); + if (!result && GetLastError() != ERROR_IO_PENDING) { + err = GetLastError(); + CloseHandle(ipc_header_req->u.io.overlapped.hEvent); + return err; + } + + if (!result) { + /* Request not completed immediately. Wait for it.*/ + if (WaitForSingleObject(ipc_header_req->u.io.overlapped.hEvent, INFINITE) != + WAIT_OBJECT_0) { + err = GetLastError(); + CloseHandle(ipc_header_req->u.io.overlapped.hEvent); + return err; + } + } + ipc_header_req->u.io.queued_bytes = 0; + CloseHandle(ipc_header_req->u.io.overlapped.hEvent); + ipc_header_req->u.io.overlapped.hEvent = NULL; + + REGISTER_HANDLE_REQ(loop, handle, ipc_header_req); + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + + /* If we don't have any raw data to write - we're done. */ + if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) { + return 0; + } + } + + if ((handle->flags & + (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) == + (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) { + DWORD bytes; + result = WriteFile(handle->handle, + bufs[0].base, + bufs[0].len, + &bytes, + NULL); + + if (!result) { + err = GetLastError(); + return err; + } else { + /* Request completed immediately. */ + req->u.io.queued_bytes = 0; + } + + REGISTER_HANDLE_REQ(loop, handle, req); + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + POST_COMPLETION_FOR_REQ(loop, req); + return 0; + } else if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + req->write_buffer = bufs[0]; + uv_insert_non_overlapped_write_req(handle, req); + if (handle->stream.conn.write_reqs_pending == 0) { + uv_queue_non_overlapped_write(handle); + } + + /* Request queued by the kernel. */ + req->u.io.queued_bytes = bufs[0].len; + handle->write_queue_size += req->u.io.queued_bytes; + } else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) { + /* Using overlapped IO, but wait for completion before returning */ + req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL); + if (!req->u.io.overlapped.hEvent) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + + result = WriteFile(handle->handle, + bufs[0].base, + bufs[0].len, + NULL, + &req->u.io.overlapped); + + if (!result && GetLastError() != ERROR_IO_PENDING) { + err = GetLastError(); + CloseHandle(req->u.io.overlapped.hEvent); + return err; + } + + if (result) { + /* Request completed immediately. */ + req->u.io.queued_bytes = 0; + } else { + /* Request queued by the kernel. */ + req->u.io.queued_bytes = bufs[0].len; + handle->write_queue_size += req->u.io.queued_bytes; + if (WaitForSingleObject(req->u.io.overlapped.hEvent, INFINITE) != + WAIT_OBJECT_0) { + err = GetLastError(); + CloseHandle(req->u.io.overlapped.hEvent); + return uv_translate_sys_error(err); + } + } + CloseHandle(req->u.io.overlapped.hEvent); + + REGISTER_HANDLE_REQ(loop, handle, req); + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + return 0; + } else { + result = WriteFile(handle->handle, + bufs[0].base, + bufs[0].len, + NULL, + &req->u.io.overlapped); + + if (!result && GetLastError() != ERROR_IO_PENDING) { + return GetLastError(); + } + + if (result) { + /* Request completed immediately. */ + req->u.io.queued_bytes = 0; + } else { + /* Request queued by the kernel. */ + req->u.io.queued_bytes = bufs[0].len; + handle->write_queue_size += req->u.io.queued_bytes; + } + + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + req->event_handle = CreateEvent(NULL, 0, 0, NULL); + if (!req->event_handle) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + if (!RegisterWaitForSingleObject(&req->wait_handle, + req->u.io.overlapped.hEvent, post_completion_write_wait, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD)) { + return GetLastError(); + } + } + } + + REGISTER_HANDLE_REQ(loop, handle, req); + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + + return 0; +} + + +int uv_pipe_write(uv_loop_t* loop, + uv_write_t* req, + uv_pipe_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb) { + return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, NULL, cb); +} + + +int uv_pipe_write2(uv_loop_t* loop, + uv_write_t* req, + uv_pipe_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb) { + if (!handle->ipc) { + return WSAEINVAL; + } + + return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, send_handle, cb); +} + + +static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle, + uv_buf_t buf) { + /* If there is an eof timer running, we don't need it any more, */ + /* so discard it. */ + eof_timer_destroy(handle); + + handle->flags &= ~UV_HANDLE_READABLE; + uv_read_stop((uv_stream_t*) handle); + + handle->read_cb((uv_stream_t*) handle, UV_EOF, &buf); +} + + +static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error, + uv_buf_t buf) { + /* If there is an eof timer running, we don't need it any more, */ + /* so discard it. */ + eof_timer_destroy(handle); + + uv_read_stop((uv_stream_t*) handle); + + handle->read_cb((uv_stream_t*)handle, uv_translate_sys_error(error), &buf); +} + + +static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle, + int error, uv_buf_t buf) { + if (error == ERROR_BROKEN_PIPE) { + uv_pipe_read_eof(loop, handle, buf); + } else { + uv_pipe_read_error(loop, handle, error, buf); + } +} + + +void uv__pipe_insert_pending_socket(uv_pipe_t* handle, + uv__ipc_socket_info_ex* info, + int tcp_connection) { + uv__ipc_queue_item_t* item; + + item = (uv__ipc_queue_item_t*) uv__malloc(sizeof(*item)); + if (item == NULL) + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + + memcpy(&item->socket_info_ex, info, sizeof(item->socket_info_ex)); + item->tcp_connection = tcp_connection; + QUEUE_INSERT_TAIL(&handle->pipe.conn.pending_ipc_info.queue, &item->member); + handle->pipe.conn.pending_ipc_info.queue_len++; +} + + +void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_req_t* req) { + DWORD bytes, avail; + uv_buf_t buf; + uv_ipc_frame_uv_stream ipc_frame; + + assert(handle->type == UV_NAMED_PIPE); + + handle->flags &= ~UV_HANDLE_READ_PENDING; + eof_timer_stop(handle); + + if (!REQ_SUCCESS(req)) { + /* An error occurred doing the 0-read. */ + if (handle->flags & UV_HANDLE_READING) { + uv_pipe_read_error_or_eof(loop, + handle, + GET_REQ_ERROR(req), + uv_null_buf_); + } + } else { + /* Do non-blocking reads until the buffer is empty */ + while (handle->flags & UV_HANDLE_READING) { + if (!PeekNamedPipe(handle->handle, + NULL, + 0, + NULL, + &avail, + NULL)) { + uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_); + break; + } + + if (avail == 0) { + /* There is nothing to read after all. */ + break; + } + + if (handle->ipc) { + /* Use the IPC framing protocol to read the incoming data. */ + if (handle->pipe.conn.remaining_ipc_rawdata_bytes == 0) { + /* We're reading a new frame. First, read the header. */ + assert(avail >= sizeof(ipc_frame.header)); + + if (!ReadFile(handle->handle, + &ipc_frame.header, + sizeof(ipc_frame.header), + &bytes, + NULL)) { + uv_pipe_read_error_or_eof(loop, handle, GetLastError(), + uv_null_buf_); + break; + } + + assert(bytes == sizeof(ipc_frame.header)); + assert(ipc_frame.header.flags <= (UV_IPC_TCP_SERVER | UV_IPC_RAW_DATA | + UV_IPC_TCP_CONNECTION)); + + if (ipc_frame.header.flags & UV_IPC_TCP_SERVER) { + assert(avail - sizeof(ipc_frame.header) >= + sizeof(ipc_frame.socket_info_ex)); + + /* Read the TCP socket info. */ + if (!ReadFile(handle->handle, + &ipc_frame.socket_info_ex, + sizeof(ipc_frame) - sizeof(ipc_frame.header), + &bytes, + NULL)) { + uv_pipe_read_error_or_eof(loop, handle, GetLastError(), + uv_null_buf_); + break; + } + + assert(bytes == sizeof(ipc_frame) - sizeof(ipc_frame.header)); + + /* Store the pending socket info. */ + uv__pipe_insert_pending_socket( + handle, + &ipc_frame.socket_info_ex, + ipc_frame.header.flags & UV_IPC_TCP_CONNECTION); + } + + if (ipc_frame.header.flags & UV_IPC_RAW_DATA) { + handle->pipe.conn.remaining_ipc_rawdata_bytes = + ipc_frame.header.raw_data_length; + continue; + } + } else { + avail = min(avail, (DWORD)handle->pipe.conn.remaining_ipc_rawdata_bytes); + } + } + + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, avail, &buf); + if (buf.base == NULL || buf.len == 0) { + handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); + break; + } + assert(buf.base != NULL); + + if (ReadFile(handle->handle, + buf.base, + min(buf.len, avail), + &bytes, + NULL)) { + /* Successful read */ + if (handle->ipc) { + assert(handle->pipe.conn.remaining_ipc_rawdata_bytes >= bytes); + handle->pipe.conn.remaining_ipc_rawdata_bytes = + handle->pipe.conn.remaining_ipc_rawdata_bytes - bytes; + } + handle->read_cb((uv_stream_t*)handle, bytes, &buf); + + /* Read again only if bytes == buf.len */ + if (bytes <= buf.len) { + break; + } + } else { + uv_pipe_read_error_or_eof(loop, handle, GetLastError(), buf); + break; + } + } + + /* Post another 0-read if still reading and not closing. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_pipe_queue_read(loop, handle); + } + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_write_t* req) { + int err; + + assert(handle->type == UV_NAMED_PIPE); + + assert(handle->write_queue_size >= req->u.io.queued_bytes); + handle->write_queue_size -= req->u.io.queued_bytes; + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (req->wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(req->wait_handle); + req->wait_handle = INVALID_HANDLE_VALUE; + } + if (req->event_handle) { + CloseHandle(req->event_handle); + req->event_handle = NULL; + } + } + + if (req->ipc_header) { + if (req == &handle->pipe.conn.ipc_header_write_req) { + req->type = UV_UNKNOWN_REQ; + } else { + uv__free(req); + } + } else { + if (req->cb) { + err = GET_REQ_ERROR(req); + req->cb(req, uv_translate_sys_error(err)); + } + } + + handle->stream.conn.write_reqs_pending--; + + if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE && + handle->pipe.conn.non_overlapped_writes_tail) { + assert(handle->stream.conn.write_reqs_pending > 0); + uv_queue_non_overlapped_write(handle); + } + + if (handle->stream.conn.shutdown_req != NULL && + handle->stream.conn.write_reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_req_t* raw_req) { + uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req; + + assert(handle->type == UV_NAMED_PIPE); + + if (handle->flags & UV__HANDLE_CLOSING) { + /* The req->pipeHandle should be freed already in uv_pipe_cleanup(). */ + assert(req->pipeHandle == INVALID_HANDLE_VALUE); + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + if (REQ_SUCCESS(req)) { + assert(req->pipeHandle != INVALID_HANDLE_VALUE); + req->next_pending = handle->pipe.serv.pending_accepts; + handle->pipe.serv.pending_accepts = req; + + if (handle->stream.serv.connection_cb) { + handle->stream.serv.connection_cb((uv_stream_t*)handle, 0); + } + } else { + if (req->pipeHandle != INVALID_HANDLE_VALUE) { + CloseHandle(req->pipeHandle); + req->pipeHandle = INVALID_HANDLE_VALUE; + } + if (!(handle->flags & UV__HANDLE_CLOSING)) { + uv_pipe_queue_accept(loop, handle, req, FALSE); + } + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_connect_t* req) { + int err; + + assert(handle->type == UV_NAMED_PIPE); + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (req->cb) { + err = 0; + if (REQ_SUCCESS(req)) { + uv_pipe_connection_init(handle); + } else { + err = GET_REQ_ERROR(req); + } + req->cb(req, uv_translate_sys_error(err)); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_shutdown_t* req) { + assert(handle->type == UV_NAMED_PIPE); + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (handle->flags & UV_HANDLE_READABLE) { + /* Initialize and optionally start the eof timer. Only do this if the */ + /* pipe is readable and we haven't seen EOF come in ourselves. */ + eof_timer_init(handle); + + /* If reading start the timer right now. */ + /* Otherwise uv_pipe_queue_read will start it. */ + if (handle->flags & UV_HANDLE_READ_PENDING) { + eof_timer_start(handle); + } + + } else { + /* This pipe is not readable. We can just close it to let the other end */ + /* know that we're done writing. */ + close_pipe(handle); + } + + if (req->cb) { + req->cb(req, 0); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +static void eof_timer_init(uv_pipe_t* pipe) { + int r; + + assert(pipe->pipe.conn.eof_timer == NULL); + assert(pipe->flags & UV_HANDLE_CONNECTION); + + pipe->pipe.conn.eof_timer = (uv_timer_t*) uv__malloc(sizeof *pipe->pipe.conn.eof_timer); + + r = uv_timer_init(pipe->loop, pipe->pipe.conn.eof_timer); + assert(r == 0); /* timers can't fail */ + pipe->pipe.conn.eof_timer->data = pipe; + uv_unref((uv_handle_t*) pipe->pipe.conn.eof_timer); +} + + +static void eof_timer_start(uv_pipe_t* pipe) { + assert(pipe->flags & UV_HANDLE_CONNECTION); + + if (pipe->pipe.conn.eof_timer != NULL) { + uv_timer_start(pipe->pipe.conn.eof_timer, eof_timer_cb, eof_timeout, 0); + } +} + + +static void eof_timer_stop(uv_pipe_t* pipe) { + assert(pipe->flags & UV_HANDLE_CONNECTION); + + if (pipe->pipe.conn.eof_timer != NULL) { + uv_timer_stop(pipe->pipe.conn.eof_timer); + } +} + + +static void eof_timer_cb(uv_timer_t* timer) { + uv_pipe_t* pipe = (uv_pipe_t*) timer->data; + uv_loop_t* loop = timer->loop; + + assert(pipe->type == UV_NAMED_PIPE); + + /* This should always be true, since we start the timer only */ + /* in uv_pipe_queue_read after successfully calling ReadFile, */ + /* or in uv_process_pipe_shutdown_req if a read is pending, */ + /* and we always immediately stop the timer in */ + /* uv_process_pipe_read_req. */ + assert(pipe->flags & UV_HANDLE_READ_PENDING); + + /* If there are many packets coming off the iocp then the timer callback */ + /* may be called before the read request is coming off the queue. */ + /* Therefore we check here if the read request has completed but will */ + /* be processed later. */ + if ((pipe->flags & UV_HANDLE_READ_PENDING) && + HasOverlappedIoCompleted(&pipe->read_req.u.io.overlapped)) { + return; + } + + /* Force both ends off the pipe. */ + close_pipe(pipe); + + /* Stop reading, so the pending read that is going to fail will */ + /* not be reported to the user. */ + uv_read_stop((uv_stream_t*) pipe); + + /* Report the eof and update flags. This will get reported even if the */ + /* user stopped reading in the meantime. TODO: is that okay? */ + uv_pipe_read_eof(loop, pipe, uv_null_buf_); +} + + +static void eof_timer_destroy(uv_pipe_t* pipe) { + assert(pipe->flags & UV_HANDLE_CONNECTION); + + if (pipe->pipe.conn.eof_timer) { + uv_close((uv_handle_t*) pipe->pipe.conn.eof_timer, eof_timer_close_cb); + pipe->pipe.conn.eof_timer = NULL; + } +} + + +static void eof_timer_close_cb(uv_handle_t* handle) { + assert(handle->type == UV_TIMER); + uv__free(handle); +} + + +int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { + HANDLE os_handle = uv__get_osfhandle(file); + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_ACCESS_INFORMATION access; + DWORD duplex_flags = 0; + + if (os_handle == INVALID_HANDLE_VALUE) + return UV_EBADF; + + /* In order to avoid closing a stdio file descriptor 0-2, duplicate the + * underlying OS handle and forget about the original fd. + * We could also opt to use the original OS handle and just never close it, + * but then there would be no reliable way to cancel pending read operations + * upon close. + */ + if (file <= 2) { + if (!DuplicateHandle(INVALID_HANDLE_VALUE, + os_handle, + INVALID_HANDLE_VALUE, + &os_handle, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)) + return uv_translate_sys_error(GetLastError()); + file = -1; + } + + /* Determine what kind of permissions we have on this handle. + * Cygwin opens the pipe in message mode, but we can support it, + * just query the access flags and set the stream flags accordingly. + */ + nt_status = pNtQueryInformationFile(os_handle, + &io_status, + &access, + sizeof(access), + FileAccessInformation); + if (nt_status != STATUS_SUCCESS) + return UV_EINVAL; + + if (pipe->ipc) { + if (!(access.AccessFlags & FILE_WRITE_DATA) || + !(access.AccessFlags & FILE_READ_DATA)) { + return UV_EINVAL; + } + } + + if (access.AccessFlags & FILE_WRITE_DATA) + duplex_flags |= UV_HANDLE_WRITABLE; + if (access.AccessFlags & FILE_READ_DATA) + duplex_flags |= UV_HANDLE_READABLE; + + if (os_handle == INVALID_HANDLE_VALUE || + uv_set_pipe_handle(pipe->loop, + pipe, + os_handle, + file, + duplex_flags) == -1) { + return UV_EINVAL; + } + + uv_pipe_connection_init(pipe); + + if (pipe->ipc) { + assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); + pipe->pipe.conn.ipc_pid = uv_parent_pid(); + assert(pipe->pipe.conn.ipc_pid != -1); + } + return 0; +} + + +static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) { + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_NAME_INFORMATION tmp_name_info; + FILE_NAME_INFORMATION* name_info; + WCHAR* name_buf; + unsigned int addrlen; + unsigned int name_size; + unsigned int name_len; + int err; + + name_info = NULL; + + if (handle->handle == INVALID_HANDLE_VALUE) { + *size = 0; + return UV_EINVAL; + } + + uv__pipe_pause_read((uv_pipe_t*)handle); /* cast away const warning */ + + nt_status = pNtQueryInformationFile(handle->handle, + &io_status, + &tmp_name_info, + sizeof tmp_name_info, + FileNameInformation); + if (nt_status == STATUS_BUFFER_OVERFLOW) { + name_size = sizeof(*name_info) + tmp_name_info.FileNameLength; + name_info = uv__malloc(name_size); + if (!name_info) { + *size = 0; + err = UV_ENOMEM; + goto cleanup; + } + + nt_status = pNtQueryInformationFile(handle->handle, + &io_status, + name_info, + name_size, + FileNameInformation); + } + + if (nt_status != STATUS_SUCCESS) { + *size = 0; + err = uv_translate_sys_error(pRtlNtStatusToDosError(nt_status)); + goto error; + } + + if (!name_info) { + /* the struct on stack was used */ + name_buf = tmp_name_info.FileName; + name_len = tmp_name_info.FileNameLength; + } else { + name_buf = name_info->FileName; + name_len = name_info->FileNameLength; + } + + if (name_len == 0) { + *size = 0; + err = 0; + goto error; + } + + name_len /= sizeof(WCHAR); + + /* check how much space we need */ + addrlen = WideCharToMultiByte(CP_UTF8, + 0, + name_buf, + name_len, + NULL, + 0, + NULL, + NULL); + if (!addrlen) { + *size = 0; + err = uv_translate_sys_error(GetLastError()); + goto error; + } else if (pipe_prefix_len + addrlen >= *size) { + /* "\\\\.\\pipe" + name */ + *size = pipe_prefix_len + addrlen + 1; + err = UV_ENOBUFS; + goto error; + } + + memcpy(buffer, pipe_prefix, pipe_prefix_len); + addrlen = WideCharToMultiByte(CP_UTF8, + 0, + name_buf, + name_len, + buffer+pipe_prefix_len, + *size-pipe_prefix_len, + NULL, + NULL); + if (!addrlen) { + *size = 0; + err = uv_translate_sys_error(GetLastError()); + goto error; + } + + addrlen += pipe_prefix_len; + *size = addrlen; + buffer[addrlen] = '\0'; + + err = 0; + goto cleanup; + +error: + uv__free(name_info); + +cleanup: + uv__pipe_unpause_read((uv_pipe_t*)handle); /* cast away const warning */ + return err; +} + + +int uv_pipe_pending_count(uv_pipe_t* handle) { + if (!handle->ipc) + return 0; + return handle->pipe.conn.pending_ipc_info.queue_len; +} + + +int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) { + if (handle->flags & UV_HANDLE_BOUND) + return uv__pipe_getname(handle, buffer, size); + + if (handle->flags & UV_HANDLE_CONNECTION || + handle->handle != INVALID_HANDLE_VALUE) { + *size = 0; + return 0; + } + + return UV_EBADF; +} + + +int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) { + /* emulate unix behaviour */ + if (handle->flags & UV_HANDLE_BOUND) + return UV_ENOTCONN; + + if (handle->handle != INVALID_HANDLE_VALUE) + return uv__pipe_getname(handle, buffer, size); + + return UV_EBADF; +} + + +uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { + if (!handle->ipc) + return UV_UNKNOWN_HANDLE; + if (handle->pipe.conn.pending_ipc_info.queue_len == 0) + return UV_UNKNOWN_HANDLE; + else + return UV_TCP; +} diff --git a/src/win/poll.c b/src/win/poll.c new file mode 100644 index 0000000..d479e52 --- /dev/null +++ b/src/win/poll.c @@ -0,0 +1,646 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = { + {0xe70f1aa0, 0xab8b, 0x11cf, + {0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}, + {0xf9eab0c0, 0x26d4, 0x11d0, + {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}}, + {0x9fc48064, 0x7298, 0x43e4, + {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}} +}; + +typedef struct uv_single_fd_set_s { + unsigned int fd_count; + SOCKET fd_array[1]; +} uv_single_fd_set_t; + + +static OVERLAPPED overlapped_dummy_; +static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT; + +static AFD_POLL_INFO afd_poll_info_dummy_; + + +static void uv__init_overlapped_dummy(void) { + HANDLE event; + + event = CreateEvent(NULL, TRUE, TRUE, NULL); + if (event == NULL) + uv_fatal_error(GetLastError(), "CreateEvent"); + + memset(&overlapped_dummy_, 0, sizeof overlapped_dummy_); + overlapped_dummy_.hEvent = (HANDLE) ((uintptr_t) event | 1); +} + + +static OVERLAPPED* uv__get_overlapped_dummy() { + uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy); + return &overlapped_dummy_; +} + + +static AFD_POLL_INFO* uv__get_afd_poll_info_dummy() { + return &afd_poll_info_dummy_; +} + + +static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { + uv_req_t* req; + AFD_POLL_INFO* afd_poll_info; + DWORD result; + + /* Find a yet unsubmitted req to submit. */ + if (handle->submitted_events_1 == 0) { + req = &handle->poll_req_1; + afd_poll_info = &handle->afd_poll_info_1; + handle->submitted_events_1 = handle->events; + handle->mask_events_1 = 0; + handle->mask_events_2 = handle->events; + } else if (handle->submitted_events_2 == 0) { + req = &handle->poll_req_2; + afd_poll_info = &handle->afd_poll_info_2; + handle->submitted_events_2 = handle->events; + handle->mask_events_1 = handle->events; + handle->mask_events_2 = 0; + } else { + /* Just wait until there's an unsubmitted req. */ + /* This will happen almost immediately as one of the 2 outstanding */ + /* requests is about to return. When this happens, */ + /* uv__fast_poll_process_poll_req will be called, and the pending */ + /* events, if needed, will be processed in a subsequent request. */ + return; + } + + /* Setting Exclusive to TRUE makes the other poll request return if there */ + /* is any. */ + afd_poll_info->Exclusive = TRUE; + afd_poll_info->NumberOfHandles = 1; + afd_poll_info->Timeout.QuadPart = INT64_MAX; + afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket; + afd_poll_info->Handles[0].Status = 0; + afd_poll_info->Handles[0].Events = 0; + + if (handle->events & UV_READABLE) { + afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE | + AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT; + } else { + if (handle->events & UV_DISCONNECT) { + afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT; + } + } + if (handle->events & UV_WRITABLE) { + afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL; + } + + memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped); + + result = uv_msafd_poll((SOCKET) handle->peer_socket, + afd_poll_info, + afd_poll_info, + &req->u.io.overlapped); + if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) { + /* Queue this req, reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, req); + } +} + + +static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) { + AFD_POLL_INFO afd_poll_info; + DWORD result; + + afd_poll_info.Exclusive = TRUE; + afd_poll_info.NumberOfHandles = 1; + afd_poll_info.Timeout.QuadPart = INT64_MAX; + afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket; + afd_poll_info.Handles[0].Status = 0; + afd_poll_info.Handles[0].Events = AFD_POLL_ALL; + + result = uv_msafd_poll(handle->socket, + &afd_poll_info, + uv__get_afd_poll_info_dummy(), + uv__get_overlapped_dummy()); + + if (result == SOCKET_ERROR) { + DWORD error = WSAGetLastError(); + if (error != WSA_IO_PENDING) + return error; + } + + return 0; +} + + +static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, + uv_req_t* req) { + unsigned char mask_events; + AFD_POLL_INFO* afd_poll_info; + + if (req == &handle->poll_req_1) { + afd_poll_info = &handle->afd_poll_info_1; + handle->submitted_events_1 = 0; + mask_events = handle->mask_events_1; + } else if (req == &handle->poll_req_2) { + afd_poll_info = &handle->afd_poll_info_2; + handle->submitted_events_2 = 0; + mask_events = handle->mask_events_2; + } else { + assert(0); + return; + } + + /* Report an error unless the select was just interrupted. */ + if (!REQ_SUCCESS(req)) { + DWORD error = GET_REQ_SOCK_ERROR(req); + if (error != WSAEINTR && handle->events != 0) { + handle->events = 0; /* Stop the watcher */ + handle->poll_cb(handle, uv_translate_sys_error(error), 0); + } + + } else if (afd_poll_info->NumberOfHandles >= 1) { + unsigned char events = 0; + + if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE | + AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) { + events |= UV_READABLE; + if ((afd_poll_info->Handles[0].Events & AFD_POLL_DISCONNECT) != 0) { + events |= UV_DISCONNECT; + } + } + if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND | + AFD_POLL_CONNECT_FAIL)) != 0) { + events |= UV_WRITABLE; + } + + events &= handle->events & ~mask_events; + + if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) { + /* Stop polling. */ + handle->events = 0; + if (uv__is_active(handle)) + uv__handle_stop(handle); + } + + if (events != 0) { + handle->poll_cb(handle, 0, events); + } + } + + if ((handle->events & ~(handle->submitted_events_1 | + handle->submitted_events_2)) != 0) { + uv__fast_poll_submit_poll_req(loop, handle); + } else if ((handle->flags & UV__HANDLE_CLOSING) && + handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { + assert(handle->type == UV_POLL); + assert(!(handle->flags & UV__HANDLE_CLOSING)); + assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); + + handle->events = events; + + if (handle->events != 0) { + uv__handle_start(handle); + } else { + uv__handle_stop(handle); + } + + if ((handle->events & ~(handle->submitted_events_1 | + handle->submitted_events_2)) != 0) { + uv__fast_poll_submit_poll_req(handle->loop, handle); + } + + return 0; +} + + +static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) { + handle->events = 0; + uv__handle_closing(handle); + + if (handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + return 0; + } else { + /* Cancel outstanding poll requests by executing another, unique poll */ + /* request that forces the outstanding ones to return. */ + return uv__fast_poll_cancel_poll_req(loop, handle); + } +} + + +static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp, + WSAPROTOCOL_INFOW* protocol_info) { + SOCKET sock = 0; + + sock = WSASocketW(protocol_info->iAddressFamily, + protocol_info->iSocketType, + protocol_info->iProtocol, + protocol_info, + 0, + WSA_FLAG_OVERLAPPED); + if (sock == INVALID_SOCKET) { + return INVALID_SOCKET; + } + + if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) { + goto error; + }; + + if (CreateIoCompletionPort((HANDLE) sock, + iocp, + (ULONG_PTR) sock, + 0) == NULL) { + goto error; + } + + return sock; + + error: + closesocket(sock); + return INVALID_SOCKET; +} + + +static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop, + WSAPROTOCOL_INFOW* protocol_info) { + int index, i; + SOCKET peer_socket; + + index = -1; + for (i = 0; (size_t) i < ARRAY_SIZE(uv_msafd_provider_ids); i++) { + if (memcmp((void*) &protocol_info->ProviderId, + (void*) &uv_msafd_provider_ids[i], + sizeof protocol_info->ProviderId) == 0) { + index = i; + } + } + + /* Check if the protocol uses an msafd socket. */ + if (index < 0) { + return INVALID_SOCKET; + } + + /* If we didn't (try) to create a peer socket yet, try to make one. Don't */ + /* try again if the peer socket creation failed earlier for the same */ + /* protocol. */ + peer_socket = loop->poll_peer_sockets[index]; + if (peer_socket == 0) { + peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info); + loop->poll_peer_sockets[index] = peer_socket; + } + + return peer_socket; +} + + +static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) { + uv_req_t* req = (uv_req_t*) arg; + uv_poll_t* handle = (uv_poll_t*) req->data; + unsigned char reported_events; + int r; + uv_single_fd_set_t rfds, wfds, efds; + struct timeval timeout; + + assert(handle->type == UV_POLL); + assert(req->type == UV_POLL_REQ); + + if (handle->events & UV_READABLE) { + rfds.fd_count = 1; + rfds.fd_array[0] = handle->socket; + } else { + rfds.fd_count = 0; + } + + if (handle->events & UV_WRITABLE) { + wfds.fd_count = 1; + wfds.fd_array[0] = handle->socket; + efds.fd_count = 1; + efds.fd_array[0] = handle->socket; + } else { + wfds.fd_count = 0; + efds.fd_count = 0; + } + + /* Make the select() time out after 3 minutes. If select() hangs because */ + /* the user closed the socket, we will at least not hang indefinitely. */ + timeout.tv_sec = 3 * 60; + timeout.tv_usec = 0; + + r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout); + if (r == SOCKET_ERROR) { + /* Queue this req, reporting an error. */ + SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError()); + POST_COMPLETION_FOR_REQ(handle->loop, req); + return 0; + } + + reported_events = 0; + + if (r > 0) { + if (rfds.fd_count > 0) { + assert(rfds.fd_count == 1); + assert(rfds.fd_array[0] == handle->socket); + reported_events |= UV_READABLE; + } + + if (wfds.fd_count > 0) { + assert(wfds.fd_count == 1); + assert(wfds.fd_array[0] == handle->socket); + reported_events |= UV_WRITABLE; + } else if (efds.fd_count > 0) { + assert(efds.fd_count == 1); + assert(efds.fd_array[0] == handle->socket); + reported_events |= UV_WRITABLE; + } + } + + SET_REQ_SUCCESS(req); + req->u.io.overlapped.InternalHigh = (DWORD) reported_events; + POST_COMPLETION_FOR_REQ(handle->loop, req); + + return 0; +} + + +static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { + uv_req_t* req; + + /* Find a yet unsubmitted req to submit. */ + if (handle->submitted_events_1 == 0) { + req = &handle->poll_req_1; + handle->submitted_events_1 = handle->events; + handle->mask_events_1 = 0; + handle->mask_events_2 = handle->events; + } else if (handle->submitted_events_2 == 0) { + req = &handle->poll_req_2; + handle->submitted_events_2 = handle->events; + handle->mask_events_1 = handle->events; + handle->mask_events_2 = 0; + } else { + assert(0); + return; + } + + if (!QueueUserWorkItem(uv__slow_poll_thread_proc, + (void*) req, + WT_EXECUTELONGFUNCTION)) { + /* Make this req pending, reporting an error. */ + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, req); + } +} + + + +static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, + uv_req_t* req) { + unsigned char mask_events; + int err; + + if (req == &handle->poll_req_1) { + handle->submitted_events_1 = 0; + mask_events = handle->mask_events_1; + } else if (req == &handle->poll_req_2) { + handle->submitted_events_2 = 0; + mask_events = handle->mask_events_2; + } else { + assert(0); + return; + } + + if (!REQ_SUCCESS(req)) { + /* Error. */ + if (handle->events != 0) { + err = GET_REQ_ERROR(req); + handle->events = 0; /* Stop the watcher */ + handle->poll_cb(handle, uv_translate_sys_error(err), 0); + } + } else { + /* Got some events. */ + int events = req->u.io.overlapped.InternalHigh & handle->events & ~mask_events; + if (events != 0) { + handle->poll_cb(handle, 0, events); + } + } + + if ((handle->events & ~(handle->submitted_events_1 | + handle->submitted_events_2)) != 0) { + uv__slow_poll_submit_poll_req(loop, handle); + } else if ((handle->flags & UV__HANDLE_CLOSING) && + handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { + assert(handle->type == UV_POLL); + assert(!(handle->flags & UV__HANDLE_CLOSING)); + assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); + + handle->events = events; + + if (handle->events != 0) { + uv__handle_start(handle); + } else { + uv__handle_stop(handle); + } + + if ((handle->events & + ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) { + uv__slow_poll_submit_poll_req(handle->loop, handle); + } + + return 0; +} + + +static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) { + handle->events = 0; + uv__handle_closing(handle); + + if (handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + + return 0; +} + + +int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { + return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd)); +} + + +int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, + uv_os_sock_t socket) { + WSAPROTOCOL_INFOW protocol_info; + int len; + SOCKET peer_socket, base_socket; + DWORD bytes; + DWORD yes = 1; + + /* Set the socket to nonblocking mode */ + if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) + return uv_translate_sys_error(WSAGetLastError()); + + /* Try to obtain a base handle for the socket. This increases this chances */ + /* that we find an AFD handle and are able to use the fast poll mechanism. */ + /* This will always fail on windows XP/2k3, since they don't support the */ + /* SIO_BASE_HANDLE ioctl. */ +#ifndef NDEBUG + base_socket = INVALID_SOCKET; +#endif + + if (WSAIoctl(socket, + SIO_BASE_HANDLE, + NULL, + 0, + &base_socket, + sizeof base_socket, + &bytes, + NULL, + NULL) == 0) { + assert(base_socket != 0 && base_socket != INVALID_SOCKET); + socket = base_socket; + } + + uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL); + handle->socket = socket; + handle->events = 0; + + /* Obtain protocol information about the socket. */ + len = sizeof protocol_info; + if (getsockopt(socket, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &len) != 0) { + return uv_translate_sys_error(WSAGetLastError()); + } + + /* Get the peer socket that is needed to enable fast poll. If the returned */ + /* value is NULL, the protocol is not implemented by MSAFD and we'll have */ + /* to use slow mode. */ + peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info); + + if (peer_socket != INVALID_SOCKET) { + /* Initialize fast poll specific fields. */ + handle->peer_socket = peer_socket; + } else { + /* Initialize slow poll specific fields. */ + handle->flags |= UV_HANDLE_POLL_SLOW; + } + + /* Initialize 2 poll reqs. */ + handle->submitted_events_1 = 0; + uv_req_init(loop, (uv_req_t*) &(handle->poll_req_1)); + handle->poll_req_1.type = UV_POLL_REQ; + handle->poll_req_1.data = handle; + + handle->submitted_events_2 = 0; + uv_req_init(loop, (uv_req_t*) &(handle->poll_req_2)); + handle->poll_req_2.type = UV_POLL_REQ; + handle->poll_req_2.data = handle; + + return 0; +} + + +int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) { + int err; + + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + err = uv__fast_poll_set(handle->loop, handle, events); + } else { + err = uv__slow_poll_set(handle->loop, handle, events); + } + + if (err) { + return uv_translate_sys_error(err); + } + + handle->poll_cb = cb; + + return 0; +} + + +int uv_poll_stop(uv_poll_t* handle) { + int err; + + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + err = uv__fast_poll_set(handle->loop, handle, 0); + } else { + err = uv__slow_poll_set(handle->loop, handle, 0); + } + + return uv_translate_sys_error(err); +} + + +void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) { + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + uv__fast_poll_process_poll_req(loop, handle, req); + } else { + uv__slow_poll_process_poll_req(loop, handle, req); + } +} + + +int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) { + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + return uv__fast_poll_close(loop, handle); + } else { + return uv__slow_poll_close(loop, handle); + } +} + + +void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) { + assert(handle->flags & UV__HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + assert(handle->submitted_events_1 == 0); + assert(handle->submitted_events_2 == 0); + + uv__handle_close(handle); +} diff --git a/src/win/process-stdio.c b/src/win/process-stdio.c new file mode 100644 index 0000000..e3c06f5 --- /dev/null +++ b/src/win/process-stdio.c @@ -0,0 +1,510 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" + + +/* + * The `child_stdio_buffer` buffer has the following layout: + * int number_of_fds + * unsigned char crt_flags[number_of_fds] + * HANDLE os_handle[number_of_fds] + */ +#define CHILD_STDIO_SIZE(count) \ + (sizeof(int) + \ + sizeof(unsigned char) * (count) + \ + sizeof(uintptr_t) * (count)) + +#define CHILD_STDIO_COUNT(buffer) \ + *((unsigned int*) (buffer)) + +#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \ + *((unsigned char*) (buffer) + sizeof(int) + fd) + +#define CHILD_STDIO_HANDLE(buffer, fd) \ + *((HANDLE*) ((unsigned char*) (buffer) + \ + sizeof(int) + \ + sizeof(unsigned char) * \ + CHILD_STDIO_COUNT((buffer)) + \ + sizeof(HANDLE) * (fd))) + + +/* CRT file descriptor mode flags */ +#define FOPEN 0x01 +#define FEOFLAG 0x02 +#define FCRLF 0x04 +#define FPIPE 0x08 +#define FNOINHERIT 0x10 +#define FAPPEND 0x20 +#define FDEV 0x40 +#define FTEXT 0x80 + + +/* + * Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited + * the parent process. Don't check for errors - the stdio handles may not be + * valid, or may be closed already. There is no guarantee that this function + * does a perfect job. + */ +void uv_disable_stdio_inheritance(void) { + HANDLE handle; + STARTUPINFOW si; + + /* Make the windows stdio handles non-inheritable. */ + handle = GetStdHandle(STD_INPUT_HANDLE); + if (handle != NULL && handle != INVALID_HANDLE_VALUE) + SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); + + handle = GetStdHandle(STD_OUTPUT_HANDLE); + if (handle != NULL && handle != INVALID_HANDLE_VALUE) + SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); + + handle = GetStdHandle(STD_ERROR_HANDLE); + if (handle != NULL && handle != INVALID_HANDLE_VALUE) + SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); + + /* Make inherited CRT FDs non-inheritable. */ + GetStartupInfoW(&si); + if (uv__stdio_verify(si.lpReserved2, si.cbReserved2)) + uv__stdio_noinherit(si.lpReserved2); +} + + +static int uv__create_stdio_pipe_pair(uv_loop_t* loop, + uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) { + char pipe_name[64]; + SECURITY_ATTRIBUTES sa; + DWORD server_access = 0; + DWORD client_access = 0; + HANDLE child_pipe = INVALID_HANDLE_VALUE; + int err; + + if (flags & UV_READABLE_PIPE) { + /* The server needs inbound access too, otherwise CreateNamedPipe() */ + /* won't give us the FILE_READ_ATTRIBUTES permission. We need that to */ + /* probe the state of the write buffer when we're trying to shutdown */ + /* the pipe. */ + server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND; + client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; + } + if (flags & UV_WRITABLE_PIPE) { + server_access |= PIPE_ACCESS_INBOUND; + client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES; + } + + /* Create server pipe handle. */ + err = uv_stdio_pipe_server(loop, + server_pipe, + server_access, + pipe_name, + sizeof(pipe_name)); + if (err) + goto error; + + /* Create child pipe handle. */ + sa.nLength = sizeof sa; + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + child_pipe = CreateFileA(pipe_name, + client_access, + 0, + &sa, + OPEN_EXISTING, + server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0, + NULL); + if (child_pipe == INVALID_HANDLE_VALUE) { + err = GetLastError(); + goto error; + } + +#ifndef NDEBUG + /* Validate that the pipe was opened in the right mode. */ + { + DWORD mode; + BOOL r = GetNamedPipeHandleState(child_pipe, + &mode, + NULL, + NULL, + NULL, + NULL, + 0); + assert(r == TRUE); + assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT)); + } +#endif + + /* Do a blocking ConnectNamedPipe. This should not block because we have */ + /* both ends of the pipe created. */ + if (!ConnectNamedPipe(server_pipe->handle, NULL)) { + if (GetLastError() != ERROR_PIPE_CONNECTED) { + err = GetLastError(); + goto error; + } + } + + /* The server end is now readable and/or writable. */ + if (flags & UV_READABLE_PIPE) + server_pipe->flags |= UV_HANDLE_WRITABLE; + if (flags & UV_WRITABLE_PIPE) + server_pipe->flags |= UV_HANDLE_READABLE; + + *child_pipe_ptr = child_pipe; + return 0; + + error: + if (server_pipe->handle != INVALID_HANDLE_VALUE) { + uv_pipe_cleanup(loop, server_pipe); + } + + if (child_pipe != INVALID_HANDLE_VALUE) { + CloseHandle(child_pipe); + } + + return err; +} + + +static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) { + HANDLE current_process; + + + /* _get_osfhandle will sometimes return -2 in case of an error. This seems */ + /* to happen when fd <= 2 and the process' corresponding stdio handle is */ + /* set to NULL. Unfortunately DuplicateHandle will happily duplicate */ + /* (HANDLE) -2, so this situation goes unnoticed until someone tries to */ + /* use the duplicate. Therefore we filter out known-invalid handles here. */ + if (handle == INVALID_HANDLE_VALUE || + handle == NULL || + handle == (HANDLE) -2) { + *dup = INVALID_HANDLE_VALUE; + return ERROR_INVALID_HANDLE; + } + + current_process = GetCurrentProcess(); + + if (!DuplicateHandle(current_process, + handle, + current_process, + dup, + 0, + TRUE, + DUPLICATE_SAME_ACCESS)) { + *dup = INVALID_HANDLE_VALUE; + return GetLastError(); + } + + return 0; +} + + +static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) { + HANDLE handle; + + if (fd == -1) { + *dup = INVALID_HANDLE_VALUE; + return ERROR_INVALID_HANDLE; + } + + handle = uv__get_osfhandle(fd); + return uv__duplicate_handle(loop, handle, dup); +} + + +int uv__create_nul_handle(HANDLE* handle_ptr, + DWORD access) { + HANDLE handle; + SECURITY_ATTRIBUTES sa; + + sa.nLength = sizeof sa; + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + handle = CreateFileW(L"NUL", + access, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sa, + OPEN_EXISTING, + 0, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + return GetLastError(); + } + + *handle_ptr = handle; + return 0; +} + + +int uv__stdio_create(uv_loop_t* loop, + const uv_process_options_t* options, + BYTE** buffer_ptr) { + BYTE* buffer; + int count, i; + int err; + + count = options->stdio_count; + + if (count < 0 || count > 255) { + /* Only support FDs 0-255 */ + return ERROR_NOT_SUPPORTED; + } else if (count < 3) { + /* There should always be at least 3 stdio handles. */ + count = 3; + } + + /* Allocate the child stdio buffer */ + buffer = (BYTE*) uv__malloc(CHILD_STDIO_SIZE(count)); + if (buffer == NULL) { + return ERROR_OUTOFMEMORY; + } + + /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */ + /* clean up on failure. */ + CHILD_STDIO_COUNT(buffer) = count; + for (i = 0; i < count; i++) { + CHILD_STDIO_CRT_FLAGS(buffer, i) = 0; + CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE; + } + + for (i = 0; i < count; i++) { + uv_stdio_container_t fdopt; + if (i < options->stdio_count) { + fdopt = options->stdio[i]; + } else { + fdopt.flags = UV_IGNORE; + } + + switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | + UV_INHERIT_STREAM)) { + case UV_IGNORE: + /* Starting a process with no stdin/stout/stderr can confuse it. */ + /* So no matter what the user specified, we make sure the first */ + /* three FDs are always open in their typical modes, e.g. stdin */ + /* be readable and stdout/err should be writable. For FDs > 2, don't */ + /* do anything - all handles in the stdio buffer are initialized with */ + /* INVALID_HANDLE_VALUE, which should be okay. */ + if (i <= 2) { + DWORD access = (i == 0) ? FILE_GENERIC_READ : + FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES; + + err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i), + access); + if (err) + goto error; + + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; + } + break; + + case UV_CREATE_PIPE: { + /* Create a pair of two connected pipe ends; one end is turned into */ + /* an uv_pipe_t for use by the parent. The other one is given to */ + /* the child. */ + uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream; + HANDLE child_pipe = INVALID_HANDLE_VALUE; + + /* Create a new, connected pipe pair. stdio[i].stream should point */ + /* to an uninitialized, but not connected pipe handle. */ + assert(fdopt.data.stream->type == UV_NAMED_PIPE); + assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION)); + assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER)); + + err = uv__create_stdio_pipe_pair(loop, + parent_pipe, + &child_pipe, + fdopt.flags); + if (err) + goto error; + + CHILD_STDIO_HANDLE(buffer, i) = child_pipe; + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE; + break; + } + + case UV_INHERIT_FD: { + /* Inherit a raw FD. */ + HANDLE child_handle; + + /* Make an inheritable duplicate of the handle. */ + err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle); + if (err) { + /* If fdopt.data.fd is not valid and fd fd <= 2, then ignore the */ + /* error. */ + if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) { + CHILD_STDIO_CRT_FLAGS(buffer, i) = 0; + CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE; + break; + } + goto error; + } + + /* Figure out what the type is. */ + switch (GetFileType(child_handle)) { + case FILE_TYPE_DISK: + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN; + break; + + case FILE_TYPE_PIPE: + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE; + + case FILE_TYPE_CHAR: + case FILE_TYPE_REMOTE: + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; + break; + + case FILE_TYPE_UNKNOWN: + if (GetLastError() != 0) { + err = GetLastError(); + CloseHandle(child_handle); + goto error; + } + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; + break; + + default: + assert(0); + return -1; + } + + CHILD_STDIO_HANDLE(buffer, i) = child_handle; + break; + } + + case UV_INHERIT_STREAM: { + /* Use an existing stream as the stdio handle for the child. */ + HANDLE stream_handle, child_handle; + unsigned char crt_flags; + uv_stream_t* stream = fdopt.data.stream; + + /* Leech the handle out of the stream. */ + if (stream->type == UV_TTY) { + stream_handle = ((uv_tty_t*) stream)->handle; + crt_flags = FOPEN | FDEV; + } else if (stream->type == UV_NAMED_PIPE && + stream->flags & UV_HANDLE_CONNECTION) { + stream_handle = ((uv_pipe_t*) stream)->handle; + crt_flags = FOPEN | FPIPE; + } else { + stream_handle = INVALID_HANDLE_VALUE; + crt_flags = 0; + } + + if (stream_handle == NULL || + stream_handle == INVALID_HANDLE_VALUE) { + /* The handle is already closed, or not yet created, or the */ + /* stream type is not supported. */ + err = ERROR_NOT_SUPPORTED; + goto error; + } + + /* Make an inheritable copy of the handle. */ + err = uv__duplicate_handle(loop, stream_handle, &child_handle); + if (err) + goto error; + + CHILD_STDIO_HANDLE(buffer, i) = child_handle; + CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags; + break; + } + + default: + assert(0); + return -1; + } + } + + *buffer_ptr = buffer; + return 0; + + error: + uv__stdio_destroy(buffer); + return err; +} + + +void uv__stdio_destroy(BYTE* buffer) { + int i, count; + + count = CHILD_STDIO_COUNT(buffer); + for (i = 0; i < count; i++) { + HANDLE handle = CHILD_STDIO_HANDLE(buffer, i); + if (handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle); + } + } + + uv__free(buffer); +} + + +void uv__stdio_noinherit(BYTE* buffer) { + int i, count; + + count = CHILD_STDIO_COUNT(buffer); + for (i = 0; i < count; i++) { + HANDLE handle = CHILD_STDIO_HANDLE(buffer, i); + if (handle != INVALID_HANDLE_VALUE) { + SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); + } + } +} + + +int uv__stdio_verify(BYTE* buffer, WORD size) { + unsigned int count; + + /* Check the buffer pointer. */ + if (buffer == NULL) + return 0; + + /* Verify that the buffer is at least big enough to hold the count. */ + if (size < CHILD_STDIO_SIZE(0)) + return 0; + + /* Verify if the count is within range. */ + count = CHILD_STDIO_COUNT(buffer); + if (count > 256) + return 0; + + /* Verify that the buffer size is big enough to hold info for N FDs. */ + if (size < CHILD_STDIO_SIZE(count)) + return 0; + + return 1; +} + + +WORD uv__stdio_size(BYTE* buffer) { + return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer))); +} + + +HANDLE uv__stdio_handle(BYTE* buffer, int fd) { + return CHILD_STDIO_HANDLE(buffer, fd); +} diff --git a/src/win/process.c b/src/win/process.c new file mode 100644 index 0000000..855c374 --- /dev/null +++ b/src/win/process.c @@ -0,0 +1,1247 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include /* alloca */ + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +#define SIGKILL 9 + + +typedef struct env_var { + const WCHAR* const wide; + const WCHAR* const wide_eq; + const size_t len; /* including null or '=' */ +} env_var_t; + +#define E_V(str) { L##str, L##str L"=", sizeof(str) } + +static const env_var_t required_vars[] = { /* keep me sorted */ + E_V("HOMEDRIVE"), + E_V("HOMEPATH"), + E_V("LOGONSERVER"), + E_V("PATH"), + E_V("SYSTEMDRIVE"), + E_V("SYSTEMROOT"), + E_V("TEMP"), + E_V("USERDOMAIN"), + E_V("USERNAME"), + E_V("USERPROFILE"), + E_V("WINDIR"), +}; +static size_t n_required_vars = ARRAY_SIZE(required_vars); + + +static HANDLE uv_global_job_handle_; +static uv_once_t uv_global_job_handle_init_guard_ = UV_ONCE_INIT; + + +static void uv__init_global_job_handle(void) { + /* Create a job object and set it up to kill all contained processes when + * it's closed. Since this handle is made non-inheritable and we're not + * giving it to anyone, we're the only process holding a reference to it. + * That means that if this process exits it is closed and all the processes + * it contains are killed. All processes created with uv_spawn that are not + * spawned with the UV_PROCESS_DETACHED flag are assigned to this job. + * + * We're setting the JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag so only the + * processes that we explicitly add are affected, and *their* subprocesses + * are not. This ensures that our child processes are not limited in their + * ability to use job control on Windows versions that don't deal with + * nested jobs (prior to Windows 8 / Server 2012). It also lets our child + * processes created detached processes without explicitly breaking away + * from job control (which uv_spawn doesn't, either). + */ + SECURITY_ATTRIBUTES attr; + JOBOBJECT_EXTENDED_LIMIT_INFORMATION info; + + memset(&attr, 0, sizeof attr); + attr.bInheritHandle = FALSE; + + memset(&info, 0, sizeof info); + info.BasicLimitInformation.LimitFlags = + JOB_OBJECT_LIMIT_BREAKAWAY_OK | + JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK | + JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION | + JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + + uv_global_job_handle_ = CreateJobObjectW(&attr, NULL); + if (uv_global_job_handle_ == NULL) + uv_fatal_error(GetLastError(), "CreateJobObjectW"); + + if (!SetInformationJobObject(uv_global_job_handle_, + JobObjectExtendedLimitInformation, + &info, + sizeof info)) + uv_fatal_error(GetLastError(), "SetInformationJobObject"); +} + + +static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) { + int ws_len, r; + WCHAR* ws; + + ws_len = MultiByteToWideChar(CP_UTF8, + 0, + s, + -1, + NULL, + 0); + if (ws_len <= 0) { + return GetLastError(); + } + + ws = (WCHAR*) uv__malloc(ws_len * sizeof(WCHAR)); + if (ws == NULL) { + return ERROR_OUTOFMEMORY; + } + + r = MultiByteToWideChar(CP_UTF8, + 0, + s, + -1, + ws, + ws_len); + assert(r == ws_len); + + *ws_ptr = ws; + return 0; +} + + +static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) { + uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS); + handle->exit_cb = NULL; + handle->pid = 0; + handle->exit_signal = 0; + handle->wait_handle = INVALID_HANDLE_VALUE; + handle->process_handle = INVALID_HANDLE_VALUE; + handle->child_stdio_buffer = NULL; + handle->exit_cb_pending = 0; + + uv_req_init(loop, (uv_req_t*)&handle->exit_req); + handle->exit_req.type = UV_PROCESS_EXIT; + handle->exit_req.data = handle; +} + + +/* + * Path search functions + */ + +/* + * Helper function for search_path + */ +static WCHAR* search_path_join_test(const WCHAR* dir, + size_t dir_len, + const WCHAR* name, + size_t name_len, + const WCHAR* ext, + size_t ext_len, + const WCHAR* cwd, + size_t cwd_len) { + WCHAR *result, *result_pos; + DWORD attrs; + if (dir_len > 2 && dir[0] == L'\\' && dir[1] == L'\\') { + /* It's a UNC path so ignore cwd */ + cwd_len = 0; + } else if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) { + /* It's a full path without drive letter, use cwd's drive letter only */ + cwd_len = 2; + } else if (dir_len >= 2 && dir[1] == L':' && + (dir_len < 3 || (dir[2] != L'/' && dir[2] != L'\\'))) { + /* It's a relative path with drive letter (ext.g. D:../some/file) + * Replace drive letter in dir by full cwd if it points to the same drive, + * otherwise use the dir only. + */ + if (cwd_len < 2 || _wcsnicmp(cwd, dir, 2) != 0) { + cwd_len = 0; + } else { + dir += 2; + dir_len -= 2; + } + } else if (dir_len > 2 && dir[1] == L':') { + /* It's an absolute path with drive letter + * Don't use the cwd at all + */ + cwd_len = 0; + } + + /* Allocate buffer for output */ + result = result_pos = (WCHAR*)uv__malloc(sizeof(WCHAR) * + (cwd_len + 1 + dir_len + 1 + name_len + 1 + ext_len + 1)); + + /* Copy cwd */ + wcsncpy(result_pos, cwd, cwd_len); + result_pos += cwd_len; + + /* Add a path separator if cwd didn't end with one */ + if (cwd_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) { + result_pos[0] = L'\\'; + result_pos++; + } + + /* Copy dir */ + wcsncpy(result_pos, dir, dir_len); + result_pos += dir_len; + + /* Add a separator if the dir didn't end with one */ + if (dir_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) { + result_pos[0] = L'\\'; + result_pos++; + } + + /* Copy filename */ + wcsncpy(result_pos, name, name_len); + result_pos += name_len; + + if (ext_len) { + /* Add a dot if the filename didn't end with one */ + if (name_len && result_pos[-1] != '.') { + result_pos[0] = L'.'; + result_pos++; + } + + /* Copy extension */ + wcsncpy(result_pos, ext, ext_len); + result_pos += ext_len; + } + + /* Null terminator */ + result_pos[0] = L'\0'; + + attrs = GetFileAttributesW(result); + + if (attrs != INVALID_FILE_ATTRIBUTES && + !(attrs & FILE_ATTRIBUTE_DIRECTORY)) { + return result; + } + + uv__free(result); + return NULL; +} + + +/* + * Helper function for search_path + */ +static WCHAR* path_search_walk_ext(const WCHAR *dir, + size_t dir_len, + const WCHAR *name, + size_t name_len, + WCHAR *cwd, + size_t cwd_len, + int name_has_ext) { + WCHAR* result; + + /* If the name itself has a nonempty extension, try this extension first */ + if (name_has_ext) { + result = search_path_join_test(dir, dir_len, + name, name_len, + L"", 0, + cwd, cwd_len); + if (result != NULL) { + return result; + } + } + + /* Try .com extension */ + result = search_path_join_test(dir, dir_len, + name, name_len, + L"com", 3, + cwd, cwd_len); + if (result != NULL) { + return result; + } + + /* Try .exe extension */ + result = search_path_join_test(dir, dir_len, + name, name_len, + L"exe", 3, + cwd, cwd_len); + if (result != NULL) { + return result; + } + + return NULL; +} + + +/* + * search_path searches the system path for an executable filename - + * the windows API doesn't provide this as a standalone function nor as an + * option to CreateProcess. + * + * It tries to return an absolute filename. + * + * Furthermore, it tries to follow the semantics that cmd.exe, with this + * exception that PATHEXT environment variable isn't used. Since CreateProcess + * can start only .com and .exe files, only those extensions are tried. This + * behavior equals that of msvcrt's spawn functions. + * + * - Do not search the path if the filename already contains a path (either + * relative or absolute). + * + * - If there's really only a filename, check the current directory for file, + * then search all path directories. + * + * - If filename specified has *any* extension, search for the file with the + * specified extension first. + * + * - If the literal filename is not found in a directory, try *appending* + * (not replacing) .com first and then .exe. + * + * - The path variable may contain relative paths; relative paths are relative + * to the cwd. + * + * - Directories in path may or may not end with a trailing backslash. + * + * - CMD does not trim leading/trailing whitespace from path/pathex entries + * nor from the environment variables as a whole. + * + * - When cmd.exe cannot read a directory, it will just skip it and go on + * searching. However, unlike posix-y systems, it will happily try to run a + * file that is not readable/executable; if the spawn fails it will not + * continue searching. + * + * UNC path support: we are dealing with UNC paths in both the path and the + * filename. This is a deviation from what cmd.exe does (it does not let you + * start a program by specifying an UNC path on the command line) but this is + * really a pointless restriction. + * + */ +static WCHAR* search_path(const WCHAR *file, + WCHAR *cwd, + const WCHAR *path) { + int file_has_dir; + WCHAR* result = NULL; + WCHAR *file_name_start; + WCHAR *dot; + const WCHAR *dir_start, *dir_end, *dir_path; + size_t dir_len; + int name_has_ext; + + size_t file_len = wcslen(file); + size_t cwd_len = wcslen(cwd); + + /* If the caller supplies an empty filename, + * we're not gonna return c:\windows\.exe -- GFY! + */ + if (file_len == 0 + || (file_len == 1 && file[0] == L'.')) { + return NULL; + } + + /* Find the start of the filename so we can split the directory from the */ + /* name. */ + for (file_name_start = (WCHAR*)file + file_len; + file_name_start > file + && file_name_start[-1] != L'\\' + && file_name_start[-1] != L'/' + && file_name_start[-1] != L':'; + file_name_start--); + + file_has_dir = file_name_start != file; + + /* Check if the filename includes an extension */ + dot = wcschr(file_name_start, L'.'); + name_has_ext = (dot != NULL && dot[1] != L'\0'); + + if (file_has_dir) { + /* The file has a path inside, don't use path */ + result = path_search_walk_ext( + file, file_name_start - file, + file_name_start, file_len - (file_name_start - file), + cwd, cwd_len, + name_has_ext); + + } else { + dir_end = path; + + /* The file is really only a name; look in cwd first, then scan path */ + result = path_search_walk_ext(L"", 0, + file, file_len, + cwd, cwd_len, + name_has_ext); + + while (result == NULL) { + if (*dir_end == L'\0') { + break; + } + + /* Skip the separator that dir_end now points to */ + if (dir_end != path || *path == L';') { + dir_end++; + } + + /* Next slice starts just after where the previous one ended */ + dir_start = dir_end; + + /* Slice until the next ; or \0 is found */ + dir_end = wcschr(dir_start, L';'); + if (dir_end == NULL) { + dir_end = wcschr(dir_start, L'\0'); + } + + /* If the slice is zero-length, don't bother */ + if (dir_end - dir_start == 0) { + continue; + } + + dir_path = dir_start; + dir_len = dir_end - dir_start; + + /* Adjust if the path is quoted. */ + if (dir_path[0] == '"' || dir_path[0] == '\'') { + ++dir_path; + --dir_len; + } + + if (dir_path[dir_len - 1] == '"' || dir_path[dir_len - 1] == '\'') { + --dir_len; + } + + result = path_search_walk_ext(dir_path, dir_len, + file, file_len, + cwd, cwd_len, + name_has_ext); + } + } + + return result; +} + + +/* + * Quotes command line arguments + * Returns a pointer to the end (next char to be written) of the buffer + */ +WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) { + size_t len = wcslen(source); + size_t i; + int quote_hit; + WCHAR* start; + + if (len == 0) { + /* Need double quotation for empty argument */ + *(target++) = L'"'; + *(target++) = L'"'; + return target; + } + + if (NULL == wcspbrk(source, L" \t\"")) { + /* No quotation needed */ + wcsncpy(target, source, len); + target += len; + return target; + } + + if (NULL == wcspbrk(source, L"\"\\")) { + /* + * No embedded double quotes or backlashes, so I can just wrap + * quote marks around the whole thing. + */ + *(target++) = L'"'; + wcsncpy(target, source, len); + target += len; + *(target++) = L'"'; + return target; + } + + /* + * Expected input/output: + * input : hello"world + * output: "hello\"world" + * input : hello""world + * output: "hello\"\"world" + * input : hello\world + * output: hello\world + * input : hello\\world + * output: hello\\world + * input : hello\"world + * output: "hello\\\"world" + * input : hello\\"world + * output: "hello\\\\\"world" + * input : hello world\ + * output: "hello world\" + */ + + *(target++) = L'"'; + start = target; + quote_hit = 1; + + for (i = len; i > 0; --i) { + *(target++) = source[i - 1]; + + if (quote_hit && source[i - 1] == L'\\') { + *(target++) = L'\\'; + } else if(source[i - 1] == L'"') { + quote_hit = 1; + *(target++) = L'\\'; + } else { + quote_hit = 0; + } + } + target[0] = L'\0'; + wcsrev(start); + *(target++) = L'"'; + return target; +} + + +int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) { + char** arg; + WCHAR* dst = NULL; + WCHAR* temp_buffer = NULL; + size_t dst_len = 0; + size_t temp_buffer_len = 0; + WCHAR* pos; + int arg_count = 0; + int err = 0; + + /* Count the required size. */ + for (arg = args; *arg; arg++) { + DWORD arg_len; + + arg_len = MultiByteToWideChar(CP_UTF8, + 0, + *arg, + -1, + NULL, + 0); + if (arg_len == 0) { + return GetLastError(); + } + + dst_len += arg_len; + + if (arg_len > temp_buffer_len) + temp_buffer_len = arg_len; + + arg_count++; + } + + /* Adjust for potential quotes. Also assume the worst-case scenario */ + /* that every character needs escaping, so we need twice as much space. */ + dst_len = dst_len * 2 + arg_count * 2; + + /* Allocate buffer for the final command line. */ + dst = (WCHAR*) uv__malloc(dst_len * sizeof(WCHAR)); + if (dst == NULL) { + err = ERROR_OUTOFMEMORY; + goto error; + } + + /* Allocate temporary working buffer. */ + temp_buffer = (WCHAR*) uv__malloc(temp_buffer_len * sizeof(WCHAR)); + if (temp_buffer == NULL) { + err = ERROR_OUTOFMEMORY; + goto error; + } + + pos = dst; + for (arg = args; *arg; arg++) { + DWORD arg_len; + + /* Convert argument to wide char. */ + arg_len = MultiByteToWideChar(CP_UTF8, + 0, + *arg, + -1, + temp_buffer, + (int) (dst + dst_len - pos)); + if (arg_len == 0) { + err = GetLastError(); + goto error; + } + + if (verbatim_arguments) { + /* Copy verbatim. */ + wcscpy(pos, temp_buffer); + pos += arg_len - 1; + } else { + /* Quote/escape, if needed. */ + pos = quote_cmd_arg(temp_buffer, pos); + } + + *pos++ = *(arg + 1) ? L' ' : L'\0'; + } + + uv__free(temp_buffer); + + *dst_ptr = dst; + return 0; + +error: + uv__free(dst); + uv__free(temp_buffer); + return err; +} + + +int env_strncmp(const wchar_t* a, int na, const wchar_t* b) { + wchar_t* a_eq; + wchar_t* b_eq; + wchar_t* A; + wchar_t* B; + int nb; + int r; + + if (na < 0) { + a_eq = wcschr(a, L'='); + assert(a_eq); + na = (int)(long)(a_eq - a); + } else { + na--; + } + b_eq = wcschr(b, L'='); + assert(b_eq); + nb = b_eq - b; + + A = alloca((na+1) * sizeof(wchar_t)); + B = alloca((nb+1) * sizeof(wchar_t)); + + r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, a, na, A, na); + assert(r==na); + A[na] = L'\0'; + r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, b, nb, B, nb); + assert(r==nb); + B[nb] = L'\0'; + + while (1) { + wchar_t AA = *A++; + wchar_t BB = *B++; + if (AA < BB) { + return -1; + } else if (AA > BB) { + return 1; + } else if (!AA && !BB) { + return 0; + } + } +} + + +static int qsort_wcscmp(const void *a, const void *b) { + wchar_t* astr = *(wchar_t* const*)a; + wchar_t* bstr = *(wchar_t* const*)b; + return env_strncmp(astr, -1, bstr); +} + + +/* + * The way windows takes environment variables is different than what C does; + * Windows wants a contiguous block of null-terminated strings, terminated + * with an additional null. + * + * Windows has a few "essential" environment variables. winsock will fail + * to initialize if SYSTEMROOT is not defined; some APIs make reference to + * TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that + * these get defined if the input environment block does not contain any + * values for them. + * + * Also add variables known to Cygwin to be required for correct + * subprocess operation in many cases: + * https://github.com/Alexpux/Cygwin/blob/b266b04fbbd3a595f02ea149e4306d3ab9b1fe3d/winsup/cygwin/environ.cc#L955 + * + */ +int make_program_env(char* env_block[], WCHAR** dst_ptr) { + WCHAR* dst; + WCHAR* ptr; + char** env; + size_t env_len = 0; + int len; + size_t i; + DWORD var_size; + size_t env_block_count = 1; /* 1 for null-terminator */ + WCHAR* dst_copy; + WCHAR** ptr_copy; + WCHAR** env_copy; + DWORD* required_vars_value_len = alloca(n_required_vars * sizeof(DWORD*)); + + /* first pass: determine size in UTF-16 */ + for (env = env_block; *env; env++) { + int len; + if (strchr(*env, '=')) { + len = MultiByteToWideChar(CP_UTF8, + 0, + *env, + -1, + NULL, + 0); + if (len <= 0) { + return GetLastError(); + } + env_len += len; + env_block_count++; + } + } + + /* second pass: copy to UTF-16 environment block */ + dst_copy = (WCHAR*)uv__malloc(env_len * sizeof(WCHAR)); + if (!dst_copy) { + return ERROR_OUTOFMEMORY; + } + env_copy = alloca(env_block_count * sizeof(WCHAR*)); + + ptr = dst_copy; + ptr_copy = env_copy; + for (env = env_block; *env; env++) { + if (strchr(*env, '=')) { + len = MultiByteToWideChar(CP_UTF8, + 0, + *env, + -1, + ptr, + (int) (env_len - (ptr - dst_copy))); + if (len <= 0) { + DWORD err = GetLastError(); + uv__free(dst_copy); + return err; + } + *ptr_copy++ = ptr; + ptr += len; + } + } + *ptr_copy = NULL; + assert(env_len == ptr - dst_copy); + + /* sort our (UTF-16) copy */ + qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp); + + /* third pass: check for required variables */ + for (ptr_copy = env_copy, i = 0; i < n_required_vars; ) { + int cmp; + if (!*ptr_copy) { + cmp = -1; + } else { + cmp = env_strncmp(required_vars[i].wide_eq, + required_vars[i].len, + *ptr_copy); + } + if (cmp < 0) { + /* missing required var */ + var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0); + required_vars_value_len[i] = var_size; + if (var_size != 0) { + env_len += required_vars[i].len; + env_len += var_size; + } + i++; + } else { + ptr_copy++; + if (cmp == 0) + i++; + } + } + + /* final pass: copy, in sort order, and inserting required variables */ + dst = uv__malloc((1+env_len) * sizeof(WCHAR)); + if (!dst) { + uv__free(dst_copy); + return ERROR_OUTOFMEMORY; + } + + for (ptr = dst, ptr_copy = env_copy, i = 0; + *ptr_copy || i < n_required_vars; + ptr += len) { + int cmp; + if (i >= n_required_vars) { + cmp = 1; + } else if (!*ptr_copy) { + cmp = -1; + } else { + cmp = env_strncmp(required_vars[i].wide_eq, + required_vars[i].len, + *ptr_copy); + } + if (cmp < 0) { + /* missing required var */ + len = required_vars_value_len[i]; + if (len) { + wcscpy(ptr, required_vars[i].wide_eq); + ptr += required_vars[i].len; + var_size = GetEnvironmentVariableW(required_vars[i].wide, + ptr, + (int) (env_len - (ptr - dst))); + if (var_size != len-1) { /* race condition? */ + uv_fatal_error(GetLastError(), "GetEnvironmentVariableW"); + } + } + i++; + } else { + /* copy var from env_block */ + len = wcslen(*ptr_copy) + 1; + wmemcpy(ptr, *ptr_copy, len); + ptr_copy++; + if (cmp == 0) + i++; + } + } + + /* Terminate with an extra NULL. */ + assert(env_len == (ptr - dst)); + *ptr = L'\0'; + + uv__free(dst_copy); + *dst_ptr = dst; + return 0; +} + +/* + * Attempt to find the value of the PATH environment variable in the child's + * preprocessed environment. + * + * If found, a pointer into `env` is returned. If not found, NULL is returned. + */ +static WCHAR* find_path(WCHAR *env) { + for (; env != NULL && *env != 0; env += wcslen(env) + 1) { + if (wcsncmp(env, L"PATH=", 5) == 0) + return &env[5]; + } + + return NULL; +} + +/* + * Called on Windows thread-pool thread to indicate that + * a child process has exited. + */ +static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) { + uv_process_t* process = (uv_process_t*) data; + uv_loop_t* loop = process->loop; + + assert(didTimeout == FALSE); + assert(process); + assert(!process->exit_cb_pending); + + process->exit_cb_pending = 1; + + /* Post completed */ + POST_COMPLETION_FOR_REQ(loop, &process->exit_req); +} + + +/* Called on main thread after a child process has exited. */ +void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { + int64_t exit_code; + DWORD status; + + assert(handle->exit_cb_pending); + handle->exit_cb_pending = 0; + + /* If we're closing, don't call the exit callback. Just schedule a close */ + /* callback now. */ + if (handle->flags & UV__HANDLE_CLOSING) { + uv_want_endgame(loop, (uv_handle_t*) handle); + return; + } + + /* Unregister from process notification. */ + if (handle->wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(handle->wait_handle); + handle->wait_handle = INVALID_HANDLE_VALUE; + } + + /* Set the handle to inactive: no callbacks will be made after the exit */ + /* callback.*/ + uv__handle_stop(handle); + + if (GetExitCodeProcess(handle->process_handle, &status)) { + exit_code = status; + } else { + /* Unable to to obtain the exit code. This should never happen. */ + exit_code = uv_translate_sys_error(GetLastError()); + } + + /* Fire the exit callback. */ + if (handle->exit_cb) { + handle->exit_cb(handle, exit_code, handle->exit_signal); + } +} + + +void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { + uv__handle_closing(handle); + + if (handle->wait_handle != INVALID_HANDLE_VALUE) { + /* This blocks until either the wait was cancelled, or the callback has */ + /* completed. */ + BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE); + if (!r) { + /* This should never happen, and if it happens, we can't recover... */ + uv_fatal_error(GetLastError(), "UnregisterWaitEx"); + } + + handle->wait_handle = INVALID_HANDLE_VALUE; + } + + if (!handle->exit_cb_pending) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } +} + + +void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) { + assert(!handle->exit_cb_pending); + assert(handle->flags & UV__HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + /* Clean-up the process handle. */ + CloseHandle(handle->process_handle); + + uv__handle_close(handle); +} + + +int uv_spawn(uv_loop_t* loop, + uv_process_t* process, + const uv_process_options_t* options) { + int i; + int err = 0; + WCHAR* path = NULL, *alloc_path = NULL; + BOOL result; + WCHAR* application_path = NULL, *application = NULL, *arguments = NULL, + *env = NULL, *cwd = NULL; + STARTUPINFOW startup; + PROCESS_INFORMATION info; + DWORD process_flags; + + uv_process_init(loop, process); + process->exit_cb = options->exit_cb; + + if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) { + return UV_ENOTSUP; + } + + if (options->file == NULL || + options->args == NULL) { + return UV_EINVAL; + } + + assert(options->file != NULL); + assert(!(options->flags & ~(UV_PROCESS_DETACHED | + UV_PROCESS_SETGID | + UV_PROCESS_SETUID | + UV_PROCESS_WINDOWS_HIDE | + UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); + + err = uv_utf8_to_utf16_alloc(options->file, &application); + if (err) + goto done; + + err = make_program_args( + options->args, + options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS, + &arguments); + if (err) + goto done; + + if (options->env) { + err = make_program_env(options->env, &env); + if (err) + goto done; + } + + if (options->cwd) { + /* Explicit cwd */ + err = uv_utf8_to_utf16_alloc(options->cwd, &cwd); + if (err) + goto done; + + } else { + /* Inherit cwd */ + DWORD cwd_len, r; + + cwd_len = GetCurrentDirectoryW(0, NULL); + if (!cwd_len) { + err = GetLastError(); + goto done; + } + + cwd = (WCHAR*) uv__malloc(cwd_len * sizeof(WCHAR)); + if (cwd == NULL) { + err = ERROR_OUTOFMEMORY; + goto done; + } + + r = GetCurrentDirectoryW(cwd_len, cwd); + if (r == 0 || r >= cwd_len) { + err = GetLastError(); + goto done; + } + } + + /* Get PATH environment variable. */ + path = find_path(env); + if (path == NULL) { + DWORD path_len, r; + + path_len = GetEnvironmentVariableW(L"PATH", NULL, 0); + if (path_len == 0) { + err = GetLastError(); + goto done; + } + + alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR)); + if (alloc_path == NULL) { + err = ERROR_OUTOFMEMORY; + goto done; + } + path = alloc_path; + + r = GetEnvironmentVariableW(L"PATH", path, path_len); + if (r == 0 || r >= path_len) { + err = GetLastError(); + goto done; + } + } + + err = uv__stdio_create(loop, options, &process->child_stdio_buffer); + if (err) + goto done; + + application_path = search_path(application, + cwd, + path); + if (application_path == NULL) { + /* Not found. */ + err = ERROR_FILE_NOT_FOUND; + goto done; + } + + startup.cb = sizeof(startup); + startup.lpReserved = NULL; + startup.lpDesktop = NULL; + startup.lpTitle = NULL; + startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + + startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer); + startup.lpReserved2 = (BYTE*) process->child_stdio_buffer; + + startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0); + startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1); + startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2); + + if (options->flags & UV_PROCESS_WINDOWS_HIDE) { + /* Use SW_HIDE to avoid any potential process window. */ + startup.wShowWindow = SW_HIDE; + } else { + startup.wShowWindow = SW_SHOWDEFAULT; + } + + process_flags = CREATE_UNICODE_ENVIRONMENT; + + if (options->flags & UV_PROCESS_DETACHED) { + /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That + * means that libuv might not let you create a fully daemonized process + * when run under job control. However the type of job control that libuv + * itself creates doesn't trickle down to subprocesses so they can still + * daemonize. + * + * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the + * CreateProcess call fail if we're under job control that doesn't allow + * breakaway. + */ + process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; + } + + if (!CreateProcessW(application_path, + arguments, + NULL, + NULL, + 1, + process_flags, + env, + cwd, + &startup, + &info)) { + /* CreateProcessW failed. */ + err = GetLastError(); + goto done; + } + + /* Spawn succeeded */ + /* Beyond this point, failure is reported asynchronously. */ + + process->process_handle = info.hProcess; + process->pid = info.dwProcessId; + + /* If the process isn't spawned as detached, assign to the global job */ + /* object so windows will kill it when the parent process dies. */ + if (!(options->flags & UV_PROCESS_DETACHED)) { + uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle); + + if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) { + /* AssignProcessToJobObject might fail if this process is under job + * control and the job doesn't have the + * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version + * that doesn't support nested jobs. + * + * When that happens we just swallow the error and continue without + * establishing a kill-child-on-parent-exit relationship, otherwise + * there would be no way for libuv applications run under job control + * to spawn processes at all. + */ + DWORD err = GetLastError(); + if (err != ERROR_ACCESS_DENIED) + uv_fatal_error(err, "AssignProcessToJobObject"); + } + } + + /* Set IPC pid to all IPC pipes. */ + for (i = 0; i < options->stdio_count; i++) { + const uv_stdio_container_t* fdopt = &options->stdio[i]; + if (fdopt->flags & UV_CREATE_PIPE && + fdopt->data.stream->type == UV_NAMED_PIPE && + ((uv_pipe_t*) fdopt->data.stream)->ipc) { + ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId; + } + } + + /* Setup notifications for when the child process exits. */ + result = RegisterWaitForSingleObject(&process->wait_handle, + process->process_handle, exit_wait_callback, (void*)process, INFINITE, + WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE); + if (!result) { + uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject"); + } + + CloseHandle(info.hThread); + + assert(!err); + + /* Make the handle active. It will remain active until the exit callback */ + /* is made or the handle is closed, whichever happens first. */ + uv__handle_start(process); + + /* Cleanup, whether we succeeded or failed. */ + done: + uv__free(application); + uv__free(application_path); + uv__free(arguments); + uv__free(cwd); + uv__free(env); + uv__free(alloc_path); + + if (process->child_stdio_buffer != NULL) { + /* Clean up child stdio handles. */ + uv__stdio_destroy(process->child_stdio_buffer); + process->child_stdio_buffer = NULL; + } + + return uv_translate_sys_error(err); +} + + +static int uv__kill(HANDLE process_handle, int signum) { + switch (signum) { + case SIGTERM: + case SIGKILL: + case SIGINT: { + /* Unconditionally terminate the process. On Windows, killed processes */ + /* normally return 1. */ + DWORD status; + int err; + + if (TerminateProcess(process_handle, 1)) + return 0; + + /* If the process already exited before TerminateProcess was called, */ + /* TerminateProcess will fail with ERROR_ACCESS_DENIED. */ + err = GetLastError(); + if (err == ERROR_ACCESS_DENIED && + GetExitCodeProcess(process_handle, &status) && + status != STILL_ACTIVE) { + return UV_ESRCH; + } + + return uv_translate_sys_error(err); + } + + case 0: { + /* Health check: is the process still alive? */ + DWORD status; + + if (!GetExitCodeProcess(process_handle, &status)) + return uv_translate_sys_error(GetLastError()); + + if (status != STILL_ACTIVE) + return UV_ESRCH; + + return 0; + } + + default: + /* Unsupported signal. */ + return UV_ENOSYS; + } +} + + +int uv_process_kill(uv_process_t* process, int signum) { + int err; + + if (process->process_handle == INVALID_HANDLE_VALUE) { + return UV_EINVAL; + } + + err = uv__kill(process->process_handle, signum); + if (err) { + return err; /* err is already translated. */ + } + + process->exit_signal = signum; + + return 0; +} + + +int uv_kill(int pid, int signum) { + int err; + HANDLE process_handle = OpenProcess(PROCESS_TERMINATE | + PROCESS_QUERY_INFORMATION, FALSE, pid); + + if (process_handle == NULL) { + err = GetLastError(); + if (err == ERROR_INVALID_PARAMETER) { + return UV_ESRCH; + } else { + return uv_translate_sys_error(err); + } + } + + err = uv__kill(process_handle, signum); + CloseHandle(process_handle); + + return err; /* err is already translated. */ +} diff --git a/src/win/req-inl.h b/src/win/req-inl.h new file mode 100644 index 0000000..b5e502e --- /dev/null +++ b/src/win/req-inl.h @@ -0,0 +1,224 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_WIN_REQ_INL_H_ +#define UV_WIN_REQ_INL_H_ + +#include + +#include "uv.h" +#include "internal.h" + + +#define SET_REQ_STATUS(req, status) \ + (req)->u.io.overlapped.Internal = (ULONG_PTR) (status) + +#define SET_REQ_ERROR(req, error) \ + SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error))) + +#define SET_REQ_SUCCESS(req) \ + SET_REQ_STATUS((req), STATUS_SUCCESS) + +#define GET_REQ_STATUS(req) \ + ((NTSTATUS) (req)->u.io.overlapped.Internal) + +#define REQ_SUCCESS(req) \ + (NT_SUCCESS(GET_REQ_STATUS((req)))) + +#define GET_REQ_ERROR(req) \ + (pRtlNtStatusToDosError(GET_REQ_STATUS((req)))) + +#define GET_REQ_SOCK_ERROR(req) \ + (uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req)))) + + +#define REGISTER_HANDLE_REQ(loop, handle, req) \ + do { \ + INCREASE_ACTIVE_COUNT((loop), (handle)); \ + uv__req_register((loop), (req)); \ + } while (0) + +#define UNREGISTER_HANDLE_REQ(loop, handle, req) \ + do { \ + DECREASE_ACTIVE_COUNT((loop), (handle)); \ + uv__req_unregister((loop), (req)); \ + } while (0) + + +#define UV_SUCCEEDED_WITHOUT_IOCP(result) \ + ((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP)) + +#define UV_SUCCEEDED_WITH_IOCP(result) \ + ((result) || (GetLastError() == ERROR_IO_PENDING)) + + +#define POST_COMPLETION_FOR_REQ(loop, req) \ + if (!PostQueuedCompletionStatus((loop)->iocp, \ + 0, \ + 0, \ + &((req)->u.io.overlapped))) { \ + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \ + } + + +INLINE static void uv_req_init(uv_loop_t* loop, uv_req_t* req) { + req->type = UV_UNKNOWN_REQ; + SET_REQ_SUCCESS(req); +} + + +INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) { + return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped); +} + + +INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) { + req->next_req = NULL; + if (loop->pending_reqs_tail) { +#ifdef _DEBUG + /* Ensure the request is not already in the queue, or the queue + * will get corrupted. + */ + uv_req_t* current = loop->pending_reqs_tail; + do { + assert(req != current); + current = current->next_req; + } while(current != loop->pending_reqs_tail); +#endif + + req->next_req = loop->pending_reqs_tail->next_req; + loop->pending_reqs_tail->next_req = req; + loop->pending_reqs_tail = req; + } else { + req->next_req = req; + loop->pending_reqs_tail = req; + } +} + + +#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \ + do { \ + switch (((uv_handle_t*) (req)->handle_at)->type) { \ + case UV_TCP: \ + uv_process_tcp_##method##_req(loop, \ + (uv_tcp_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + case UV_NAMED_PIPE: \ + uv_process_pipe_##method##_req(loop, \ + (uv_pipe_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + case UV_TTY: \ + uv_process_tty_##method##_req(loop, \ + (uv_tty_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + default: \ + assert(0); \ + } \ + } while (0) + + +INLINE static int uv_process_reqs(uv_loop_t* loop) { + uv_req_t* req; + uv_req_t* first; + uv_req_t* next; + + if (loop->pending_reqs_tail == NULL) + return 0; + + first = loop->pending_reqs_tail->next_req; + next = first; + loop->pending_reqs_tail = NULL; + + while (next != NULL) { + req = next; + next = req->next_req != first ? req->next_req : NULL; + + switch (req->type) { + case UV_READ: + DELEGATE_STREAM_REQ(loop, req, read, data); + break; + + case UV_WRITE: + DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle); + break; + + case UV_ACCEPT: + DELEGATE_STREAM_REQ(loop, req, accept, data); + break; + + case UV_CONNECT: + DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle); + break; + + case UV_SHUTDOWN: + /* Tcp shutdown requests don't come here. */ + assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE); + uv_process_pipe_shutdown_req( + loop, + (uv_pipe_t*) ((uv_shutdown_t*) req)->handle, + (uv_shutdown_t*) req); + break; + + case UV_UDP_RECV: + uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req); + break; + + case UV_UDP_SEND: + uv_process_udp_send_req(loop, + ((uv_udp_send_t*) req)->handle, + (uv_udp_send_t*) req); + break; + + case UV_WAKEUP: + uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req); + break; + + case UV_SIGNAL_REQ: + uv_process_signal_req(loop, (uv_signal_t*) req->data, req); + break; + + case UV_POLL_REQ: + uv_process_poll_req(loop, (uv_poll_t*) req->data, req); + break; + + case UV_PROCESS_EXIT: + uv_process_proc_exit(loop, (uv_process_t*) req->data); + break; + + case UV_FS_EVENT_REQ: + uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data); + break; + + default: + assert(0); + } + } + + return 1; +} + +#endif /* UV_WIN_REQ_INL_H_ */ diff --git a/src/win/req.c b/src/win/req.c new file mode 100644 index 0000000..111cc5e --- /dev/null +++ b/src/win/req.c @@ -0,0 +1,25 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include + +#include "uv.h" +#include "internal.h" diff --git a/src/win/signal.c b/src/win/signal.c new file mode 100644 index 0000000..2c64a55 --- /dev/null +++ b/src/win/signal.c @@ -0,0 +1,356 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +RB_HEAD(uv_signal_tree_s, uv_signal_s); + +static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree); +static ssize_t volatile uv__signal_control_handler_refs = 0; +static CRITICAL_SECTION uv__signal_lock; + + +void uv_signals_init() { + InitializeCriticalSection(&uv__signal_lock); +} + + +static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { + /* Compare signums first so all watchers with the same signnum end up */ + /* adjacent. */ + if (w1->signum < w2->signum) return -1; + if (w1->signum > w2->signum) return 1; + + /* Sort by loop pointer, so we can easily look up the first item after */ + /* { .signum = x, .loop = NULL } */ + if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1; + if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1; + + if ((uintptr_t) w1 < (uintptr_t) w2) return -1; + if ((uintptr_t) w1 > (uintptr_t) w2) return 1; + + return 0; +} + + +RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare); + + +/* + * Dispatches signal {signum} to all active uv_signal_t watchers in all loops. + * Returns 1 if the signal was dispatched to any watcher, or 0 if there were + * no active signal watchers observing this signal. + */ +int uv__signal_dispatch(int signum) { + uv_signal_t lookup; + uv_signal_t* handle; + int dispatched = 0; + + EnterCriticalSection(&uv__signal_lock); + + lookup.signum = signum; + lookup.loop = NULL; + + for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup); + handle != NULL && handle->signum == signum; + handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) { + unsigned long previous = InterlockedExchange( + (volatile LONG*) &handle->pending_signum, signum); + + if (!previous) { + POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req); + } + + dispatched = 1; + } + + LeaveCriticalSection(&uv__signal_lock); + + return dispatched; +} + + +static BOOL WINAPI uv__signal_control_handler(DWORD type) { + switch (type) { + case CTRL_C_EVENT: + return uv__signal_dispatch(SIGINT); + + case CTRL_BREAK_EVENT: + return uv__signal_dispatch(SIGBREAK); + + case CTRL_CLOSE_EVENT: + if (uv__signal_dispatch(SIGHUP)) { + /* Windows will terminate the process after the control handler */ + /* returns. After that it will just terminate our process. Therefore */ + /* block the signal handler so the main loop has some time to pick */ + /* up the signal and do something for a few seconds. */ + Sleep(INFINITE); + return TRUE; + } + return FALSE; + + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + /* These signals are only sent to services. Services have their own */ + /* notification mechanism, so there's no point in handling these. */ + + default: + /* We don't handle these. */ + return FALSE; + } +} + + +static int uv__signal_register_control_handler() { + /* When this function is called, the uv__signal_lock must be held. */ + + /* If the console control handler has already been hooked, just add a */ + /* reference. */ + if (uv__signal_control_handler_refs > 0) { + uv__signal_control_handler_refs++; + return 0; + } + + if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) + return GetLastError(); + + uv__signal_control_handler_refs++; + + return 0; +} + + +static void uv__signal_unregister_control_handler() { + /* When this function is called, the uv__signal_lock must be held. */ + BOOL r; + + /* Don't unregister if the number of console control handlers exceeds one. */ + /* Just remove a reference in that case. */ + if (uv__signal_control_handler_refs > 1) { + uv__signal_control_handler_refs--; + return; + } + + assert(uv__signal_control_handler_refs == 1); + + r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE); + /* This should never fail; if it does it is probably a bug in libuv. */ + assert(r); + + uv__signal_control_handler_refs--; +} + + +static int uv__signal_register(int signum) { + switch (signum) { + case SIGINT: + case SIGBREAK: + case SIGHUP: + return uv__signal_register_control_handler(); + + case SIGWINCH: + /* SIGWINCH is generated in tty.c. No need to register anything. */ + return 0; + + case SIGILL: + case SIGABRT_COMPAT: + case SIGFPE: + case SIGSEGV: + case SIGTERM: + case SIGABRT: + /* Signal is never raised. */ + return 0; + + default: + /* Invalid signal. */ + return ERROR_INVALID_PARAMETER; + } +} + + +static void uv__signal_unregister(int signum) { + switch (signum) { + case SIGINT: + case SIGBREAK: + case SIGHUP: + uv__signal_unregister_control_handler(); + return; + + case SIGWINCH: + /* SIGWINCH is generated in tty.c. No need to unregister anything. */ + return; + + case SIGILL: + case SIGABRT_COMPAT: + case SIGFPE: + case SIGSEGV: + case SIGTERM: + case SIGABRT: + /* Nothing is registered for this signal. */ + return; + + default: + /* Libuv bug. */ + assert(0 && "Invalid signum"); + return; + } +} + + +int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { + uv_req_t* req; + + uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL); + handle->pending_signum = 0; + handle->signum = 0; + handle->signal_cb = NULL; + + req = &handle->signal_req; + uv_req_init(loop, req); + req->type = UV_SIGNAL_REQ; + req->data = handle; + + return 0; +} + + +int uv_signal_stop(uv_signal_t* handle) { + uv_signal_t* removed_handle; + + /* If the watcher wasn't started, this is a no-op. */ + if (handle->signum == 0) + return 0; + + EnterCriticalSection(&uv__signal_lock); + + uv__signal_unregister(handle->signum); + + removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle); + assert(removed_handle == handle); + + LeaveCriticalSection(&uv__signal_lock); + + handle->signum = 0; + uv__handle_stop(handle); + + return 0; +} + + +int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { + int err; + + /* If the user supplies signum == 0, then return an error already. If the */ + /* signum is otherwise invalid then uv__signal_register will find out */ + /* eventually. */ + if (signum == 0) { + return UV_EINVAL; + } + + /* Short circuit: if the signal watcher is already watching {signum} don't */ + /* go through the process of deregistering and registering the handler. */ + /* Additionally, this avoids pending signals getting lost in the (small) */ + /* time frame that handle->signum == 0. */ + if (signum == handle->signum) { + handle->signal_cb = signal_cb; + return 0; + } + + /* If the signal handler was already active, stop it first. */ + if (handle->signum != 0) { + int r = uv_signal_stop(handle); + /* uv_signal_stop is infallible. */ + assert(r == 0); + } + + EnterCriticalSection(&uv__signal_lock); + + err = uv__signal_register(signum); + if (err) { + /* Uh-oh, didn't work. */ + LeaveCriticalSection(&uv__signal_lock); + return uv_translate_sys_error(err); + } + + handle->signum = signum; + RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle); + + LeaveCriticalSection(&uv__signal_lock); + + handle->signal_cb = signal_cb; + uv__handle_start(handle); + + return 0; +} + + +void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, + uv_req_t* req) { + long dispatched_signum; + + assert(handle->type == UV_SIGNAL); + assert(req->type == UV_SIGNAL_REQ); + + dispatched_signum = InterlockedExchange( + (volatile LONG*) &handle->pending_signum, 0); + assert(dispatched_signum != 0); + + /* Check if the pending signal equals the signum that we are watching for. */ + /* These can get out of sync when the handler is stopped and restarted */ + /* while the signal_req is pending. */ + if (dispatched_signum == handle->signum) + handle->signal_cb(handle, dispatched_signum); + + if (handle->flags & UV__HANDLE_CLOSING) { + /* When it is closing, it must be stopped at this point. */ + assert(handle->signum == 0); + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) { + uv_signal_stop(handle); + uv__handle_closing(handle); + + if (handle->pending_signum == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) { + assert(handle->flags & UV__HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + assert(handle->signum == 0); + assert(handle->pending_signum == 0); + + handle->flags |= UV_HANDLE_CLOSED; + + uv__handle_close(handle); +} diff --git a/src/win/snprintf.c b/src/win/snprintf.c new file mode 100644 index 0000000..776c0e3 --- /dev/null +++ b/src/win/snprintf.c @@ -0,0 +1,42 @@ +/* Copyright the libuv project contributors. All rights reserved. + * + * 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. + */ + +#if defined(_MSC_VER) && _MSC_VER < 1900 + +#include +#include + +/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer + * on overflow... + */ +int snprintf(char* buf, size_t len, const char* fmt, ...) { + int n; + va_list ap; + va_start(ap, fmt); + + n = _vscprintf(fmt, ap); + vsnprintf_s(buf, len, _TRUNCATE, fmt, ap); + + va_end(ap); + return n; +} + +#endif diff --git a/src/win/stream-inl.h b/src/win/stream-inl.h new file mode 100644 index 0000000..b7a3c11 --- /dev/null +++ b/src/win/stream-inl.h @@ -0,0 +1,56 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_WIN_STREAM_INL_H_ +#define UV_WIN_STREAM_INL_H_ + +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +INLINE static void uv_stream_init(uv_loop_t* loop, + uv_stream_t* handle, + uv_handle_type type) { + uv__handle_init(loop, (uv_handle_t*) handle, type); + handle->write_queue_size = 0; + handle->activecnt = 0; +} + + +INLINE static void uv_connection_init(uv_stream_t* handle) { + handle->flags |= UV_HANDLE_CONNECTION; + handle->stream.conn.write_reqs_pending = 0; + + uv_req_init(handle->loop, (uv_req_t*) &(handle->read_req)); + handle->read_req.event_handle = NULL; + handle->read_req.wait_handle = INVALID_HANDLE_VALUE; + handle->read_req.type = UV_READ; + handle->read_req.data = handle; + + handle->stream.conn.shutdown_req = NULL; +} + + +#endif /* UV_WIN_STREAM_INL_H_ */ diff --git a/src/win/stream.c b/src/win/stream.c new file mode 100644 index 0000000..a2466e5 --- /dev/null +++ b/src/win/stream.c @@ -0,0 +1,249 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { + int err; + + err = ERROR_INVALID_PARAMETER; + switch (stream->type) { + case UV_TCP: + err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb); + break; + case UV_NAMED_PIPE: + err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_accept(uv_stream_t* server, uv_stream_t* client) { + int err; + + err = ERROR_INVALID_PARAMETER; + switch (server->type) { + case UV_TCP: + err = uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client); + break; + case UV_NAMED_PIPE: + err = uv_pipe_accept((uv_pipe_t*)server, client); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { + int err; + + if (handle->flags & UV_HANDLE_READING) { + return UV_EALREADY; + } + + if (!(handle->flags & UV_HANDLE_READABLE)) { + return UV_ENOTCONN; + } + + err = ERROR_INVALID_PARAMETER; + switch (handle->type) { + case UV_TCP: + err = uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb); + break; + case UV_NAMED_PIPE: + err = uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb); + break; + case UV_TTY: + err = uv_tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_read_stop(uv_stream_t* handle) { + int err; + + if (!(handle->flags & UV_HANDLE_READING)) + return 0; + + err = 0; + if (handle->type == UV_TTY) { + err = uv_tty_read_stop((uv_tty_t*) handle); + } else { + if (handle->type == UV_NAMED_PIPE) { + uv__pipe_stop_read((uv_pipe_t*) handle); + } else { + handle->flags &= ~UV_HANDLE_READING; + } + DECREASE_ACTIVE_COUNT(handle->loop, handle); + } + + return uv_translate_sys_error(err); +} + + +int uv_write(uv_write_t* req, + uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb) { + uv_loop_t* loop = handle->loop; + int err; + + if (!(handle->flags & UV_HANDLE_WRITABLE)) { + return UV_EPIPE; + } + + err = ERROR_INVALID_PARAMETER; + switch (handle->type) { + case UV_TCP: + err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb); + break; + case UV_NAMED_PIPE: + err = uv_pipe_write(loop, req, (uv_pipe_t*) handle, bufs, nbufs, cb); + break; + case UV_TTY: + err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_write2(uv_write_t* req, + uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb) { + uv_loop_t* loop = handle->loop; + int err; + + if (!(handle->flags & UV_HANDLE_WRITABLE)) { + return UV_EPIPE; + } + + err = ERROR_INVALID_PARAMETER; + switch (handle->type) { + case UV_NAMED_PIPE: + err = uv_pipe_write2(loop, + req, + (uv_pipe_t*) handle, + bufs, + nbufs, + send_handle, + cb); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_try_write(uv_stream_t* stream, + const uv_buf_t bufs[], + unsigned int nbufs) { + if (stream->flags & UV__HANDLE_CLOSING) + return UV_EBADF; + if (!(stream->flags & UV_HANDLE_WRITABLE)) + return UV_EPIPE; + + switch (stream->type) { + case UV_TCP: + return uv__tcp_try_write((uv_tcp_t*) stream, bufs, nbufs); + case UV_TTY: + return uv__tty_try_write((uv_tty_t*) stream, bufs, nbufs); + case UV_NAMED_PIPE: + return UV_EAGAIN; + default: + assert(0); + return UV_ENOSYS; + } +} + + +int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { + uv_loop_t* loop = handle->loop; + + if (!(handle->flags & UV_HANDLE_WRITABLE)) { + return UV_EPIPE; + } + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_SHUTDOWN; + req->handle = handle; + req->cb = cb; + + handle->flags &= ~UV_HANDLE_WRITABLE; + handle->stream.conn.shutdown_req = req; + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + + uv_want_endgame(loop, (uv_handle_t*)handle); + + return 0; +} + + +int uv_is_readable(const uv_stream_t* handle) { + return !!(handle->flags & UV_HANDLE_READABLE); +} + + +int uv_is_writable(const uv_stream_t* handle) { + return !!(handle->flags & UV_HANDLE_WRITABLE); +} + + +int uv_stream_set_blocking(uv_stream_t* handle, int blocking) { + if (handle->type != UV_NAMED_PIPE) + return UV_EINVAL; + + if (blocking != 0) + handle->flags |= UV_HANDLE_BLOCKING_WRITES; + else + handle->flags &= ~UV_HANDLE_BLOCKING_WRITES; + + return 0; +} diff --git a/src/win/tcp.c b/src/win/tcp.c new file mode 100644 index 0000000..0709696 --- /dev/null +++ b/src/win/tcp.c @@ -0,0 +1,1510 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" + + +/* + * Threshold of active tcp streams for which to preallocate tcp read buffers. + * (Due to node slab allocator performing poorly under this pattern, + * the optimization is temporarily disabled (threshold=0). This will be + * revisited once node allocator is improved.) + */ +const unsigned int uv_active_tcp_streams_threshold = 0; + +/* + * Number of simultaneous pending AcceptEx calls. + */ +const unsigned int uv_simultaneous_server_accepts = 32; + +/* A zero-size buffer for use by uv_tcp_read */ +static char uv_zero_[] = ""; + +static int uv__tcp_nodelay(uv_tcp_t* handle, SOCKET socket, int enable) { + if (setsockopt(socket, + IPPROTO_TCP, + TCP_NODELAY, + (const char*)&enable, + sizeof enable) == -1) { + return WSAGetLastError(); + } + return 0; +} + + +static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsigned int delay) { + if (setsockopt(socket, + SOL_SOCKET, + SO_KEEPALIVE, + (const char*)&enable, + sizeof enable) == -1) { + return WSAGetLastError(); + } + + if (enable && setsockopt(socket, + IPPROTO_TCP, + TCP_KEEPALIVE, + (const char*)&delay, + sizeof delay) == -1) { + return WSAGetLastError(); + } + + return 0; +} + + +static int uv_tcp_set_socket(uv_loop_t* loop, + uv_tcp_t* handle, + SOCKET socket, + int family, + int imported) { + DWORD yes = 1; + int non_ifs_lsp; + int err; + + if (handle->socket != INVALID_SOCKET) + return UV_EBUSY; + + /* Set the socket to nonblocking mode */ + if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) { + return WSAGetLastError(); + } + + /* Make the socket non-inheritable */ + if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0)) + return GetLastError(); + + /* Associate it with the I/O completion port. */ + /* Use uv_handle_t pointer as completion key. */ + if (CreateIoCompletionPort((HANDLE)socket, + loop->iocp, + (ULONG_PTR)socket, + 0) == NULL) { + if (imported) { + handle->flags |= UV_HANDLE_EMULATE_IOCP; + } else { + return GetLastError(); + } + } + + if (family == AF_INET6) { + non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv6; + } else { + non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4; + } + + if (pSetFileCompletionNotificationModes && + !(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) { + if (pSetFileCompletionNotificationModes((HANDLE) socket, + FILE_SKIP_SET_EVENT_ON_HANDLE | + FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { + handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; + } else if (GetLastError() != ERROR_INVALID_FUNCTION) { + return GetLastError(); + } + } + + if (handle->flags & UV_HANDLE_TCP_NODELAY) { + err = uv__tcp_nodelay(handle, socket, 1); + if (err) + return err; + } + + /* TODO: Use stored delay. */ + if (handle->flags & UV_HANDLE_TCP_KEEPALIVE) { + err = uv__tcp_keepalive(handle, socket, 1, 60); + if (err) + return err; + } + + handle->socket = socket; + + if (family == AF_INET6) { + handle->flags |= UV_HANDLE_IPV6; + } else { + assert(!(handle->flags & UV_HANDLE_IPV6)); + } + + return 0; +} + + +int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) { + int domain; + + /* Use the lower 8 bits for the domain */ + domain = flags & 0xFF; + if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) + return UV_EINVAL; + + if (flags & ~0xFF) + return UV_EINVAL; + + uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP); + handle->tcp.serv.accept_reqs = NULL; + handle->tcp.serv.pending_accepts = NULL; + handle->socket = INVALID_SOCKET; + handle->reqs_pending = 0; + handle->tcp.serv.func_acceptex = NULL; + handle->tcp.conn.func_connectex = NULL; + handle->tcp.serv.processed_accepts = 0; + handle->delayed_error = 0; + + /* If anything fails beyond this point we need to remove the handle from + * the handle queue, since it was added by uv__handle_init in uv_stream_init. + */ + + if (domain != AF_UNSPEC) { + SOCKET sock; + DWORD err; + + sock = socket(domain, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) { + err = WSAGetLastError(); + QUEUE_REMOVE(&handle->handle_queue); + return uv_translate_sys_error(err); + } + + err = uv_tcp_set_socket(handle->loop, handle, sock, domain, 0); + if (err) { + closesocket(sock); + QUEUE_REMOVE(&handle->handle_queue); + return uv_translate_sys_error(err); + } + + } + + return 0; +} + + +int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) { + return uv_tcp_init_ex(loop, handle, AF_UNSPEC); +} + + +void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { + int err; + unsigned int i; + uv_tcp_accept_t* req; + + if (handle->flags & UV_HANDLE_CONNECTION && + handle->stream.conn.shutdown_req != NULL && + handle->stream.conn.write_reqs_pending == 0) { + + UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req); + + err = 0; + if (handle->flags & UV__HANDLE_CLOSING) { + err = ERROR_OPERATION_ABORTED; + } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) { + err = WSAGetLastError(); + } + + if (handle->stream.conn.shutdown_req->cb) { + handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, + uv_translate_sys_error(err)); + } + + handle->stream.conn.shutdown_req = NULL; + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + if (handle->flags & UV__HANDLE_CLOSING && + handle->reqs_pending == 0) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) { + closesocket(handle->socket); + handle->socket = INVALID_SOCKET; + handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; + } + + if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) { + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + for (i = 0; i < uv_simultaneous_server_accepts; i++) { + req = &handle->tcp.serv.accept_reqs[i]; + if (req->wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(req->wait_handle); + req->wait_handle = INVALID_HANDLE_VALUE; + } + if (req->event_handle) { + CloseHandle(req->event_handle); + req->event_handle = NULL; + } + } + } + + uv__free(handle->tcp.serv.accept_reqs); + handle->tcp.serv.accept_reqs = NULL; + } + + if (handle->flags & UV_HANDLE_CONNECTION && + handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(handle->read_req.wait_handle); + handle->read_req.wait_handle = INVALID_HANDLE_VALUE; + } + if (handle->read_req.event_handle) { + CloseHandle(handle->read_req.event_handle); + handle->read_req.event_handle = NULL; + } + } + + uv__handle_close(handle); + loop->active_tcp_streams--; + } +} + + +/* Unlike on Unix, here we don't set SO_REUSEADDR, because it doesn't just + * allow binding to addresses that are in use by sockets in TIME_WAIT, it + * effectively allows 'stealing' a port which is in use by another application. + * + * SO_EXCLUSIVEADDRUSE is also not good here because it does check all sockets, + * regardless of state, so we'd get an error even if the port is in use by a + * socket in TIME_WAIT state. + * + * See issue #1360. + * + */ +static int uv_tcp_try_bind(uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + DWORD err; + int r; + + if (handle->socket == INVALID_SOCKET) { + SOCKET sock; + + /* Cannot set IPv6-only mode on non-IPv6 socket. */ + if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6) + return ERROR_INVALID_PARAMETER; + + sock = socket(addr->sa_family, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) { + return WSAGetLastError(); + } + + err = uv_tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0); + if (err) { + closesocket(sock); + return err; + } + } + +#ifdef IPV6_V6ONLY + if (addr->sa_family == AF_INET6) { + int on; + + on = (flags & UV_TCP_IPV6ONLY) != 0; + + /* TODO: how to handle errors? This may fail if there is no ipv4 stack */ + /* available, or when run on XP/2003 which have no support for dualstack */ + /* sockets. For now we're silently ignoring the error. */ + setsockopt(handle->socket, + IPPROTO_IPV6, + IPV6_V6ONLY, + (const char*)&on, + sizeof on); + } +#endif + + r = bind(handle->socket, addr, addrlen); + + if (r == SOCKET_ERROR) { + err = WSAGetLastError(); + if (err == WSAEADDRINUSE) { + /* Some errors are not to be reported until connect() or listen() */ + handle->delayed_error = err; + } else { + return err; + } + } + + handle->flags |= UV_HANDLE_BOUND; + + return 0; +} + + +static void CALLBACK post_completion(void* context, BOOLEAN timed_out) { + uv_req_t* req; + uv_tcp_t* handle; + + req = (uv_req_t*) context; + assert(req != NULL); + handle = (uv_tcp_t*)req->data; + assert(handle != NULL); + assert(!timed_out); + + if (!PostQueuedCompletionStatus(handle->loop->iocp, + req->u.io.overlapped.InternalHigh, + 0, + &req->u.io.overlapped)) { + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); + } +} + + +static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) { + uv_write_t* req; + uv_tcp_t* handle; + + req = (uv_write_t*) context; + assert(req != NULL); + handle = (uv_tcp_t*)req->handle; + assert(handle != NULL); + assert(!timed_out); + + if (!PostQueuedCompletionStatus(handle->loop->iocp, + req->u.io.overlapped.InternalHigh, + 0, + &req->u.io.overlapped)) { + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); + } +} + + +static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { + uv_loop_t* loop = handle->loop; + BOOL success; + DWORD bytes; + SOCKET accept_socket; + short family; + + assert(handle->flags & UV_HANDLE_LISTENING); + assert(req->accept_socket == INVALID_SOCKET); + + /* choose family and extension function */ + if (handle->flags & UV_HANDLE_IPV6) { + family = AF_INET6; + } else { + family = AF_INET; + } + + /* Open a socket for the accepted connection. */ + accept_socket = socket(family, SOCK_STREAM, 0); + if (accept_socket == INVALID_SOCKET) { + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->reqs_pending++; + return; + } + + /* Make the socket non-inheritable */ + if (!SetHandleInformation((HANDLE) accept_socket, HANDLE_FLAG_INHERIT, 0)) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->reqs_pending++; + closesocket(accept_socket); + return; + } + + /* Prepare the overlapped structure. */ + memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); + } + + success = handle->tcp.serv.func_acceptex(handle->socket, + accept_socket, + (void*)req->accept_buffer, + 0, + sizeof(struct sockaddr_storage), + sizeof(struct sockaddr_storage), + &bytes, + &req->u.io.overlapped); + + if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { + /* Process the req without IOCP. */ + req->accept_socket = accept_socket; + handle->reqs_pending++; + uv_insert_pending_req(loop, (uv_req_t*)req); + } else if (UV_SUCCEEDED_WITH_IOCP(success)) { + /* The req will be processed with IOCP. */ + req->accept_socket = accept_socket; + handle->reqs_pending++; + if (handle->flags & UV_HANDLE_EMULATE_IOCP && + req->wait_handle == INVALID_HANDLE_VALUE && + !RegisterWaitForSingleObject(&req->wait_handle, + req->event_handle, post_completion, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD)) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->reqs_pending++; + return; + } + } else { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->reqs_pending++; + /* Destroy the preallocated client socket. */ + closesocket(accept_socket); + /* Destroy the event handle */ + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + CloseHandle(req->u.io.overlapped.hEvent); + req->event_handle = NULL; + } + } +} + + +static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { + uv_read_t* req; + uv_buf_t buf; + int result; + DWORD bytes, flags; + + assert(handle->flags & UV_HANDLE_READING); + assert(!(handle->flags & UV_HANDLE_READ_PENDING)); + + req = &handle->read_req; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + + /* + * Preallocate a read buffer if the number of active streams is below + * the threshold. + */ + if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) { + handle->flags &= ~UV_HANDLE_ZERO_READ; + handle->tcp.conn.read_buffer = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer); + if (handle->tcp.conn.read_buffer.base == NULL || + handle->tcp.conn.read_buffer.len == 0) { + handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tcp.conn.read_buffer); + return; + } + assert(handle->tcp.conn.read_buffer.base != NULL); + buf = handle->tcp.conn.read_buffer; + } else { + handle->flags |= UV_HANDLE_ZERO_READ; + buf.base = (char*) &uv_zero_; + buf.len = 0; + } + + /* Prepare the overlapped structure. */ + memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + assert(req->event_handle); + req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); + } + + flags = 0; + result = WSARecv(handle->socket, + (WSABUF*)&buf, + 1, + &bytes, + &flags, + &req->u.io.overlapped, + NULL); + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Process the req without IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + req->u.io.overlapped.InternalHigh = bytes; + handle->reqs_pending++; + uv_insert_pending_req(loop, (uv_req_t*)req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* The req will be processed with IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + if (handle->flags & UV_HANDLE_EMULATE_IOCP && + req->wait_handle == INVALID_HANDLE_VALUE && + !RegisterWaitForSingleObject(&req->wait_handle, + req->event_handle, post_completion, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD)) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + } + } else { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->reqs_pending++; + } +} + + +int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { + uv_loop_t* loop = handle->loop; + unsigned int i, simultaneous_accepts; + uv_tcp_accept_t* req; + int err; + + assert(backlog > 0); + + if (handle->flags & UV_HANDLE_LISTENING) { + handle->stream.serv.connection_cb = cb; + } + + if (handle->flags & UV_HANDLE_READING) { + return WSAEISCONN; + } + + if (handle->delayed_error) { + return handle->delayed_error; + } + + if (!(handle->flags & UV_HANDLE_BOUND)) { + err = uv_tcp_try_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + 0); + if (err) + return err; + if (handle->delayed_error) + return handle->delayed_error; + } + + if (!handle->tcp.serv.func_acceptex) { + if (!uv_get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) { + return WSAEAFNOSUPPORT; + } + } + + if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) && + listen(handle->socket, backlog) == SOCKET_ERROR) { + return WSAGetLastError(); + } + + handle->flags |= UV_HANDLE_LISTENING; + handle->stream.serv.connection_cb = cb; + INCREASE_ACTIVE_COUNT(loop, handle); + + simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1 + : uv_simultaneous_server_accepts; + + if(!handle->tcp.serv.accept_reqs) { + handle->tcp.serv.accept_reqs = (uv_tcp_accept_t*) + uv__malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t)); + if (!handle->tcp.serv.accept_reqs) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + for (i = 0; i < simultaneous_accepts; i++) { + req = &handle->tcp.serv.accept_reqs[i]; + uv_req_init(loop, (uv_req_t*)req); + req->type = UV_ACCEPT; + req->accept_socket = INVALID_SOCKET; + req->data = handle; + + req->wait_handle = INVALID_HANDLE_VALUE; + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + req->event_handle = CreateEvent(NULL, 0, 0, NULL); + if (!req->event_handle) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + } else { + req->event_handle = NULL; + } + + uv_tcp_queue_accept(handle, req); + } + + /* Initialize other unused requests too, because uv_tcp_endgame */ + /* doesn't know how how many requests were initialized, so it will */ + /* try to clean up {uv_simultaneous_server_accepts} requests. */ + for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) { + req = &handle->tcp.serv.accept_reqs[i]; + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_ACCEPT; + req->accept_socket = INVALID_SOCKET; + req->data = handle; + req->wait_handle = INVALID_HANDLE_VALUE; + req->event_handle = NULL; + } + } + + return 0; +} + + +int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { + uv_loop_t* loop = server->loop; + int err = 0; + int family; + + uv_tcp_accept_t* req = server->tcp.serv.pending_accepts; + + if (!req) { + /* No valid connections found, so we error out. */ + return WSAEWOULDBLOCK; + } + + if (req->accept_socket == INVALID_SOCKET) { + return WSAENOTCONN; + } + + if (server->flags & UV_HANDLE_IPV6) { + family = AF_INET6; + } else { + family = AF_INET; + } + + err = uv_tcp_set_socket(client->loop, + client, + req->accept_socket, + family, + 0); + if (err) { + closesocket(req->accept_socket); + } else { + uv_connection_init((uv_stream_t*) client); + /* AcceptEx() implicitly binds the accepted socket. */ + client->flags |= UV_HANDLE_BOUND | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + } + + /* Prepare the req to pick up a new connection */ + server->tcp.serv.pending_accepts = req->next_pending; + req->next_pending = NULL; + req->accept_socket = INVALID_SOCKET; + + if (!(server->flags & UV__HANDLE_CLOSING)) { + /* Check if we're in a middle of changing the number of pending accepts. */ + if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) { + uv_tcp_queue_accept(server, req); + } else { + /* We better be switching to a single pending accept. */ + assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT); + + server->tcp.serv.processed_accepts++; + + if (server->tcp.serv.processed_accepts >= uv_simultaneous_server_accepts) { + server->tcp.serv.processed_accepts = 0; + /* + * All previously queued accept requests are now processed. + * We now switch to queueing just a single accept. + */ + uv_tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]); + server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING; + server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; + } + } + } + + loop->active_tcp_streams++; + + return err; +} + + +int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { + uv_loop_t* loop = handle->loop; + + handle->flags |= UV_HANDLE_READING; + handle->read_cb = read_cb; + handle->alloc_cb = alloc_cb; + INCREASE_ACTIVE_COUNT(loop, handle); + + /* If reading was stopped and then started again, there could still be a */ + /* read request pending. */ + if (!(handle->flags & UV_HANDLE_READ_PENDING)) { + if (handle->flags & UV_HANDLE_EMULATE_IOCP && + !handle->read_req.event_handle) { + handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL); + if (!handle->read_req.event_handle) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + } + uv_tcp_queue_read(loop, handle); + } + + return 0; +} + + +static int uv_tcp_try_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + uv_connect_cb cb) { + uv_loop_t* loop = handle->loop; + const struct sockaddr* bind_addr; + BOOL success; + DWORD bytes; + int err; + + if (handle->delayed_error) { + return handle->delayed_error; + } + + if (!(handle->flags & UV_HANDLE_BOUND)) { + if (addrlen == sizeof(uv_addr_ip4_any_)) { + bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_; + } else if (addrlen == sizeof(uv_addr_ip6_any_)) { + bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_; + } else { + abort(); + } + err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0); + if (err) + return err; + if (handle->delayed_error) + return handle->delayed_error; + } + + if (!handle->tcp.conn.func_connectex) { + if (!uv_get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) { + return WSAEAFNOSUPPORT; + } + } + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_CONNECT; + req->handle = (uv_stream_t*) handle; + req->cb = cb; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + + success = handle->tcp.conn.func_connectex(handle->socket, + addr, + addrlen, + NULL, + 0, + &bytes, + &req->u.io.overlapped); + + if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { + /* Process the req without IOCP. */ + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + uv_insert_pending_req(loop, (uv_req_t*)req); + } else if (UV_SUCCEEDED_WITH_IOCP(success)) { + /* The req will be processed with IOCP. */ + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + } else { + return WSAGetLastError(); + } + + return 0; +} + + +int uv_tcp_getsockname(const uv_tcp_t* handle, + struct sockaddr* name, + int* namelen) { + int result; + + if (handle->socket == INVALID_SOCKET) { + return UV_EINVAL; + } + + if (handle->delayed_error) { + return uv_translate_sys_error(handle->delayed_error); + } + + result = getsockname(handle->socket, name, namelen); + if (result != 0) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +int uv_tcp_getpeername(const uv_tcp_t* handle, + struct sockaddr* name, + int* namelen) { + int result; + + if (handle->socket == INVALID_SOCKET) { + return UV_EINVAL; + } + + if (handle->delayed_error) { + return uv_translate_sys_error(handle->delayed_error); + } + + result = getpeername(handle->socket, name, namelen); + if (result != 0) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +int uv_tcp_write(uv_loop_t* loop, + uv_write_t* req, + uv_tcp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb) { + int result; + DWORD bytes; + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_WRITE; + req->handle = (uv_stream_t*) handle; + req->cb = cb; + + /* Prepare the overlapped structure. */ + memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + req->event_handle = CreateEvent(NULL, 0, 0, NULL); + if (!req->event_handle) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); + req->wait_handle = INVALID_HANDLE_VALUE; + } + + result = WSASend(handle->socket, + (WSABUF*) bufs, + nbufs, + &bytes, + 0, + &req->u.io.overlapped, + NULL); + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Request completed immediately. */ + req->u.io.queued_bytes = 0; + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + uv_insert_pending_req(loop, (uv_req_t*) req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* Request queued by the kernel. */ + req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs); + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + handle->write_queue_size += req->u.io.queued_bytes; + if (handle->flags & UV_HANDLE_EMULATE_IOCP && + !RegisterWaitForSingleObject(&req->wait_handle, + req->event_handle, post_write_completion, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + } + } else { + /* Send failed due to an error, report it later */ + req->u.io.queued_bytes = 0; + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, (uv_req_t*) req); + } + + return 0; +} + + +int uv__tcp_try_write(uv_tcp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs) { + int result; + DWORD bytes; + + if (handle->stream.conn.write_reqs_pending > 0) + return UV_EAGAIN; + + result = WSASend(handle->socket, + (WSABUF*) bufs, + nbufs, + &bytes, + 0, + NULL, + NULL); + + if (result == SOCKET_ERROR) + return uv_translate_sys_error(WSAGetLastError()); + else + return bytes; +} + + +void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_req_t* req) { + DWORD bytes, flags, err; + uv_buf_t buf; + + assert(handle->type == UV_TCP); + + handle->flags &= ~UV_HANDLE_READ_PENDING; + + if (!REQ_SUCCESS(req)) { + /* An error occurred doing the read. */ + if ((handle->flags & UV_HANDLE_READING) || + !(handle->flags & UV_HANDLE_ZERO_READ)) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + buf = (handle->flags & UV_HANDLE_ZERO_READ) ? + uv_buf_init(NULL, 0) : handle->tcp.conn.read_buffer; + + err = GET_REQ_SOCK_ERROR(req); + + if (err == WSAECONNABORTED) { + /* + * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix. + */ + err = WSAECONNRESET; + } + + handle->read_cb((uv_stream_t*)handle, + uv_translate_sys_error(err), + &buf); + } + } else { + if (!(handle->flags & UV_HANDLE_ZERO_READ)) { + /* The read was done with a non-zero buffer length. */ + if (req->u.io.overlapped.InternalHigh > 0) { + /* Successful read */ + handle->read_cb((uv_stream_t*)handle, + req->u.io.overlapped.InternalHigh, + &handle->tcp.conn.read_buffer); + /* Read again only if bytes == buf.len */ + if (req->u.io.overlapped.InternalHigh < handle->tcp.conn.read_buffer.len) { + goto done; + } + } else { + /* Connection closed */ + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + handle->flags &= ~UV_HANDLE_READABLE; + + buf.base = 0; + buf.len = 0; + handle->read_cb((uv_stream_t*)handle, UV_EOF, &handle->tcp.conn.read_buffer); + goto done; + } + } + + /* Do nonblocking reads until the buffer is empty */ + while (handle->flags & UV_HANDLE_READING) { + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); + if (buf.base == NULL || buf.len == 0) { + handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); + break; + } + assert(buf.base != NULL); + + flags = 0; + if (WSARecv(handle->socket, + (WSABUF*)&buf, + 1, + &bytes, + &flags, + NULL, + NULL) != SOCKET_ERROR) { + if (bytes > 0) { + /* Successful read */ + handle->read_cb((uv_stream_t*)handle, bytes, &buf); + /* Read again only if bytes == buf.len */ + if (bytes < buf.len) { + break; + } + } else { + /* Connection closed */ + handle->flags &= ~(UV_HANDLE_READING | UV_HANDLE_READABLE); + DECREASE_ACTIVE_COUNT(loop, handle); + + handle->read_cb((uv_stream_t*)handle, UV_EOF, &buf); + break; + } + } else { + err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK) { + /* Read buffer was completely empty, report a 0-byte read. */ + handle->read_cb((uv_stream_t*)handle, 0, &buf); + } else { + /* Ouch! serious error. */ + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + + if (err == WSAECONNABORTED) { + /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with */ + /* Unix. */ + err = WSAECONNRESET; + } + + handle->read_cb((uv_stream_t*)handle, + uv_translate_sys_error(err), + &buf); + } + break; + } + } + +done: + /* Post another read if still reading and not closing. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_tcp_queue_read(loop, handle); + } + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_write_t* req) { + int err; + + assert(handle->type == UV_TCP); + + assert(handle->write_queue_size >= req->u.io.queued_bytes); + handle->write_queue_size -= req->u.io.queued_bytes; + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (req->wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(req->wait_handle); + req->wait_handle = INVALID_HANDLE_VALUE; + } + if (req->event_handle) { + CloseHandle(req->event_handle); + req->event_handle = NULL; + } + } + + if (req->cb) { + err = uv_translate_sys_error(GET_REQ_SOCK_ERROR(req)); + if (err == UV_ECONNABORTED) { + /* use UV_ECANCELED for consistency with Unix */ + err = UV_ECANCELED; + } + req->cb(req, err); + } + + handle->stream.conn.write_reqs_pending--; + if (handle->stream.conn.shutdown_req != NULL && + handle->stream.conn.write_reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_req_t* raw_req) { + uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req; + int err; + + assert(handle->type == UV_TCP); + + /* If handle->accepted_socket is not a valid socket, then */ + /* uv_queue_accept must have failed. This is a serious error. We stop */ + /* accepting connections and report this error to the connection */ + /* callback. */ + if (req->accept_socket == INVALID_SOCKET) { + if (handle->flags & UV_HANDLE_LISTENING) { + handle->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, handle); + if (handle->stream.serv.connection_cb) { + err = GET_REQ_SOCK_ERROR(req); + handle->stream.serv.connection_cb((uv_stream_t*)handle, + uv_translate_sys_error(err)); + } + } + } else if (REQ_SUCCESS(req) && + setsockopt(req->accept_socket, + SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, + (char*)&handle->socket, + sizeof(handle->socket)) == 0) { + req->next_pending = handle->tcp.serv.pending_accepts; + handle->tcp.serv.pending_accepts = req; + + /* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */ + if (handle->stream.serv.connection_cb) { + handle->stream.serv.connection_cb((uv_stream_t*)handle, 0); + } + } else { + /* Error related to accepted socket is ignored because the server */ + /* socket may still be healthy. If the server socket is broken */ + /* uv_queue_accept will detect it. */ + closesocket(req->accept_socket); + req->accept_socket = INVALID_SOCKET; + if (handle->flags & UV_HANDLE_LISTENING) { + uv_tcp_queue_accept(handle, req); + } + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_connect_t* req) { + int err; + + assert(handle->type == UV_TCP); + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + err = 0; + if (REQ_SUCCESS(req)) { + if (setsockopt(handle->socket, + SOL_SOCKET, + SO_UPDATE_CONNECT_CONTEXT, + NULL, + 0) == 0) { + uv_connection_init((uv_stream_t*)handle); + handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + loop->active_tcp_streams++; + } else { + err = WSAGetLastError(); + } + } else { + err = GET_REQ_SOCK_ERROR(req); + } + req->cb(req, uv_translate_sys_error(err)); + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex, + int tcp_connection) { + int err; + SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + &socket_info_ex->socket_info, + 0, + WSA_FLAG_OVERLAPPED); + + if (socket == INVALID_SOCKET) { + return WSAGetLastError(); + } + + err = uv_tcp_set_socket(tcp->loop, + tcp, + socket, + socket_info_ex->socket_info.iAddressFamily, + 1); + if (err) { + closesocket(socket); + return err; + } + + if (tcp_connection) { + uv_connection_init((uv_stream_t*)tcp); + tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + } + + tcp->flags |= UV_HANDLE_BOUND; + tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET; + + tcp->delayed_error = socket_info_ex->delayed_error; + + tcp->loop->active_tcp_streams++; + return 0; +} + + +int uv_tcp_nodelay(uv_tcp_t* handle, int enable) { + int err; + + if (handle->socket != INVALID_SOCKET) { + err = uv__tcp_nodelay(handle, handle->socket, enable); + if (err) + return err; + } + + if (enable) { + handle->flags |= UV_HANDLE_TCP_NODELAY; + } else { + handle->flags &= ~UV_HANDLE_TCP_NODELAY; + } + + return 0; +} + + +int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { + int err; + + if (handle->socket != INVALID_SOCKET) { + err = uv__tcp_keepalive(handle, handle->socket, enable, delay); + if (err) + return err; + } + + if (enable) { + handle->flags |= UV_HANDLE_TCP_KEEPALIVE; + } else { + handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE; + } + + /* TODO: Store delay if handle->socket isn't created yet. */ + + return 0; +} + + +int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, + LPWSAPROTOCOL_INFOW protocol_info) { + if (!(handle->flags & UV_HANDLE_CONNECTION)) { + /* + * We're about to share the socket with another process. Because + * this is a listening socket, we assume that the other process will + * be accepting connections on it. So, before sharing the socket + * with another process, we call listen here in the parent process. + */ + + if (!(handle->flags & UV_HANDLE_LISTENING)) { + if (!(handle->flags & UV_HANDLE_BOUND)) { + return ERROR_INVALID_PARAMETER; + } + + if (!(handle->delayed_error)) { + if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) { + handle->delayed_error = WSAGetLastError(); + } + } + } + } + + if (WSADuplicateSocketW(handle->socket, pid, protocol_info)) { + return WSAGetLastError(); + } + + handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET; + + return 0; +} + + +int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { + if (handle->flags & UV_HANDLE_CONNECTION) { + return UV_EINVAL; + } + + /* Check if we're already in the desired mode. */ + if ((enable && !(handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) || + (!enable && handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) { + return 0; + } + + /* Don't allow switching from single pending accept to many. */ + if (enable) { + return UV_ENOTSUP; + } + + /* Check if we're in a middle of changing the number of pending accepts. */ + if (handle->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING) { + return 0; + } + + handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; + + /* Flip the changing flag if we have already queued multiple accepts. */ + if (handle->flags & UV_HANDLE_LISTENING) { + handle->flags |= UV_HANDLE_TCP_ACCEPT_STATE_CHANGING; + } + + return 0; +} + + +static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) { + SOCKET socket = tcp->socket; + int non_ifs_lsp; + + /* Check if we have any non-IFS LSPs stacked on top of TCP */ + non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 : + uv_tcp_non_ifs_lsp_ipv4; + + /* If there are non-ifs LSPs then try to obtain a base handle for the */ + /* socket. This will always fail on Windows XP/3k. */ + if (non_ifs_lsp) { + DWORD bytes; + if (WSAIoctl(socket, + SIO_BASE_HANDLE, + NULL, + 0, + &socket, + sizeof socket, + &bytes, + NULL, + NULL) != 0) { + /* Failed. We can't do CancelIo. */ + return -1; + } + } + + assert(socket != 0 && socket != INVALID_SOCKET); + + if (!CancelIo((HANDLE) socket)) { + return GetLastError(); + } + + /* It worked. */ + return 0; +} + + +void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { + int close_socket = 1; + + if (tcp->flags & UV_HANDLE_READ_PENDING) { + /* In order for winsock to do a graceful close there must not be any */ + /* any pending reads, or the socket must be shut down for writing */ + if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) { + /* Just do shutdown on non-shared sockets, which ensures graceful close. */ + shutdown(tcp->socket, SD_SEND); + + } else if (uv_tcp_try_cancel_io(tcp) == 0) { + /* In case of a shared socket, we try to cancel all outstanding I/O, */ + /* If that works, don't close the socket yet - wait for the read req to */ + /* return and close the socket in uv_tcp_endgame. */ + close_socket = 0; + + } else { + /* When cancelling isn't possible - which could happen when an LSP is */ + /* present on an old Windows version, we will have to close the socket */ + /* with a read pending. That is not nice because trailing sent bytes */ + /* may not make it to the other side. */ + } + + } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) && + tcp->tcp.serv.accept_reqs != NULL) { + /* Under normal circumstances closesocket() will ensure that all pending */ + /* accept reqs are canceled. However, when the socket is shared the */ + /* presence of another reference to the socket in another process will */ + /* keep the accept reqs going, so we have to ensure that these are */ + /* canceled. */ + if (uv_tcp_try_cancel_io(tcp) != 0) { + /* When cancellation is not possible, there is another option: we can */ + /* close the incoming sockets, which will also cancel the accept */ + /* operations. However this is not cool because we might inadvertently */ + /* close a socket that just accepted a new connection, which will */ + /* cause the connection to be aborted. */ + unsigned int i; + for (i = 0; i < uv_simultaneous_server_accepts; i++) { + uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i]; + if (req->accept_socket != INVALID_SOCKET && + !HasOverlappedIoCompleted(&req->u.io.overlapped)) { + closesocket(req->accept_socket); + req->accept_socket = INVALID_SOCKET; + } + } + } + } + + if (tcp->flags & UV_HANDLE_READING) { + tcp->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, tcp); + } + + if (tcp->flags & UV_HANDLE_LISTENING) { + tcp->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, tcp); + } + + if (close_socket) { + closesocket(tcp->socket); + tcp->socket = INVALID_SOCKET; + tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; + } + + tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); + uv__handle_closing(tcp); + + if (tcp->reqs_pending == 0) { + uv_want_endgame(tcp->loop, (uv_handle_t*)tcp); + } +} + + +int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { + WSAPROTOCOL_INFOW protocol_info; + int opt_len; + int err; + + /* Detect the address family of the socket. */ + opt_len = (int) sizeof protocol_info; + if (getsockopt(sock, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &opt_len) == SOCKET_ERROR) { + return uv_translate_sys_error(GetLastError()); + } + + err = uv_tcp_set_socket(handle->loop, + handle, + sock, + protocol_info.iAddressFamily, + 1); + if (err) { + return uv_translate_sys_error(err); + } + + return 0; +} + + +/* This function is an egress point, i.e. it returns libuv errors rather than + * system errors. + */ +int uv__tcp_bind(uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + int err; + + err = uv_tcp_try_bind(handle, addr, addrlen, flags); + if (err) + return uv_translate_sys_error(err); + + return 0; +} + + +/* This function is an egress point, i.e. it returns libuv errors rather than + * system errors. + */ +int uv__tcp_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + uv_connect_cb cb) { + int err; + + err = uv_tcp_try_connect(req, handle, addr, addrlen, cb); + if (err) + return uv_translate_sys_error(err); + + return 0; +} diff --git a/src/win/thread.c b/src/win/thread.c new file mode 100644 index 0000000..91684e9 --- /dev/null +++ b/src/win/thread.c @@ -0,0 +1,697 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include + +#include "uv.h" +#include "internal.h" + + +#define HAVE_CONDVAR_API() (pInitializeConditionVariable != NULL) + +static int uv_cond_fallback_init(uv_cond_t* cond); +static void uv_cond_fallback_destroy(uv_cond_t* cond); +static void uv_cond_fallback_signal(uv_cond_t* cond); +static void uv_cond_fallback_broadcast(uv_cond_t* cond); +static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex); +static int uv_cond_fallback_timedwait(uv_cond_t* cond, + uv_mutex_t* mutex, uint64_t timeout); + +static int uv_cond_condvar_init(uv_cond_t* cond); +static void uv_cond_condvar_destroy(uv_cond_t* cond); +static void uv_cond_condvar_signal(uv_cond_t* cond); +static void uv_cond_condvar_broadcast(uv_cond_t* cond); +static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex); +static int uv_cond_condvar_timedwait(uv_cond_t* cond, + uv_mutex_t* mutex, uint64_t timeout); + + +static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) { + DWORD result; + HANDLE existing_event, created_event; + + created_event = CreateEvent(NULL, 1, 0, NULL); + if (created_event == 0) { + /* Could fail in a low-memory situation? */ + uv_fatal_error(GetLastError(), "CreateEvent"); + } + + existing_event = InterlockedCompareExchangePointer(&guard->event, + created_event, + NULL); + + if (existing_event == NULL) { + /* We won the race */ + callback(); + + result = SetEvent(created_event); + assert(result); + guard->ran = 1; + + } else { + /* We lost the race. Destroy the event we created and wait for the */ + /* existing one to become signaled. */ + CloseHandle(created_event); + result = WaitForSingleObject(existing_event, INFINITE); + assert(result == WAIT_OBJECT_0); + } +} + + +void uv_once(uv_once_t* guard, void (*callback)(void)) { + /* Fast case - avoid WaitForSingleObject. */ + if (guard->ran) { + return; + } + + uv__once_inner(guard, callback); +} + + +/* Verify that uv_thread_t can be stored in a TLS slot. */ +STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*)); + +static uv_key_t uv__current_thread_key; +static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT; + + +static void uv__init_current_thread_key(void) { + if (uv_key_create(&uv__current_thread_key)) + abort(); +} + + +struct thread_ctx { + void (*entry)(void* arg); + void* arg; + uv_thread_t self; +}; + + +static UINT __stdcall uv__thread_start(void* arg) { + struct thread_ctx *ctx_p; + struct thread_ctx ctx; + + ctx_p = arg; + ctx = *ctx_p; + uv__free(ctx_p); + + uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key); + uv_key_set(&uv__current_thread_key, (void*) ctx.self); + + ctx.entry(ctx.arg); + + return 0; +} + + +int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { + struct thread_ctx* ctx; + int err; + HANDLE thread; + + ctx = uv__malloc(sizeof(*ctx)); + if (ctx == NULL) + return UV_ENOMEM; + + ctx->entry = entry; + ctx->arg = arg; + + /* Create the thread in suspended state so we have a chance to pass + * its own creation handle to it */ + thread = (HANDLE) _beginthreadex(NULL, + 0, + uv__thread_start, + ctx, + CREATE_SUSPENDED, + NULL); + if (thread == NULL) { + err = errno; + uv__free(ctx); + } else { + err = 0; + *tid = thread; + ctx->self = thread; + ResumeThread(thread); + } + + switch (err) { + case 0: + return 0; + case EACCES: + return UV_EACCES; + case EAGAIN: + return UV_EAGAIN; + case EINVAL: + return UV_EINVAL; + } + + return UV_EIO; +} + + +uv_thread_t uv_thread_self(void) { + uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key); + return (uv_thread_t) uv_key_get(&uv__current_thread_key); +} + + +int uv_thread_join(uv_thread_t *tid) { + if (WaitForSingleObject(*tid, INFINITE)) + return uv_translate_sys_error(GetLastError()); + else { + CloseHandle(*tid); + *tid = 0; + return 0; + } +} + + +int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { + return *t1 == *t2; +} + + +int uv_mutex_init(uv_mutex_t* mutex) { + InitializeCriticalSection(mutex); + return 0; +} + + +void uv_mutex_destroy(uv_mutex_t* mutex) { + DeleteCriticalSection(mutex); +} + + +void uv_mutex_lock(uv_mutex_t* mutex) { + EnterCriticalSection(mutex); +} + + +int uv_mutex_trylock(uv_mutex_t* mutex) { + if (TryEnterCriticalSection(mutex)) + return 0; + else + return UV_EBUSY; +} + + +void uv_mutex_unlock(uv_mutex_t* mutex) { + LeaveCriticalSection(mutex); +} + + +int uv_rwlock_init(uv_rwlock_t* rwlock) { + /* Initialize the semaphore that acts as the write lock. */ + HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL); + if (handle == NULL) + return uv_translate_sys_error(GetLastError()); + rwlock->state_.write_semaphore_ = handle; + + /* Initialize the critical section protecting the reader count. */ + InitializeCriticalSection(&rwlock->state_.num_readers_lock_); + + /* Initialize the reader count. */ + rwlock->state_.num_readers_ = 0; + + return 0; +} + + +void uv_rwlock_destroy(uv_rwlock_t* rwlock) { + DeleteCriticalSection(&rwlock->state_.num_readers_lock_); + CloseHandle(rwlock->state_.write_semaphore_); +} + + +void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { + /* Acquire the lock that protects the reader count. */ + EnterCriticalSection(&rwlock->state_.num_readers_lock_); + + /* Increase the reader count, and lock for write if this is the first + * reader. + */ + if (++rwlock->state_.num_readers_ == 1) { + DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE); + if (r != WAIT_OBJECT_0) + uv_fatal_error(GetLastError(), "WaitForSingleObject"); + } + + /* Release the lock that protects the reader count. */ + LeaveCriticalSection(&rwlock->state_.num_readers_lock_); +} + + +int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { + int err; + + if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_)) + return UV_EBUSY; + + err = 0; + + if (rwlock->state_.num_readers_ == 0) { + /* Currently there are no other readers, which means that the write lock + * needs to be acquired. + */ + DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0); + if (r == WAIT_OBJECT_0) + rwlock->state_.num_readers_++; + else if (r == WAIT_TIMEOUT) + err = UV_EBUSY; + else if (r == WAIT_FAILED) + uv_fatal_error(GetLastError(), "WaitForSingleObject"); + + } else { + /* The write lock has already been acquired because there are other + * active readers. + */ + rwlock->state_.num_readers_++; + } + + LeaveCriticalSection(&rwlock->state_.num_readers_lock_); + return err; +} + + +void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { + EnterCriticalSection(&rwlock->state_.num_readers_lock_); + + if (--rwlock->state_.num_readers_ == 0) { + if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL)) + uv_fatal_error(GetLastError(), "ReleaseSemaphore"); + } + + LeaveCriticalSection(&rwlock->state_.num_readers_lock_); +} + + +void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { + DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE); + if (r != WAIT_OBJECT_0) + uv_fatal_error(GetLastError(), "WaitForSingleObject"); +} + + +int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { + DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0); + if (r == WAIT_OBJECT_0) + return 0; + else if (r == WAIT_TIMEOUT) + return UV_EBUSY; + else + uv_fatal_error(GetLastError(), "WaitForSingleObject"); +} + + +void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { + if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL)) + uv_fatal_error(GetLastError(), "ReleaseSemaphore"); +} + + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + *sem = CreateSemaphore(NULL, value, INT_MAX, NULL); + if (*sem == NULL) + return uv_translate_sys_error(GetLastError()); + else + return 0; +} + + +void uv_sem_destroy(uv_sem_t* sem) { + if (!CloseHandle(*sem)) + abort(); +} + + +void uv_sem_post(uv_sem_t* sem) { + if (!ReleaseSemaphore(*sem, 1, NULL)) + abort(); +} + + +void uv_sem_wait(uv_sem_t* sem) { + if (WaitForSingleObject(*sem, INFINITE) != WAIT_OBJECT_0) + abort(); +} + + +int uv_sem_trywait(uv_sem_t* sem) { + DWORD r = WaitForSingleObject(*sem, 0); + + if (r == WAIT_OBJECT_0) + return 0; + + if (r == WAIT_TIMEOUT) + return UV_EAGAIN; + + abort(); + return -1; /* Satisfy the compiler. */ +} + + +/* This condition variable implementation is based on the SetEvent solution + * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html + * We could not use the SignalObjectAndWait solution (section 3.4) because + * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and + * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs. + */ + +static int uv_cond_fallback_init(uv_cond_t* cond) { + int err; + + /* Initialize the count to 0. */ + cond->fallback.waiters_count = 0; + + InitializeCriticalSection(&cond->fallback.waiters_count_lock); + + /* Create an auto-reset event. */ + cond->fallback.signal_event = CreateEvent(NULL, /* no security */ + FALSE, /* auto-reset event */ + FALSE, /* non-signaled initially */ + NULL); /* unnamed */ + if (!cond->fallback.signal_event) { + err = GetLastError(); + goto error2; + } + + /* Create a manual-reset event. */ + cond->fallback.broadcast_event = CreateEvent(NULL, /* no security */ + TRUE, /* manual-reset */ + FALSE, /* non-signaled */ + NULL); /* unnamed */ + if (!cond->fallback.broadcast_event) { + err = GetLastError(); + goto error; + } + + return 0; + +error: + CloseHandle(cond->fallback.signal_event); +error2: + DeleteCriticalSection(&cond->fallback.waiters_count_lock); + return uv_translate_sys_error(err); +} + + +static int uv_cond_condvar_init(uv_cond_t* cond) { + pInitializeConditionVariable(&cond->cond_var); + return 0; +} + + +int uv_cond_init(uv_cond_t* cond) { + uv__once_init(); + + if (HAVE_CONDVAR_API()) + return uv_cond_condvar_init(cond); + else + return uv_cond_fallback_init(cond); +} + + +static void uv_cond_fallback_destroy(uv_cond_t* cond) { + if (!CloseHandle(cond->fallback.broadcast_event)) + abort(); + if (!CloseHandle(cond->fallback.signal_event)) + abort(); + DeleteCriticalSection(&cond->fallback.waiters_count_lock); +} + + +static void uv_cond_condvar_destroy(uv_cond_t* cond) { + /* nothing to do */ +} + + +void uv_cond_destroy(uv_cond_t* cond) { + if (HAVE_CONDVAR_API()) + uv_cond_condvar_destroy(cond); + else + uv_cond_fallback_destroy(cond); +} + + +static void uv_cond_fallback_signal(uv_cond_t* cond) { + int have_waiters; + + /* Avoid race conditions. */ + EnterCriticalSection(&cond->fallback.waiters_count_lock); + have_waiters = cond->fallback.waiters_count > 0; + LeaveCriticalSection(&cond->fallback.waiters_count_lock); + + if (have_waiters) + SetEvent(cond->fallback.signal_event); +} + + +static void uv_cond_condvar_signal(uv_cond_t* cond) { + pWakeConditionVariable(&cond->cond_var); +} + + +void uv_cond_signal(uv_cond_t* cond) { + if (HAVE_CONDVAR_API()) + uv_cond_condvar_signal(cond); + else + uv_cond_fallback_signal(cond); +} + + +static void uv_cond_fallback_broadcast(uv_cond_t* cond) { + int have_waiters; + + /* Avoid race conditions. */ + EnterCriticalSection(&cond->fallback.waiters_count_lock); + have_waiters = cond->fallback.waiters_count > 0; + LeaveCriticalSection(&cond->fallback.waiters_count_lock); + + if (have_waiters) + SetEvent(cond->fallback.broadcast_event); +} + + +static void uv_cond_condvar_broadcast(uv_cond_t* cond) { + pWakeAllConditionVariable(&cond->cond_var); +} + + +void uv_cond_broadcast(uv_cond_t* cond) { + if (HAVE_CONDVAR_API()) + uv_cond_condvar_broadcast(cond); + else + uv_cond_fallback_broadcast(cond); +} + + +static int uv_cond_wait_helper(uv_cond_t* cond, uv_mutex_t* mutex, + DWORD dwMilliseconds) { + DWORD result; + int last_waiter; + HANDLE handles[2] = { + cond->fallback.signal_event, + cond->fallback.broadcast_event + }; + + /* Avoid race conditions. */ + EnterCriticalSection(&cond->fallback.waiters_count_lock); + cond->fallback.waiters_count++; + LeaveCriticalSection(&cond->fallback.waiters_count_lock); + + /* It's ok to release the here since Win32 manual-reset events */ + /* maintain state when used with . This avoids the "lost wakeup" */ + /* bug. */ + uv_mutex_unlock(mutex); + + /* Wait for either event to become signaled due to being */ + /* called or being called. */ + result = WaitForMultipleObjects(2, handles, FALSE, dwMilliseconds); + + EnterCriticalSection(&cond->fallback.waiters_count_lock); + cond->fallback.waiters_count--; + last_waiter = result == WAIT_OBJECT_0 + 1 + && cond->fallback.waiters_count == 0; + LeaveCriticalSection(&cond->fallback.waiters_count_lock); + + /* Some thread called . */ + if (last_waiter) { + /* We're the last waiter to be notified or to stop waiting, so reset the */ + /* the manual-reset event. */ + ResetEvent(cond->fallback.broadcast_event); + } + + /* Reacquire the . */ + uv_mutex_lock(mutex); + + if (result == WAIT_OBJECT_0 || result == WAIT_OBJECT_0 + 1) + return 0; + + if (result == WAIT_TIMEOUT) + return UV_ETIMEDOUT; + + abort(); + return -1; /* Satisfy the compiler. */ +} + + +static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex) { + if (uv_cond_wait_helper(cond, mutex, INFINITE)) + abort(); +} + + +static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex) { + if (!pSleepConditionVariableCS(&cond->cond_var, mutex, INFINITE)) + abort(); +} + + +void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) { + if (HAVE_CONDVAR_API()) + uv_cond_condvar_wait(cond, mutex); + else + uv_cond_fallback_wait(cond, mutex); +} + + +static int uv_cond_fallback_timedwait(uv_cond_t* cond, + uv_mutex_t* mutex, uint64_t timeout) { + return uv_cond_wait_helper(cond, mutex, (DWORD)(timeout / 1e6)); +} + + +static int uv_cond_condvar_timedwait(uv_cond_t* cond, + uv_mutex_t* mutex, uint64_t timeout) { + if (pSleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6))) + return 0; + if (GetLastError() != ERROR_TIMEOUT) + abort(); + return UV_ETIMEDOUT; +} + + +int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, + uint64_t timeout) { + if (HAVE_CONDVAR_API()) + return uv_cond_condvar_timedwait(cond, mutex, timeout); + else + return uv_cond_fallback_timedwait(cond, mutex, timeout); +} + + +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + int err; + + barrier->n = count; + barrier->count = 0; + + err = uv_mutex_init(&barrier->mutex); + if (err) + return err; + + err = uv_sem_init(&barrier->turnstile1, 0); + if (err) + goto error2; + + err = uv_sem_init(&barrier->turnstile2, 1); + if (err) + goto error; + + return 0; + +error: + uv_sem_destroy(&barrier->turnstile1); +error2: + uv_mutex_destroy(&barrier->mutex); + return err; + +} + + +void uv_barrier_destroy(uv_barrier_t* barrier) { + uv_sem_destroy(&barrier->turnstile2); + uv_sem_destroy(&barrier->turnstile1); + uv_mutex_destroy(&barrier->mutex); +} + + +int uv_barrier_wait(uv_barrier_t* barrier) { + int serial_thread; + + uv_mutex_lock(&barrier->mutex); + if (++barrier->count == barrier->n) { + uv_sem_wait(&barrier->turnstile2); + uv_sem_post(&barrier->turnstile1); + } + uv_mutex_unlock(&barrier->mutex); + + uv_sem_wait(&barrier->turnstile1); + uv_sem_post(&barrier->turnstile1); + + uv_mutex_lock(&barrier->mutex); + serial_thread = (--barrier->count == 0); + if (serial_thread) { + uv_sem_wait(&barrier->turnstile1); + uv_sem_post(&barrier->turnstile2); + } + uv_mutex_unlock(&barrier->mutex); + + uv_sem_wait(&barrier->turnstile2); + uv_sem_post(&barrier->turnstile2); + return serial_thread; +} + + +int uv_key_create(uv_key_t* key) { + key->tls_index = TlsAlloc(); + if (key->tls_index == TLS_OUT_OF_INDEXES) + return UV_ENOMEM; + return 0; +} + + +void uv_key_delete(uv_key_t* key) { + if (TlsFree(key->tls_index) == FALSE) + abort(); + key->tls_index = TLS_OUT_OF_INDEXES; +} + + +void* uv_key_get(uv_key_t* key) { + void* value; + + value = TlsGetValue(key->tls_index); + if (value == NULL) + if (GetLastError() != ERROR_SUCCESS) + abort(); + + return value; +} + + +void uv_key_set(uv_key_t* key, void* value) { + if (TlsSetValue(key->tls_index, value) == FALSE) + abort(); +} diff --git a/src/win/timer.c b/src/win/timer.c new file mode 100644 index 0000000..27ca771 --- /dev/null +++ b/src/win/timer.c @@ -0,0 +1,195 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "tree.h" +#include "handle-inl.h" + + +/* The number of milliseconds in one second. */ +#define UV__MILLISEC 1000 + + +void uv_update_time(uv_loop_t* loop) { + uint64_t new_time = uv__hrtime(UV__MILLISEC); + assert(new_time >= loop->time); + loop->time = new_time; +} + + +static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) { + if (a->due < b->due) + return -1; + if (a->due > b->due) + return 1; + /* + * compare start_id when both has the same due. start_id is + * allocated with loop->timer_counter in uv_timer_start(). + */ + if (a->start_id < b->start_id) + return -1; + if (a->start_id > b->start_id) + return 1; + return 0; +} + + +RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare); + + +int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { + uv__handle_init(loop, (uv_handle_t*) handle, UV_TIMER); + handle->timer_cb = NULL; + handle->repeat = 0; + + return 0; +} + + +void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) { + if (handle->flags & UV__HANDLE_CLOSING) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); + } +} + + +static uint64_t get_clamped_due_time(uint64_t loop_time, uint64_t timeout) { + uint64_t clamped_timeout; + + clamped_timeout = loop_time + timeout; + if (clamped_timeout < timeout) + clamped_timeout = (uint64_t) -1; + + return clamped_timeout; +} + + +int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout, + uint64_t repeat) { + uv_loop_t* loop = handle->loop; + uv_timer_t* old; + + if (timer_cb == NULL) + return UV_EINVAL; + + if (uv__is_active(handle)) + uv_timer_stop(handle); + + handle->timer_cb = timer_cb; + handle->due = get_clamped_due_time(loop->time, timeout); + handle->repeat = repeat; + uv__handle_start(handle); + + /* start_id is the second index to be compared in uv__timer_cmp() */ + handle->start_id = handle->loop->timer_counter++; + + old = RB_INSERT(uv_timer_tree_s, &loop->timers, handle); + assert(old == NULL); + + return 0; +} + + +int uv_timer_stop(uv_timer_t* handle) { + uv_loop_t* loop = handle->loop; + + if (!uv__is_active(handle)) + return 0; + + RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); + uv__handle_stop(handle); + + return 0; +} + + +int uv_timer_again(uv_timer_t* handle) { + /* If timer_cb is NULL that means that the timer was never started. */ + if (!handle->timer_cb) { + return UV_EINVAL; + } + + if (handle->repeat) { + uv_timer_stop(handle); + uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat); + } + + return 0; +} + + +void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) { + assert(handle->type == UV_TIMER); + handle->repeat = repeat; +} + + +uint64_t uv_timer_get_repeat(const uv_timer_t* handle) { + assert(handle->type == UV_TIMER); + return handle->repeat; +} + + +DWORD uv__next_timeout(const uv_loop_t* loop) { + uv_timer_t* timer; + int64_t delta; + + /* Check if there are any running timers + * Need to cast away const first, since RB_MIN doesn't know what we are + * going to do with this return value, it can't be marked const + */ + timer = RB_MIN(uv_timer_tree_s, &((uv_loop_t*)loop)->timers); + if (timer) { + delta = timer->due - loop->time; + if (delta >= UINT_MAX - 1) { + /* A timeout value of UINT_MAX means infinite, so that's no good. */ + return UINT_MAX - 1; + } else if (delta < 0) { + /* Negative timeout values are not allowed */ + return 0; + } else { + return (DWORD)delta; + } + } else { + /* No timers */ + return INFINITE; + } +} + + +void uv_process_timers(uv_loop_t* loop) { + uv_timer_t* timer; + + /* Call timer callbacks */ + for (timer = RB_MIN(uv_timer_tree_s, &loop->timers); + timer != NULL && timer->due <= loop->time; + timer = RB_MIN(uv_timer_tree_s, &loop->timers)) { + + uv_timer_stop(timer); + uv_timer_again(timer); + timer->timer_cb((uv_timer_t*) timer); + } +} diff --git a/src/win/tty.c b/src/win/tty.c new file mode 100644 index 0000000..9bb7879 --- /dev/null +++ b/src/win/tty.c @@ -0,0 +1,2175 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#ifndef COMMON_LVB_REVERSE_VIDEO +# define COMMON_LVB_REVERSE_VIDEO 0x4000 +#endif + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" + +#ifndef InterlockedOr +# define InterlockedOr _InterlockedOr +#endif + +#define UNICODE_REPLACEMENT_CHARACTER (0xfffd) + +#define ANSI_NORMAL 0x00 +#define ANSI_ESCAPE_SEEN 0x02 +#define ANSI_CSI 0x04 +#define ANSI_ST_CONTROL 0x08 +#define ANSI_IGNORE 0x10 +#define ANSI_IN_ARG 0x20 +#define ANSI_IN_STRING 0x40 +#define ANSI_BACKSLASH_SEEN 0x80 + +#define MAX_INPUT_BUFFER_LENGTH 8192 + + +static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info); +static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); +static int uv__cancel_read_console(uv_tty_t* handle); + + +/* Null uv_buf_t */ +static const uv_buf_t uv_null_buf_ = { 0, NULL }; + +enum uv__read_console_status_e { + NOT_STARTED, + IN_PROGRESS, + TRAP_REQUESTED, + COMPLETED +}; + +static volatile LONG uv__read_console_status = NOT_STARTED; +static volatile LONG uv__restore_screen_state; +static CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state; + + +/* + * The console virtual window. + * + * Normally cursor movement in windows is relative to the console screen buffer, + * e.g. the application is allowed to overwrite the 'history'. This is very + * inconvenient, it makes absolute cursor movement pretty useless. There is + * also the concept of 'client rect' which is defined by the actual size of + * the console window and the scroll position of the screen buffer, but it's + * very volatile because it changes when the user scrolls. + * + * To make cursor movement behave sensibly we define a virtual window to which + * cursor movement is confined. The virtual window is always as wide as the + * console screen buffer, but it's height is defined by the size of the + * console window. The top of the virtual window aligns with the position + * of the caret when the first stdout/err handle is created, unless that would + * mean that it would extend beyond the bottom of the screen buffer - in that + * that case it's located as far down as possible. + * + * When the user writes a long text or many newlines, such that the output + * reaches beyond the bottom of the virtual window, the virtual window is + * shifted downwards, but not resized. + * + * Since all tty i/o happens on the same console, this window is shared + * between all stdout/stderr handles. + */ + +static int uv_tty_virtual_offset = -1; +static int uv_tty_virtual_height = -1; +static int uv_tty_virtual_width = -1; + +static CRITICAL_SECTION uv_tty_output_lock; + +static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE; + +static WORD uv_tty_default_text_attributes = + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + +static char uv_tty_default_fg_color = 7; +static char uv_tty_default_bg_color = 0; +static char uv_tty_default_fg_bright = 0; +static char uv_tty_default_bg_bright = 0; +static char uv_tty_default_inverse = 0; + + +void uv_console_init() { + InitializeCriticalSection(&uv_tty_output_lock); +} + + +int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { + HANDLE handle; + CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; + + handle = (HANDLE) uv__get_osfhandle(fd); + if (handle == INVALID_HANDLE_VALUE) + return UV_EBADF; + + if (fd <= 2) { + /* In order to avoid closing a stdio file descriptor 0-2, duplicate the + * underlying OS handle and forget about the original fd. + * We could also opt to use the original OS handle and just never close it, + * but then there would be no reliable way to cancel pending read operations + * upon close. + */ + if (!DuplicateHandle(INVALID_HANDLE_VALUE, + handle, + INVALID_HANDLE_VALUE, + &handle, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)) + return uv_translate_sys_error(GetLastError()); + fd = -1; + } + + if (!readable) { + /* Obtain the screen buffer info with the output handle. */ + if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) { + return uv_translate_sys_error(GetLastError()); + } + + /* Obtain the the tty_output_lock because the virtual window state is */ + /* shared between all uv_tty_t handles. */ + EnterCriticalSection(&uv_tty_output_lock); + + /* Store the global tty output handle. This handle is used by TTY read */ + /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */ + /* is received. */ + uv_tty_output_handle = handle; + + /* Remember the original console text attributes. */ + uv_tty_capture_initial_style(&screen_buffer_info); + + uv_tty_update_virtual_window(&screen_buffer_info); + + LeaveCriticalSection(&uv_tty_output_lock); + } + + + uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY); + uv_connection_init((uv_stream_t*) tty); + + tty->handle = handle; + tty->u.fd = fd; + tty->reqs_pending = 0; + tty->flags |= UV_HANDLE_BOUND; + + if (readable) { + /* Initialize TTY input specific fields. */ + tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE; + /* TODO: remove me in v2.x. */ + tty->tty.rd.unused_ = NULL; + tty->tty.rd.read_line_buffer = uv_null_buf_; + tty->tty.rd.read_raw_wait = NULL; + + /* Init keycode-to-vt100 mapper state. */ + tty->tty.rd.last_key_len = 0; + tty->tty.rd.last_key_offset = 0; + tty->tty.rd.last_utf16_high_surrogate = 0; + memset(&tty->tty.rd.last_input_record, 0, sizeof tty->tty.rd.last_input_record); + } else { + /* TTY output specific fields. */ + tty->flags |= UV_HANDLE_WRITABLE; + + /* Init utf8-to-utf16 conversion state. */ + tty->tty.wr.utf8_bytes_left = 0; + tty->tty.wr.utf8_codepoint = 0; + + /* Initialize eol conversion state */ + tty->tty.wr.previous_eol = 0; + + /* Init ANSI parser state. */ + tty->tty.wr.ansi_parser_state = ANSI_NORMAL; + } + + return 0; +} + + +/* Set the default console text attributes based on how the console was + * configured when libuv started. + */ +static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) { + static int style_captured = 0; + + /* Only do this once. + Assumption: Caller has acquired uv_tty_output_lock. */ + if (style_captured) + return; + + /* Save raw win32 attributes. */ + uv_tty_default_text_attributes = info->wAttributes; + + /* Convert black text on black background to use white text. */ + if (uv_tty_default_text_attributes == 0) + uv_tty_default_text_attributes = 7; + + /* Convert Win32 attributes to ANSI colors. */ + uv_tty_default_fg_color = 0; + uv_tty_default_bg_color = 0; + uv_tty_default_fg_bright = 0; + uv_tty_default_bg_bright = 0; + uv_tty_default_inverse = 0; + + if (uv_tty_default_text_attributes & FOREGROUND_RED) + uv_tty_default_fg_color |= 1; + + if (uv_tty_default_text_attributes & FOREGROUND_GREEN) + uv_tty_default_fg_color |= 2; + + if (uv_tty_default_text_attributes & FOREGROUND_BLUE) + uv_tty_default_fg_color |= 4; + + if (uv_tty_default_text_attributes & BACKGROUND_RED) + uv_tty_default_bg_color |= 1; + + if (uv_tty_default_text_attributes & BACKGROUND_GREEN) + uv_tty_default_bg_color |= 2; + + if (uv_tty_default_text_attributes & BACKGROUND_BLUE) + uv_tty_default_bg_color |= 4; + + if (uv_tty_default_text_attributes & FOREGROUND_INTENSITY) + uv_tty_default_fg_bright = 1; + + if (uv_tty_default_text_attributes & BACKGROUND_INTENSITY) + uv_tty_default_bg_bright = 1; + + if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO) + uv_tty_default_inverse = 1; + + style_captured = 1; +} + + +int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { + DWORD flags; + unsigned char was_reading; + uv_alloc_cb alloc_cb; + uv_read_cb read_cb; + int err; + + if (!(tty->flags & UV_HANDLE_TTY_READABLE)) { + return UV_EINVAL; + } + + if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) { + return 0; + } + + switch (mode) { + case UV_TTY_MODE_NORMAL: + flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; + break; + case UV_TTY_MODE_RAW: + flags = ENABLE_WINDOW_INPUT; + break; + case UV_TTY_MODE_IO: + return UV_ENOTSUP; + default: + return UV_EINVAL; + } + + if (!SetConsoleMode(tty->handle, flags)) { + return uv_translate_sys_error(GetLastError()); + } + + /* If currently reading, stop, and restart reading. */ + if (tty->flags & UV_HANDLE_READING) { + was_reading = 1; + alloc_cb = tty->alloc_cb; + read_cb = tty->read_cb; + err = uv_tty_read_stop(tty); + if (err) { + return uv_translate_sys_error(err); + } + } else { + was_reading = 0; + } + + /* Update flag. */ + tty->flags &= ~UV_HANDLE_TTY_RAW; + tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0; + + /* If we just stopped reading, restart. */ + if (was_reading) { + err = uv_tty_read_start(tty, alloc_cb, read_cb); + if (err) { + return uv_translate_sys_error(err); + } + } + + return 0; +} + + +int uv_is_tty(uv_file file) { + DWORD result; + return GetConsoleMode((HANDLE) _get_osfhandle(file), &result) != 0; +} + + +int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { + CONSOLE_SCREEN_BUFFER_INFO info; + + if (!GetConsoleScreenBufferInfo(tty->handle, &info)) { + return uv_translate_sys_error(GetLastError()); + } + + EnterCriticalSection(&uv_tty_output_lock); + uv_tty_update_virtual_window(&info); + LeaveCriticalSection(&uv_tty_output_lock); + + *width = uv_tty_virtual_width; + *height = uv_tty_virtual_height; + + return 0; +} + + +static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) { + uv_loop_t* loop; + uv_tty_t* handle; + uv_req_t* req; + + assert(data); + assert(!didTimeout); + + req = (uv_req_t*) data; + handle = (uv_tty_t*) req->data; + loop = handle->loop; + + UnregisterWait(handle->tty.rd.read_raw_wait); + handle->tty.rd.read_raw_wait = NULL; + + SET_REQ_SUCCESS(req); + POST_COMPLETION_FOR_REQ(loop, req); +} + + +static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) { + uv_read_t* req; + BOOL r; + + assert(handle->flags & UV_HANDLE_READING); + assert(!(handle->flags & UV_HANDLE_READ_PENDING)); + + assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE); + + handle->tty.rd.read_line_buffer = uv_null_buf_; + + req = &handle->read_req; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + + r = RegisterWaitForSingleObject(&handle->tty.rd.read_raw_wait, + handle->handle, + uv_tty_post_raw_read, + (void*) req, + INFINITE, + WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE); + if (!r) { + handle->tty.rd.read_raw_wait = NULL; + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + } + + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; +} + + +static DWORD CALLBACK uv_tty_line_read_thread(void* data) { + uv_loop_t* loop; + uv_tty_t* handle; + uv_req_t* req; + DWORD bytes, read_bytes; + WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3]; + DWORD chars, read_chars; + LONG status; + COORD pos; + + assert(data); + + req = (uv_req_t*) data; + handle = (uv_tty_t*) req->data; + loop = handle->loop; + + assert(handle->tty.rd.read_line_buffer.base != NULL); + assert(handle->tty.rd.read_line_buffer.len > 0); + + /* ReadConsole can't handle big buffers. */ + if (handle->tty.rd.read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) { + bytes = handle->tty.rd.read_line_buffer.len; + } else { + bytes = MAX_INPUT_BUFFER_LENGTH; + } + + /* At last, unicode! */ + /* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */ + chars = bytes / 3; + + status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS); + if (status == TRAP_REQUESTED) { + SET_REQ_SUCCESS(req); + req->u.io.overlapped.InternalHigh = 0; + POST_COMPLETION_FOR_REQ(loop, req); + return 0; + } + + if (ReadConsoleW(handle->handle, + (void*) utf16, + chars, + &read_chars, + NULL)) { + read_bytes = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + read_chars, + handle->tty.rd.read_line_buffer.base, + bytes, + NULL, + NULL); + SET_REQ_SUCCESS(req); + req->u.io.overlapped.InternalHigh = read_bytes; + } else { + SET_REQ_ERROR(req, GetLastError()); + } + + InterlockedExchange(&uv__read_console_status, COMPLETED); + + /* If we canceled the read by sending a VK_RETURN event, restore the screen + state to undo the visual effect of the VK_RETURN*/ + if (InterlockedOr(&uv__restore_screen_state, 0)) { + HANDLE active_screen_buffer = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (active_screen_buffer != INVALID_HANDLE_VALUE) { + pos = uv__saved_screen_state.dwCursorPosition; + + /* If the cursor was at the bottom line of the screen buffer, the + VK_RETURN would have caused the buffer contents to scroll up by + one line. The right position to reset the cursor to is therefore one + line higher */ + if (pos.Y == uv__saved_screen_state.dwSize.Y - 1) + pos.Y--; + + SetConsoleCursorPosition(active_screen_buffer, pos); + CloseHandle(active_screen_buffer); + } + } + + POST_COMPLETION_FOR_REQ(loop, req); + return 0; +} + + +static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { + uv_read_t* req; + BOOL r; + + assert(handle->flags & UV_HANDLE_READING); + assert(!(handle->flags & UV_HANDLE_READ_PENDING)); + assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE); + + req = &handle->read_req; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + + handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer); + if (handle->tty.rd.read_line_buffer.base == NULL || + handle->tty.rd.read_line_buffer.len == 0) { + handle->read_cb((uv_stream_t*) handle, + UV_ENOBUFS, + &handle->tty.rd.read_line_buffer); + return; + } + assert(handle->tty.rd.read_line_buffer.base != NULL); + + /* Reset flags No locking is required since there cannot be a line read + in progress. We are also relying on the memory barrier provided by + QueueUserWorkItem*/ + uv__restore_screen_state = FALSE; + uv__read_console_status = NOT_STARTED; + r = QueueUserWorkItem(uv_tty_line_read_thread, + (void*) req, + WT_EXECUTELONGFUNCTION); + if (!r) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + } + + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; +} + + +static void uv_tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) { + if (handle->flags & UV_HANDLE_TTY_RAW) { + uv_tty_queue_read_raw(loop, handle); + } else { + uv_tty_queue_read_line(loop, handle); + } +} + + +static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl, + size_t* len) { +#define VK_CASE(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str) \ + case (vk): \ + if (shift && ctrl) { \ + *len = sizeof shift_ctrl_str; \ + return "\033" shift_ctrl_str; \ + } else if (shift) { \ + *len = sizeof shift_str ; \ + return "\033" shift_str; \ + } else if (ctrl) { \ + *len = sizeof ctrl_str; \ + return "\033" ctrl_str; \ + } else { \ + *len = sizeof normal_str; \ + return "\033" normal_str; \ + } + + switch (code) { + /* These mappings are the same as Cygwin's. Unmodified and alt-modified */ + /* keypad keys comply with linux console, modifiers comply with xterm */ + /* modifier usage. F1..f12 and shift-f1..f10 comply with linux console, */ + /* f6..f12 with and without modifiers comply with rxvt. */ + VK_CASE(VK_INSERT, "[2~", "[2;2~", "[2;5~", "[2;6~") + VK_CASE(VK_END, "[4~", "[4;2~", "[4;5~", "[4;6~") + VK_CASE(VK_DOWN, "[B", "[1;2B", "[1;5B", "[1;6B") + VK_CASE(VK_NEXT, "[6~", "[6;2~", "[6;5~", "[6;6~") + VK_CASE(VK_LEFT, "[D", "[1;2D", "[1;5D", "[1;6D") + VK_CASE(VK_CLEAR, "[G", "[1;2G", "[1;5G", "[1;6G") + VK_CASE(VK_RIGHT, "[C", "[1;2C", "[1;5C", "[1;6C") + VK_CASE(VK_UP, "[A", "[1;2A", "[1;5A", "[1;6A") + VK_CASE(VK_HOME, "[1~", "[1;2~", "[1;5~", "[1;6~") + VK_CASE(VK_PRIOR, "[5~", "[5;2~", "[5;5~", "[5;6~") + VK_CASE(VK_DELETE, "[3~", "[3;2~", "[3;5~", "[3;6~") + VK_CASE(VK_NUMPAD0, "[2~", "[2;2~", "[2;5~", "[2;6~") + VK_CASE(VK_NUMPAD1, "[4~", "[4;2~", "[4;5~", "[4;6~") + VK_CASE(VK_NUMPAD2, "[B", "[1;2B", "[1;5B", "[1;6B") + VK_CASE(VK_NUMPAD3, "[6~", "[6;2~", "[6;5~", "[6;6~") + VK_CASE(VK_NUMPAD4, "[D", "[1;2D", "[1;5D", "[1;6D") + VK_CASE(VK_NUMPAD5, "[G", "[1;2G", "[1;5G", "[1;6G") + VK_CASE(VK_NUMPAD6, "[C", "[1;2C", "[1;5C", "[1;6C") + VK_CASE(VK_NUMPAD7, "[A", "[1;2A", "[1;5A", "[1;6A") + VK_CASE(VK_NUMPAD8, "[1~", "[1;2~", "[1;5~", "[1;6~") + VK_CASE(VK_NUMPAD9, "[5~", "[5;2~", "[5;5~", "[5;6~") + VK_CASE(VK_DECIMAL, "[3~", "[3;2~", "[3;5~", "[3;6~") + VK_CASE(VK_F1, "[[A", "[23~", "[11^", "[23^" ) + VK_CASE(VK_F2, "[[B", "[24~", "[12^", "[24^" ) + VK_CASE(VK_F3, "[[C", "[25~", "[13^", "[25^" ) + VK_CASE(VK_F4, "[[D", "[26~", "[14^", "[26^" ) + VK_CASE(VK_F5, "[[E", "[28~", "[15^", "[28^" ) + VK_CASE(VK_F6, "[17~", "[29~", "[17^", "[29^" ) + VK_CASE(VK_F7, "[18~", "[31~", "[18^", "[31^" ) + VK_CASE(VK_F8, "[19~", "[32~", "[19^", "[32^" ) + VK_CASE(VK_F9, "[20~", "[33~", "[20^", "[33^" ) + VK_CASE(VK_F10, "[21~", "[34~", "[21^", "[34^" ) + VK_CASE(VK_F11, "[23~", "[23$", "[23^", "[23@" ) + VK_CASE(VK_F12, "[24~", "[24$", "[24^", "[24@" ) + + default: + *len = 0; + return NULL; + } +#undef VK_CASE +} + + +void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* req) { + /* Shortcut for handle->tty.rd.last_input_record.Event.KeyEvent. */ +#define KEV handle->tty.rd.last_input_record.Event.KeyEvent + + DWORD records_left, records_read; + uv_buf_t buf; + off_t buf_used; + + assert(handle->type == UV_TTY); + assert(handle->flags & UV_HANDLE_TTY_READABLE); + handle->flags &= ~UV_HANDLE_READ_PENDING; + + if (!(handle->flags & UV_HANDLE_READING) || + !(handle->flags & UV_HANDLE_TTY_RAW)) { + goto out; + } + + if (!REQ_SUCCESS(req)) { + /* An error occurred while waiting for the event. */ + if ((handle->flags & UV_HANDLE_READING)) { + handle->flags &= ~UV_HANDLE_READING; + handle->read_cb((uv_stream_t*)handle, + uv_translate_sys_error(GET_REQ_ERROR(req)), + &uv_null_buf_); + } + goto out; + } + + /* Fetch the number of events */ + if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb((uv_stream_t*)handle, + uv_translate_sys_error(GetLastError()), + &uv_null_buf_); + goto out; + } + + /* Windows sends a lot of events that we're not interested in, so buf */ + /* will be allocated on demand, when there's actually something to emit. */ + buf = uv_null_buf_; + buf_used = 0; + + while ((records_left > 0 || handle->tty.rd.last_key_len > 0) && + (handle->flags & UV_HANDLE_READING)) { + if (handle->tty.rd.last_key_len == 0) { + /* Read the next input record */ + if (!ReadConsoleInputW(handle->handle, + &handle->tty.rd.last_input_record, + 1, + &records_read)) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb((uv_stream_t*) handle, + uv_translate_sys_error(GetLastError()), + &buf); + goto out; + } + records_left--; + + /* If the window was resized, recompute the virtual window size. This */ + /* will trigger a SIGWINCH signal if the window size changed in an */ + /* way that matters to libuv. */ + if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) { + CONSOLE_SCREEN_BUFFER_INFO info; + + EnterCriticalSection(&uv_tty_output_lock); + + if (uv_tty_output_handle != INVALID_HANDLE_VALUE && + GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) { + uv_tty_update_virtual_window(&info); + } + + LeaveCriticalSection(&uv_tty_output_lock); + + continue; + } + + /* Ignore other events that are not key or resize events. */ + if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) { + continue; + } + + /* Ignore keyup events, unless the left alt key was held and a valid */ + /* unicode character was emitted. */ + if (!KEV.bKeyDown && !(((KEV.dwControlKeyState & LEFT_ALT_PRESSED) || + KEV.wVirtualKeyCode==VK_MENU) && KEV.uChar.UnicodeChar != 0)) { + continue; + } + + /* Ignore keypresses to numpad number keys if the left alt is held */ + /* because the user is composing a character, or windows simulating */ + /* this. */ + if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) && + !(KEV.dwControlKeyState & ENHANCED_KEY) && + (KEV.wVirtualKeyCode == VK_INSERT || + KEV.wVirtualKeyCode == VK_END || + KEV.wVirtualKeyCode == VK_DOWN || + KEV.wVirtualKeyCode == VK_NEXT || + KEV.wVirtualKeyCode == VK_LEFT || + KEV.wVirtualKeyCode == VK_CLEAR || + KEV.wVirtualKeyCode == VK_RIGHT || + KEV.wVirtualKeyCode == VK_HOME || + KEV.wVirtualKeyCode == VK_UP || + KEV.wVirtualKeyCode == VK_PRIOR || + KEV.wVirtualKeyCode == VK_NUMPAD0 || + KEV.wVirtualKeyCode == VK_NUMPAD1 || + KEV.wVirtualKeyCode == VK_NUMPAD2 || + KEV.wVirtualKeyCode == VK_NUMPAD3 || + KEV.wVirtualKeyCode == VK_NUMPAD4 || + KEV.wVirtualKeyCode == VK_NUMPAD5 || + KEV.wVirtualKeyCode == VK_NUMPAD6 || + KEV.wVirtualKeyCode == VK_NUMPAD7 || + KEV.wVirtualKeyCode == VK_NUMPAD8 || + KEV.wVirtualKeyCode == VK_NUMPAD9)) { + continue; + } + + if (KEV.uChar.UnicodeChar != 0) { + int prefix_len, char_len; + + /* Character key pressed */ + if (KEV.uChar.UnicodeChar >= 0xD800 && + KEV.uChar.UnicodeChar < 0xDC00) { + /* UTF-16 high surrogate */ + handle->tty.rd.last_utf16_high_surrogate = KEV.uChar.UnicodeChar; + continue; + } + + /* Prefix with \u033 if alt was held, but alt was not used as part */ + /* a compose sequence. */ + if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) + && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED | + RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) { + handle->tty.rd.last_key[0] = '\033'; + prefix_len = 1; + } else { + prefix_len = 0; + } + + if (KEV.uChar.UnicodeChar >= 0xDC00 && + KEV.uChar.UnicodeChar < 0xE000) { + /* UTF-16 surrogate pair */ + WCHAR utf16_buffer[2] = { handle->tty.rd.last_utf16_high_surrogate, + KEV.uChar.UnicodeChar}; + char_len = WideCharToMultiByte(CP_UTF8, + 0, + utf16_buffer, + 2, + &handle->tty.rd.last_key[prefix_len], + sizeof handle->tty.rd.last_key, + NULL, + NULL); + } else { + /* Single UTF-16 character */ + char_len = WideCharToMultiByte(CP_UTF8, + 0, + &KEV.uChar.UnicodeChar, + 1, + &handle->tty.rd.last_key[prefix_len], + sizeof handle->tty.rd.last_key, + NULL, + NULL); + } + + /* Whatever happened, the last character wasn't a high surrogate. */ + handle->tty.rd.last_utf16_high_surrogate = 0; + + /* If the utf16 character(s) couldn't be converted something must */ + /* be wrong. */ + if (!char_len) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb((uv_stream_t*) handle, + uv_translate_sys_error(GetLastError()), + &buf); + goto out; + } + + handle->tty.rd.last_key_len = (unsigned char) (prefix_len + char_len); + handle->tty.rd.last_key_offset = 0; + continue; + + } else { + /* Function key pressed */ + const char* vt100; + size_t prefix_len, vt100_len; + + vt100 = get_vt100_fn_key(KEV.wVirtualKeyCode, + !!(KEV.dwControlKeyState & SHIFT_PRESSED), + !!(KEV.dwControlKeyState & ( + LEFT_CTRL_PRESSED | + RIGHT_CTRL_PRESSED)), + &vt100_len); + + /* If we were unable to map to a vt100 sequence, just ignore. */ + if (!vt100) { + continue; + } + + /* Prefix with \x033 when the alt key was held. */ + if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) { + handle->tty.rd.last_key[0] = '\033'; + prefix_len = 1; + } else { + prefix_len = 0; + } + + /* Copy the vt100 sequence to the handle buffer. */ + assert(prefix_len + vt100_len < sizeof handle->tty.rd.last_key); + memcpy(&handle->tty.rd.last_key[prefix_len], vt100, vt100_len); + + handle->tty.rd.last_key_len = (unsigned char) (prefix_len + vt100_len); + handle->tty.rd.last_key_offset = 0; + continue; + } + } else { + /* Copy any bytes left from the last keypress to the user buffer. */ + if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) { + /* Allocate a buffer if needed */ + if (buf_used == 0) { + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 1024, &buf); + if (buf.base == NULL || buf.len == 0) { + handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); + goto out; + } + assert(buf.base != NULL); + } + + buf.base[buf_used++] = handle->tty.rd.last_key[handle->tty.rd.last_key_offset++]; + + /* If the buffer is full, emit it */ + if ((size_t) buf_used == buf.len) { + handle->read_cb((uv_stream_t*) handle, buf_used, &buf); + buf = uv_null_buf_; + buf_used = 0; + } + + continue; + } + + /* Apply dwRepeat from the last input record. */ + if (--KEV.wRepeatCount > 0) { + handle->tty.rd.last_key_offset = 0; + continue; + } + + handle->tty.rd.last_key_len = 0; + continue; + } + } + + /* Send the buffer back to the user */ + if (buf_used > 0) { + handle->read_cb((uv_stream_t*) handle, buf_used, &buf); + } + + out: + /* Wait for more input events. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_tty_queue_read(loop, handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); + +#undef KEV +} + + + +void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* req) { + uv_buf_t buf; + + assert(handle->type == UV_TTY); + assert(handle->flags & UV_HANDLE_TTY_READABLE); + + buf = handle->tty.rd.read_line_buffer; + + handle->flags &= ~UV_HANDLE_READ_PENDING; + handle->tty.rd.read_line_buffer = uv_null_buf_; + + if (!REQ_SUCCESS(req)) { + /* Read was not successful */ + if (handle->flags & UV_HANDLE_READING) { + /* Real error */ + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb((uv_stream_t*) handle, + uv_translate_sys_error(GET_REQ_ERROR(req)), + &buf); + } else { + /* The read was cancelled, or whatever we don't care */ + handle->read_cb((uv_stream_t*) handle, 0, &buf); + } + + } else { + if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { + /* Read successful */ + /* TODO: read unicode, convert to utf-8 */ + DWORD bytes = req->u.io.overlapped.InternalHigh; + handle->read_cb((uv_stream_t*) handle, bytes, &buf); + } else { + handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING; + handle->read_cb((uv_stream_t*) handle, 0, &buf); + } + } + + /* Wait for more input events. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_tty_queue_read(loop, handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* req) { + assert(handle->type == UV_TTY); + assert(handle->flags & UV_HANDLE_TTY_READABLE); + + /* If the read_line_buffer member is zero, it must have been an raw read. */ + /* Otherwise it was a line-buffered read. */ + /* FIXME: This is quite obscure. Use a flag or something. */ + if (handle->tty.rd.read_line_buffer.len == 0) { + uv_process_tty_read_raw_req(loop, handle, req); + } else { + uv_process_tty_read_line_req(loop, handle, req); + } +} + + +int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { + uv_loop_t* loop = handle->loop; + + if (!(handle->flags & UV_HANDLE_TTY_READABLE)) { + return ERROR_INVALID_PARAMETER; + } + + handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb = read_cb; + handle->alloc_cb = alloc_cb; + + /* If reading was stopped and then started again, there could still be a */ + /* read request pending. */ + if (handle->flags & UV_HANDLE_READ_PENDING) { + return 0; + } + + /* Maybe the user stopped reading half-way while processing key events. */ + /* Short-circuit if this could be the case. */ + if (handle->tty.rd.last_key_len > 0) { + SET_REQ_SUCCESS(&handle->read_req); + uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req); + return 0; + } + + uv_tty_queue_read(loop, handle); + + return 0; +} + + +int uv_tty_read_stop(uv_tty_t* handle) { + INPUT_RECORD record; + DWORD written, err; + + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(handle->loop, handle); + + if (!(handle->flags & UV_HANDLE_READ_PENDING)) + return 0; + + if (handle->flags & UV_HANDLE_TTY_RAW) { + /* Cancel raw read */ + /* Write some bullshit event to force the console wait to return. */ + memset(&record, 0, sizeof record); + if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { + return GetLastError(); + } + } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { + /* Cancel line-buffered read if not already pending */ + err = uv__cancel_read_console(handle); + if (err) + return err; + + handle->flags |= UV_HANDLE_CANCELLATION_PENDING; + } + + return 0; +} + +static int uv__cancel_read_console(uv_tty_t* handle) { + HANDLE active_screen_buffer = INVALID_HANDLE_VALUE; + INPUT_RECORD record; + DWORD written; + DWORD err = 0; + LONG status; + + assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)); + + status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED); + if (status != IN_PROGRESS) { + /* Either we have managed to set a trap for the other thread before + ReadConsole is called, or ReadConsole has returned because the user + has pressed ENTER. In either case, there is nothing else to do. */ + return 0; + } + + /* Save screen state before sending the VK_RETURN event */ + active_screen_buffer = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (active_screen_buffer != INVALID_HANDLE_VALUE && + GetConsoleScreenBufferInfo(active_screen_buffer, + &uv__saved_screen_state)) { + InterlockedOr(&uv__restore_screen_state, 1); + } + + /* Write enter key event to force the console wait to return. */ + record.EventType = KEY_EVENT; + record.Event.KeyEvent.bKeyDown = TRUE; + record.Event.KeyEvent.wRepeatCount = 1; + record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN; + record.Event.KeyEvent.wVirtualScanCode = + MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC); + record.Event.KeyEvent.uChar.UnicodeChar = L'\r'; + record.Event.KeyEvent.dwControlKeyState = 0; + if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) + err = GetLastError(); + + if (active_screen_buffer != INVALID_HANDLE_VALUE) + CloseHandle(active_screen_buffer); + + return err; +} + + +static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { + int old_virtual_width = uv_tty_virtual_width; + int old_virtual_height = uv_tty_virtual_height; + + uv_tty_virtual_width = info->dwSize.X; + uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1; + + /* Recompute virtual window offset row. */ + if (uv_tty_virtual_offset == -1) { + uv_tty_virtual_offset = info->dwCursorPosition.Y; + } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y - + uv_tty_virtual_height + 1) { + /* If suddenly find the cursor outside of the virtual window, it must */ + /* have somehow scrolled. Update the virtual window offset. */ + uv_tty_virtual_offset = info->dwCursorPosition.Y - + uv_tty_virtual_height + 1; + } + if (uv_tty_virtual_offset + uv_tty_virtual_height > info->dwSize.Y) { + uv_tty_virtual_offset = info->dwSize.Y - uv_tty_virtual_height; + } + if (uv_tty_virtual_offset < 0) { + uv_tty_virtual_offset = 0; + } + + /* If the virtual window size changed, emit a SIGWINCH signal. Don't emit */ + /* if this was the first time the virtual window size was computed. */ + if (old_virtual_width != -1 && old_virtual_height != -1 && + (uv_tty_virtual_width != old_virtual_width || + uv_tty_virtual_height != old_virtual_height)) { + uv__signal_dispatch(SIGWINCH); + } +} + + +static COORD uv_tty_make_real_coord(uv_tty_t* handle, + CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y, + unsigned char y_relative) { + COORD result; + + uv_tty_update_virtual_window(info); + + /* Adjust y position */ + if (y_relative) { + y = info->dwCursorPosition.Y + y; + } else { + y = uv_tty_virtual_offset + y; + } + /* Clip y to virtual client rectangle */ + if (y < uv_tty_virtual_offset) { + y = uv_tty_virtual_offset; + } else if (y >= uv_tty_virtual_offset + uv_tty_virtual_height) { + y = uv_tty_virtual_offset + uv_tty_virtual_height - 1; + } + + /* Adjust x */ + if (x_relative) { + x = info->dwCursorPosition.X + x; + } + /* Clip x */ + if (x < 0) { + x = 0; + } else if (x >= uv_tty_virtual_width) { + x = uv_tty_virtual_width - 1; + } + + result.X = (unsigned short) x; + result.Y = (unsigned short) y; + return result; +} + + +static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length, + DWORD* error) { + DWORD written; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + if (!WriteConsoleW(handle->handle, + (void*) buffer, + length, + &written, + NULL)) { + *error = GetLastError(); + return -1; + } + + return 0; +} + + +static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative, + int y, unsigned char y_relative, DWORD* error) { + CONSOLE_SCREEN_BUFFER_INFO info; + COORD pos; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + retry: + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + } + + pos = uv_tty_make_real_coord(handle, &info, x, x_relative, y, y_relative); + + if (!SetConsoleCursorPosition(handle->handle, pos)) { + if (GetLastError() == ERROR_INVALID_PARAMETER) { + /* The console may be resized - retry */ + goto retry; + } else { + *error = GetLastError(); + return -1; + } + } + + return 0; +} + + +static int uv_tty_reset(uv_tty_t* handle, DWORD* error) { + const COORD origin = {0, 0}; + const WORD char_attrs = uv_tty_default_text_attributes; + CONSOLE_SCREEN_BUFFER_INFO info; + DWORD count, written; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + /* Reset original text attributes. */ + if (!SetConsoleTextAttribute(handle->handle, char_attrs)) { + *error = GetLastError(); + return -1; + } + + /* Move the cursor position to (0, 0). */ + if (!SetConsoleCursorPosition(handle->handle, origin)) { + *error = GetLastError(); + return -1; + } + + /* Clear the screen buffer. */ + retry: + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + return -1; + } + + count = info.dwSize.X * info.dwSize.Y; + + if (!(FillConsoleOutputCharacterW(handle->handle, + L'\x20', + count, + origin, + &written) && + FillConsoleOutputAttribute(handle->handle, + char_attrs, + written, + origin, + &written))) { + if (GetLastError() == ERROR_INVALID_PARAMETER) { + /* The console may be resized - retry */ + goto retry; + } else { + *error = GetLastError(); + return -1; + } + } + + /* Move the virtual window up to the top. */ + uv_tty_virtual_offset = 0; + uv_tty_update_virtual_window(&info); + + return 0; +} + + +static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen, + DWORD* error) { + CONSOLE_SCREEN_BUFFER_INFO info; + COORD start, end; + DWORD count, written; + + int x1, x2, y1, y2; + int x1r, x2r, y1r, y2r; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + if (dir == 0) { + /* Clear from current position */ + x1 = 0; + x1r = 1; + } else { + /* Clear from column 0 */ + x1 = 0; + x1r = 0; + } + + if (dir == 1) { + /* Clear to current position */ + x2 = 0; + x2r = 1; + } else { + /* Clear to end of row. We pretend the console is 65536 characters wide, */ + /* uv_tty_make_real_coord will clip it to the actual console width. */ + x2 = 0xffff; + x2r = 0; + } + + if (!entire_screen) { + /* Stay on our own row */ + y1 = y2 = 0; + y1r = y2r = 1; + } else { + /* Apply columns direction to row */ + y1 = x1; + y1r = x1r; + y2 = x2; + y2r = x2r; + } + + retry: + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + return -1; + } + + start = uv_tty_make_real_coord(handle, &info, x1, x1r, y1, y1r); + end = uv_tty_make_real_coord(handle, &info, x2, x2r, y2, y2r); + count = (end.Y * info.dwSize.X + end.X) - + (start.Y * info.dwSize.X + start.X) + 1; + + if (!(FillConsoleOutputCharacterW(handle->handle, + L'\x20', + count, + start, + &written) && + FillConsoleOutputAttribute(handle->handle, + info.wAttributes, + written, + start, + &written))) { + if (GetLastError() == ERROR_INVALID_PARAMETER) { + /* The console may be resized - retry */ + goto retry; + } else { + *error = GetLastError(); + return -1; + } + } + + return 0; +} + +#define FLIP_FGBG \ + do { \ + WORD fg = info.wAttributes & 0xF; \ + WORD bg = info.wAttributes & 0xF0; \ + info.wAttributes &= 0xFF00; \ + info.wAttributes |= fg << 4; \ + info.wAttributes |= bg >> 4; \ + } while (0) + +static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) { + unsigned short argc = handle->tty.wr.ansi_csi_argc; + unsigned short* argv = handle->tty.wr.ansi_csi_argv; + int i; + CONSOLE_SCREEN_BUFFER_INFO info; + + char fg_color = -1, bg_color = -1; + char fg_bright = -1, bg_bright = -1; + char inverse = -1; + + if (argc == 0) { + /* Reset mode */ + fg_color = uv_tty_default_fg_color; + bg_color = uv_tty_default_bg_color; + fg_bright = uv_tty_default_fg_bright; + bg_bright = uv_tty_default_bg_bright; + inverse = uv_tty_default_inverse; + } + + for (i = 0; i < argc; i++) { + short arg = argv[i]; + + if (arg == 0) { + /* Reset mode */ + fg_color = uv_tty_default_fg_color; + bg_color = uv_tty_default_bg_color; + fg_bright = uv_tty_default_fg_bright; + bg_bright = uv_tty_default_bg_bright; + inverse = uv_tty_default_inverse; + + } else if (arg == 1) { + /* Foreground bright on */ + fg_bright = 1; + + } else if (arg == 2) { + /* Both bright off */ + fg_bright = 0; + bg_bright = 0; + + } else if (arg == 5) { + /* Background bright on */ + bg_bright = 1; + + } else if (arg == 7) { + /* Inverse: on */ + inverse = 1; + + } else if (arg == 21 || arg == 22) { + /* Foreground bright off */ + fg_bright = 0; + + } else if (arg == 25) { + /* Background bright off */ + bg_bright = 0; + + } else if (arg == 27) { + /* Inverse: off */ + inverse = 0; + + } else if (arg >= 30 && arg <= 37) { + /* Set foreground color */ + fg_color = arg - 30; + + } else if (arg == 39) { + /* Default text color */ + fg_color = uv_tty_default_fg_color; + fg_bright = uv_tty_default_fg_bright; + + } else if (arg >= 40 && arg <= 47) { + /* Set background color */ + bg_color = arg - 40; + + } else if (arg == 49) { + /* Default background color */ + bg_color = uv_tty_default_bg_color; + bg_bright = uv_tty_default_bg_bright; + + } else if (arg >= 90 && arg <= 97) { + /* Set bold foreground color */ + fg_bright = 1; + fg_color = arg - 90; + + } else if (arg >= 100 && arg <= 107) { + /* Set bold background color */ + bg_bright = 1; + bg_color = arg - 100; + + } + } + + if (fg_color == -1 && bg_color == -1 && fg_bright == -1 && + bg_bright == -1 && inverse == -1) { + /* Nothing changed */ + return 0; + } + + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + return -1; + } + + if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) { + FLIP_FGBG; + } + + if (fg_color != -1) { + info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + if (fg_color & 1) info.wAttributes |= FOREGROUND_RED; + if (fg_color & 2) info.wAttributes |= FOREGROUND_GREEN; + if (fg_color & 4) info.wAttributes |= FOREGROUND_BLUE; + } + + if (fg_bright != -1) { + if (fg_bright) { + info.wAttributes |= FOREGROUND_INTENSITY; + } else { + info.wAttributes &= ~FOREGROUND_INTENSITY; + } + } + + if (bg_color != -1) { + info.wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + if (bg_color & 1) info.wAttributes |= BACKGROUND_RED; + if (bg_color & 2) info.wAttributes |= BACKGROUND_GREEN; + if (bg_color & 4) info.wAttributes |= BACKGROUND_BLUE; + } + + if (bg_bright != -1) { + if (bg_bright) { + info.wAttributes |= BACKGROUND_INTENSITY; + } else { + info.wAttributes &= ~BACKGROUND_INTENSITY; + } + } + + if (inverse != -1) { + if (inverse) { + info.wAttributes |= COMMON_LVB_REVERSE_VIDEO; + } else { + info.wAttributes &= ~COMMON_LVB_REVERSE_VIDEO; + } + } + + if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) { + FLIP_FGBG; + } + + if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) { + *error = GetLastError(); + return -1; + } + + return 0; +} + + +static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes, + DWORD* error) { + CONSOLE_SCREEN_BUFFER_INFO info; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + return -1; + } + + uv_tty_update_virtual_window(&info); + + handle->tty.wr.saved_position.X = info.dwCursorPosition.X; + handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset; + handle->flags |= UV_HANDLE_TTY_SAVED_POSITION; + + if (save_attributes) { + handle->tty.wr.saved_attributes = info.wAttributes & + (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY); + handle->flags |= UV_HANDLE_TTY_SAVED_ATTRIBUTES; + } + + return 0; +} + + +static int uv_tty_restore_state(uv_tty_t* handle, + unsigned char restore_attributes, DWORD* error) { + CONSOLE_SCREEN_BUFFER_INFO info; + WORD new_attributes; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) { + if (uv_tty_move_caret(handle, + handle->tty.wr.saved_position.X, + 0, + handle->tty.wr.saved_position.Y, + 0, + error) != 0) { + return -1; + } + } + + if (restore_attributes && + (handle->flags & UV_HANDLE_TTY_SAVED_ATTRIBUTES)) { + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + return -1; + } + + new_attributes = info.wAttributes; + new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY); + new_attributes |= handle->tty.wr.saved_attributes; + + if (!SetConsoleTextAttribute(handle->handle, new_attributes)) { + *error = GetLastError(); + return -1; + } + } + + return 0; +} + +static int uv_tty_set_cursor_visibility(uv_tty_t* handle, + BOOL visible, + DWORD* error) { + CONSOLE_CURSOR_INFO cursor_info; + + if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) { + *error = GetLastError(); + return -1; + } + + cursor_info.bVisible = visible; + + if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) { + *error = GetLastError(); + return -1; + } + + return 0; +} + +static int uv_tty_write_bufs(uv_tty_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + DWORD* error) { + /* We can only write 8k characters at a time. Windows can't handle */ + /* much more characters in a single console write anyway. */ + WCHAR utf16_buf[8192]; + DWORD utf16_buf_used = 0; + unsigned int i; + +#define FLUSH_TEXT() \ + do { \ + if (utf16_buf_used > 0) { \ + uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \ + utf16_buf_used = 0; \ + } \ + } while (0) + +#define ENSURE_BUFFER_SPACE(wchars_needed) \ + if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \ + FLUSH_TEXT(); \ + } + + /* Cache for fast access */ + unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left; + unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint; + unsigned char previous_eol = handle->tty.wr.previous_eol; + unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state; + + /* Store the error here. If we encounter an error, stop trying to do i/o */ + /* but keep parsing the buffer so we leave the parser in a consistent */ + /* state. */ + *error = ERROR_SUCCESS; + + EnterCriticalSection(&uv_tty_output_lock); + + for (i = 0; i < nbufs; i++) { + uv_buf_t buf = bufs[i]; + unsigned int j; + + for (j = 0; j < buf.len; j++) { + unsigned char c = buf.base[j]; + + /* Run the character through the utf8 decoder We happily accept non */ + /* shortest form encodings and invalid code points - there's no real */ + /* harm that can be done. */ + if (utf8_bytes_left == 0) { + /* Read utf-8 start byte */ + DWORD first_zero_bit; + unsigned char not_c = ~c; +#ifdef _MSC_VER /* msvc */ + if (_BitScanReverse(&first_zero_bit, not_c)) { +#else /* assume gcc */ + if (c != 0) { + first_zero_bit = (sizeof(int) * 8) - 1 - __builtin_clz(not_c); +#endif + if (first_zero_bit == 7) { + /* Ascii - pass right through */ + utf8_codepoint = (unsigned int) c; + + } else if (first_zero_bit <= 5) { + /* Multibyte sequence */ + utf8_codepoint = (0xff >> (8 - first_zero_bit)) & c; + utf8_bytes_left = (char) (6 - first_zero_bit); + + } else { + /* Invalid continuation */ + utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; + } + + } else { + /* 0xff -- invalid */ + utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; + } + + } else if ((c & 0xc0) == 0x80) { + /* Valid continuation of utf-8 multibyte sequence */ + utf8_bytes_left--; + utf8_codepoint <<= 6; + utf8_codepoint |= ((unsigned int) c & 0x3f); + + } else { + /* Start byte where continuation was expected. */ + utf8_bytes_left = 0; + utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; + /* Patch buf offset so this character will be parsed again as a */ + /* start byte. */ + j--; + } + + /* Maybe we need to parse more bytes to find a character. */ + if (utf8_bytes_left != 0) { + continue; + } + + /* Parse vt100/ansi escape codes */ + if (ansi_parser_state == ANSI_NORMAL) { + switch (utf8_codepoint) { + case '\033': + ansi_parser_state = ANSI_ESCAPE_SEEN; + continue; + + case 0233: + ansi_parser_state = ANSI_CSI; + handle->tty.wr.ansi_csi_argc = 0; + continue; + } + + } else if (ansi_parser_state == ANSI_ESCAPE_SEEN) { + switch (utf8_codepoint) { + case '[': + ansi_parser_state = ANSI_CSI; + handle->tty.wr.ansi_csi_argc = 0; + continue; + + case '^': + case '_': + case 'P': + case ']': + /* Not supported, but we'll have to parse until we see a stop */ + /* code, e.g. ESC \ or BEL. */ + ansi_parser_state = ANSI_ST_CONTROL; + continue; + + case '\033': + /* Ignore double escape. */ + continue; + + case 'c': + /* Full console reset. */ + FLUSH_TEXT(); + uv_tty_reset(handle, error); + ansi_parser_state = ANSI_NORMAL; + continue; + + case '7': + /* Save the cursor position and text attributes. */ + FLUSH_TEXT(); + uv_tty_save_state(handle, 1, error); + ansi_parser_state = ANSI_NORMAL; + continue; + + case '8': + /* Restore the cursor position and text attributes */ + FLUSH_TEXT(); + uv_tty_restore_state(handle, 1, error); + ansi_parser_state = ANSI_NORMAL; + continue; + + default: + if (utf8_codepoint >= '@' && utf8_codepoint <= '_') { + /* Single-char control. */ + ansi_parser_state = ANSI_NORMAL; + continue; + } else { + /* Invalid - proceed as normal, */ + ansi_parser_state = ANSI_NORMAL; + } + } + + } else if (ansi_parser_state & ANSI_CSI) { + if (!(ansi_parser_state & ANSI_IGNORE)) { + if (utf8_codepoint >= '0' && utf8_codepoint <= '9') { + /* Parsing a numerical argument */ + + if (!(ansi_parser_state & ANSI_IN_ARG)) { + /* We were not currently parsing a number */ + + /* Check for too many arguments */ + if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) { + ansi_parser_state |= ANSI_IGNORE; + continue; + } + + ansi_parser_state |= ANSI_IN_ARG; + handle->tty.wr.ansi_csi_argc++; + handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = + (unsigned short) utf8_codepoint - '0'; + continue; + } else { + /* We were already parsing a number. Parse next digit. */ + uint32_t value = 10 * + handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1]; + + /* Check for overflow. */ + if (value > UINT16_MAX) { + ansi_parser_state |= ANSI_IGNORE; + continue; + } + + handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = + (unsigned short) value + (utf8_codepoint - '0'); + continue; + } + + } else if (utf8_codepoint == ';') { + /* Denotes the end of an argument. */ + if (ansi_parser_state & ANSI_IN_ARG) { + ansi_parser_state &= ~ANSI_IN_ARG; + continue; + + } else { + /* If ANSI_IN_ARG is not set, add another argument and */ + /* default it to 0. */ + /* Check for too many arguments */ + if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) { + ansi_parser_state |= ANSI_IGNORE; + continue; + } + + handle->tty.wr.ansi_csi_argc++; + handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0; + continue; + } + + } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) && + handle->tty.wr.ansi_csi_argc == 0) { + /* Ignores '?' if it is the first character after CSI[ */ + /* This is an extension character from the VT100 codeset */ + /* that is supported and used by most ANSI terminals today. */ + continue; + + } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' && + (handle->tty.wr.ansi_csi_argc > 0 || utf8_codepoint != '[')) { + int x, y, d; + + /* Command byte */ + switch (utf8_codepoint) { + case 'A': + /* cursor up */ + FLUSH_TEXT(); + y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1); + uv_tty_move_caret(handle, 0, 1, y, 1, error); + break; + + case 'B': + /* cursor down */ + FLUSH_TEXT(); + y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1; + uv_tty_move_caret(handle, 0, 1, y, 1, error); + break; + + case 'C': + /* cursor forward */ + FLUSH_TEXT(); + x = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1; + uv_tty_move_caret(handle, x, 1, 0, 1, error); + break; + + case 'D': + /* cursor back */ + FLUSH_TEXT(); + x = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1); + uv_tty_move_caret(handle, x, 1, 0, 1, error); + break; + + case 'E': + /* cursor next line */ + FLUSH_TEXT(); + y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1; + uv_tty_move_caret(handle, 0, 0, y, 1, error); + break; + + case 'F': + /* cursor previous line */ + FLUSH_TEXT(); + y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1); + uv_tty_move_caret(handle, 0, 0, y, 1, error); + break; + + case 'G': + /* cursor horizontal move absolute */ + FLUSH_TEXT(); + x = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0]) + ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0; + uv_tty_move_caret(handle, x, 0, 0, 1, error); + break; + + case 'H': + case 'f': + /* cursor move absolute */ + FLUSH_TEXT(); + y = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0]) + ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0; + x = (handle->tty.wr.ansi_csi_argc >= 2 && handle->tty.wr.ansi_csi_argv[1]) + ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0; + uv_tty_move_caret(handle, x, 0, y, 0, error); + break; + + case 'J': + /* Erase screen */ + FLUSH_TEXT(); + d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0; + if (d >= 0 && d <= 2) { + uv_tty_clear(handle, d, 1, error); + } + break; + + case 'K': + /* Erase line */ + FLUSH_TEXT(); + d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0; + if (d >= 0 && d <= 2) { + uv_tty_clear(handle, d, 0, error); + } + break; + + case 'm': + /* Set style */ + FLUSH_TEXT(); + uv_tty_set_style(handle, error); + break; + + case 's': + /* Save the cursor position. */ + FLUSH_TEXT(); + uv_tty_save_state(handle, 0, error); + break; + + case 'u': + /* Restore the cursor position */ + FLUSH_TEXT(); + uv_tty_restore_state(handle, 0, error); + break; + + case 'l': + /* Hide the cursor */ + if (handle->tty.wr.ansi_csi_argc == 1 && + handle->tty.wr.ansi_csi_argv[0] == 25) { + FLUSH_TEXT(); + uv_tty_set_cursor_visibility(handle, 0, error); + } + break; + + case 'h': + /* Show the cursor */ + if (handle->tty.wr.ansi_csi_argc == 1 && + handle->tty.wr.ansi_csi_argv[0] == 25) { + FLUSH_TEXT(); + uv_tty_set_cursor_visibility(handle, 1, error); + } + break; + } + + /* Sequence ended - go back to normal state. */ + ansi_parser_state = ANSI_NORMAL; + continue; + + } else { + /* We don't support commands that use private mode characters or */ + /* intermediaries. Ignore the rest of the sequence. */ + ansi_parser_state |= ANSI_IGNORE; + continue; + } + } else { + /* We're ignoring this command. Stop only on command character. */ + if (utf8_codepoint >= '@' && utf8_codepoint <= '~') { + ansi_parser_state = ANSI_NORMAL; + } + continue; + } + + } else if (ansi_parser_state & ANSI_ST_CONTROL) { + /* Unsupported control code */ + /* Ignore everything until we see BEL or ESC \ */ + if (ansi_parser_state & ANSI_IN_STRING) { + if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) { + if (utf8_codepoint == '"') { + ansi_parser_state &= ~ANSI_IN_STRING; + } else if (utf8_codepoint == '\\') { + ansi_parser_state |= ANSI_BACKSLASH_SEEN; + } + } else { + ansi_parser_state &= ~ANSI_BACKSLASH_SEEN; + } + } else { + if (utf8_codepoint == '\007' || (utf8_codepoint == '\\' && + (ansi_parser_state & ANSI_ESCAPE_SEEN))) { + /* End of sequence */ + ansi_parser_state = ANSI_NORMAL; + } else if (utf8_codepoint == '\033') { + /* Escape character */ + ansi_parser_state |= ANSI_ESCAPE_SEEN; + } else if (utf8_codepoint == '"') { + /* String starting */ + ansi_parser_state |= ANSI_IN_STRING; + ansi_parser_state &= ~ANSI_ESCAPE_SEEN; + ansi_parser_state &= ~ANSI_BACKSLASH_SEEN; + } else { + ansi_parser_state &= ~ANSI_ESCAPE_SEEN; + } + } + continue; + } else { + /* Inconsistent state */ + abort(); + } + + /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the */ + /* windows console doesn't really support UTF-16, so just emit the */ + /* replacement character. */ + if (utf8_codepoint > 0xffff) { + utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; + } + + if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) { + /* EOL conversion - emit \r\n when we see \n. */ + + if (utf8_codepoint == 0x0a && previous_eol != 0x0d) { + /* \n was not preceded by \r; print \r\n. */ + ENSURE_BUFFER_SPACE(2); + utf16_buf[utf16_buf_used++] = L'\r'; + utf16_buf[utf16_buf_used++] = L'\n'; + } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) { + /* \n was followed by \r; do not print the \r, since */ + /* the source was either \r\n\r (so the second \r is */ + /* redundant) or was \n\r (so the \n was processed */ + /* by the last case and an \r automatically inserted). */ + } else { + /* \r without \n; print \r as-is. */ + ENSURE_BUFFER_SPACE(1); + utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint; + } + + previous_eol = (char) utf8_codepoint; + + } else if (utf8_codepoint <= 0xffff) { + /* Encode character into utf-16 buffer. */ + ENSURE_BUFFER_SPACE(1); + utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint; + previous_eol = 0; + } + } + } + + /* Flush remaining characters */ + FLUSH_TEXT(); + + /* Copy cached values back to struct. */ + handle->tty.wr.utf8_bytes_left = utf8_bytes_left; + handle->tty.wr.utf8_codepoint = utf8_codepoint; + handle->tty.wr.previous_eol = previous_eol; + handle->tty.wr.ansi_parser_state = ansi_parser_state; + + LeaveCriticalSection(&uv_tty_output_lock); + + if (*error == STATUS_SUCCESS) { + return 0; + } else { + return -1; + } + +#undef FLUSH_TEXT +} + + +int uv_tty_write(uv_loop_t* loop, + uv_write_t* req, + uv_tty_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb) { + DWORD error; + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_WRITE; + req->handle = (uv_stream_t*) handle; + req->cb = cb; + + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + + req->u.io.queued_bytes = 0; + + if (!uv_tty_write_bufs(handle, bufs, nbufs, &error)) { + SET_REQ_SUCCESS(req); + } else { + SET_REQ_ERROR(req, error); + } + + uv_insert_pending_req(loop, (uv_req_t*) req); + + return 0; +} + + +int uv__tty_try_write(uv_tty_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs) { + DWORD error; + + if (handle->stream.conn.write_reqs_pending > 0) + return UV_EAGAIN; + + if (uv_tty_write_bufs(handle, bufs, nbufs, &error)) + return uv_translate_sys_error(error); + + return uv__count_bufs(bufs, nbufs); +} + + +void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, + uv_write_t* req) { + int err; + + handle->write_queue_size -= req->u.io.queued_bytes; + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (req->cb) { + err = GET_REQ_ERROR(req); + req->cb(req, uv_translate_sys_error(err)); + } + + handle->stream.conn.write_reqs_pending--; + if (handle->stream.conn.shutdown_req != NULL && + handle->stream.conn.write_reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_tty_close(uv_tty_t* handle) { + assert(handle->u.fd == -1 || handle->u.fd > 2); + if (handle->u.fd == -1) + CloseHandle(handle->handle); + else + close(handle->u.fd); + + if (handle->flags & UV_HANDLE_READING) + uv_tty_read_stop(handle); + + handle->u.fd = -1; + handle->handle = INVALID_HANDLE_VALUE; + handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); + uv__handle_closing(handle); + + if (handle->reqs_pending == 0) { + uv_want_endgame(handle->loop, (uv_handle_t*) handle); + } +} + + +void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { + if (!(handle->flags & UV_HANDLE_TTY_READABLE) && + handle->stream.conn.shutdown_req != NULL && + handle->stream.conn.write_reqs_pending == 0) { + UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req); + + /* TTY shutdown is really just a no-op */ + if (handle->stream.conn.shutdown_req->cb) { + if (handle->flags & UV__HANDLE_CLOSING) { + handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED); + } else { + handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0); + } + } + + handle->stream.conn.shutdown_req = NULL; + + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + if (handle->flags & UV__HANDLE_CLOSING && + handle->reqs_pending == 0) { + /* The wait handle used for raw reading should be unregistered when the */ + /* wait callback runs. */ + assert(!(handle->flags & UV_HANDLE_TTY_READABLE) || + handle->tty.rd.read_raw_wait == NULL); + + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); + } +} + + +/* TODO: remove me */ +void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* raw_req) { + abort(); +} + + +/* TODO: remove me */ +void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, + uv_connect_t* req) { + abort(); +} + + +int uv_tty_reset_mode(void) { + /* Not necessary to do anything. */ + return 0; +} diff --git a/src/win/udp.c b/src/win/udp.c new file mode 100644 index 0000000..9bf1453 --- /dev/null +++ b/src/win/udp.c @@ -0,0 +1,928 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" + + +/* + * Threshold of active udp streams for which to preallocate udp read buffers. + */ +const unsigned int uv_active_udp_streams_threshold = 0; + +/* A zero-size buffer for use by uv_udp_read */ +static char uv_zero_[] = ""; + +int uv_udp_getsockname(const uv_udp_t* handle, + struct sockaddr* name, + int* namelen) { + int result; + + if (handle->socket == INVALID_SOCKET) { + return UV_EINVAL; + } + + result = getsockname(handle->socket, name, namelen); + if (result != 0) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket, + int family) { + DWORD yes = 1; + WSAPROTOCOL_INFOW info; + int opt_len; + + if (handle->socket != INVALID_SOCKET) + return UV_EBUSY; + + /* Set the socket to nonblocking mode */ + if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) { + return WSAGetLastError(); + } + + /* Make the socket non-inheritable */ + if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) { + return GetLastError(); + } + + /* Associate it with the I/O completion port. */ + /* Use uv_handle_t pointer as completion key. */ + if (CreateIoCompletionPort((HANDLE)socket, + loop->iocp, + (ULONG_PTR)socket, + 0) == NULL) { + return GetLastError(); + } + + if (pSetFileCompletionNotificationModes) { + /* All known Windows that support SetFileCompletionNotificationModes */ + /* have a bug that makes it impossible to use this function in */ + /* conjunction with datagram sockets. We can work around that but only */ + /* if the user is using the default UDP driver (AFD) and has no other */ + /* LSPs stacked on top. Here we check whether that is the case. */ + opt_len = (int) sizeof info; + if (getsockopt(socket, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &info, + &opt_len) == SOCKET_ERROR) { + return GetLastError(); + } + + if (info.ProtocolChain.ChainLen == 1) { + if (pSetFileCompletionNotificationModes((HANDLE)socket, + FILE_SKIP_SET_EVENT_ON_HANDLE | + FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { + handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; + handle->func_wsarecv = uv_wsarecv_workaround; + handle->func_wsarecvfrom = uv_wsarecvfrom_workaround; + } else if (GetLastError() != ERROR_INVALID_FUNCTION) { + return GetLastError(); + } + } + } + + handle->socket = socket; + + if (family == AF_INET6) { + handle->flags |= UV_HANDLE_IPV6; + } else { + assert(!(handle->flags & UV_HANDLE_IPV6)); + } + + return 0; +} + + +int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) { + int domain; + + /* Use the lower 8 bits for the domain */ + domain = flags & 0xFF; + if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) + return UV_EINVAL; + + if (flags & ~0xFF) + return UV_EINVAL; + + uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP); + handle->socket = INVALID_SOCKET; + handle->reqs_pending = 0; + handle->activecnt = 0; + handle->func_wsarecv = WSARecv; + handle->func_wsarecvfrom = WSARecvFrom; + handle->send_queue_size = 0; + handle->send_queue_count = 0; + uv_req_init(loop, (uv_req_t*) &(handle->recv_req)); + handle->recv_req.type = UV_UDP_RECV; + handle->recv_req.data = handle; + + /* If anything fails beyond this point we need to remove the handle from + * the handle queue, since it was added by uv__handle_init. + */ + + if (domain != AF_UNSPEC) { + SOCKET sock; + DWORD err; + + sock = socket(domain, SOCK_DGRAM, 0); + if (sock == INVALID_SOCKET) { + err = WSAGetLastError(); + QUEUE_REMOVE(&handle->handle_queue); + return uv_translate_sys_error(err); + } + + err = uv_udp_set_socket(handle->loop, handle, sock, domain); + if (err) { + closesocket(sock); + QUEUE_REMOVE(&handle->handle_queue); + return uv_translate_sys_error(err); + } + } + + return 0; +} + + +int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { + return uv_udp_init_ex(loop, handle, AF_UNSPEC); +} + + +void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) { + uv_udp_recv_stop(handle); + closesocket(handle->socket); + handle->socket = INVALID_SOCKET; + + uv__handle_closing(handle); + + if (handle->reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) { + if (handle->flags & UV__HANDLE_CLOSING && + handle->reqs_pending == 0) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); + } +} + + +static int uv_udp_maybe_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + int r; + int err; + DWORD no = 0; + + if (handle->flags & UV_HANDLE_BOUND) + return 0; + + if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) { + /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */ + return ERROR_INVALID_PARAMETER; + } + + if (handle->socket == INVALID_SOCKET) { + SOCKET sock = socket(addr->sa_family, SOCK_DGRAM, 0); + if (sock == INVALID_SOCKET) { + return WSAGetLastError(); + } + + err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family); + if (err) { + closesocket(sock); + return err; + } + } + + if (flags & UV_UDP_REUSEADDR) { + DWORD yes = 1; + /* Set SO_REUSEADDR on the socket. */ + if (setsockopt(handle->socket, + SOL_SOCKET, + SO_REUSEADDR, + (char*) &yes, + sizeof yes) == SOCKET_ERROR) { + err = WSAGetLastError(); + return err; + } + } + + if (addr->sa_family == AF_INET6) + handle->flags |= UV_HANDLE_IPV6; + + if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) { + /* On windows IPV6ONLY is on by default. */ + /* If the user doesn't specify it libuv turns it off. */ + + /* TODO: how to handle errors? This may fail if there is no ipv4 stack */ + /* available, or when run on XP/2003 which have no support for dualstack */ + /* sockets. For now we're silently ignoring the error. */ + setsockopt(handle->socket, + IPPROTO_IPV6, + IPV6_V6ONLY, + (char*) &no, + sizeof no); + } + + r = bind(handle->socket, addr, addrlen); + if (r == SOCKET_ERROR) { + return WSAGetLastError(); + } + + handle->flags |= UV_HANDLE_BOUND; + + return 0; +} + + +static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { + uv_req_t* req; + uv_buf_t buf; + DWORD bytes, flags; + int result; + + assert(handle->flags & UV_HANDLE_READING); + assert(!(handle->flags & UV_HANDLE_READ_PENDING)); + + req = &handle->recv_req; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + + /* + * Preallocate a read buffer if the number of active streams is below + * the threshold. + */ + if (loop->active_udp_streams < uv_active_udp_streams_threshold) { + handle->flags &= ~UV_HANDLE_ZERO_READ; + + handle->recv_buffer = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer); + if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) { + handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0); + return; + } + assert(handle->recv_buffer.base != NULL); + + buf = handle->recv_buffer; + memset(&handle->recv_from, 0, sizeof handle->recv_from); + handle->recv_from_len = sizeof handle->recv_from; + flags = 0; + + result = handle->func_wsarecvfrom(handle->socket, + (WSABUF*) &buf, + 1, + &bytes, + &flags, + (struct sockaddr*) &handle->recv_from, + &handle->recv_from_len, + &req->u.io.overlapped, + NULL); + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Process the req without IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + req->u.io.overlapped.InternalHigh = bytes; + handle->reqs_pending++; + uv_insert_pending_req(loop, req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* The req will be processed with IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + } else { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, req); + handle->reqs_pending++; + } + + } else { + handle->flags |= UV_HANDLE_ZERO_READ; + + buf.base = (char*) uv_zero_; + buf.len = 0; + flags = MSG_PEEK; + + result = handle->func_wsarecv(handle->socket, + (WSABUF*) &buf, + 1, + &bytes, + &flags, + &req->u.io.overlapped, + NULL); + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Process the req without IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + req->u.io.overlapped.InternalHigh = bytes; + handle->reqs_pending++; + uv_insert_pending_req(loop, req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* The req will be processed with IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + } else { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, req); + handle->reqs_pending++; + } + } +} + + +int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, + uv_udp_recv_cb recv_cb) { + uv_loop_t* loop = handle->loop; + int err; + + if (handle->flags & UV_HANDLE_READING) { + return WSAEALREADY; + } + + err = uv_udp_maybe_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + 0); + if (err) + return err; + + handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); + loop->active_udp_streams++; + + handle->recv_cb = recv_cb; + handle->alloc_cb = alloc_cb; + + /* If reading was stopped and then started again, there could still be a */ + /* recv request pending. */ + if (!(handle->flags & UV_HANDLE_READ_PENDING)) + uv_udp_queue_recv(loop, handle); + + return 0; +} + + +int uv__udp_recv_stop(uv_udp_t* handle) { + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + handle->loop->active_udp_streams--; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + return 0; +} + + +static int uv__send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen, + uv_udp_send_cb cb) { + uv_loop_t* loop = handle->loop; + DWORD result, bytes; + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_UDP_SEND; + req->handle = handle; + req->cb = cb; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + + result = WSASendTo(handle->socket, + (WSABUF*)bufs, + nbufs, + &bytes, + 0, + addr, + addrlen, + &req->u.io.overlapped, + NULL); + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Request completed immediately. */ + req->u.io.queued_bytes = 0; + handle->reqs_pending++; + handle->send_queue_size += req->u.io.queued_bytes; + handle->send_queue_count++; + REGISTER_HANDLE_REQ(loop, handle, req); + uv_insert_pending_req(loop, (uv_req_t*)req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* Request queued by the kernel. */ + req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs); + handle->reqs_pending++; + handle->send_queue_size += req->u.io.queued_bytes; + handle->send_queue_count++; + REGISTER_HANDLE_REQ(loop, handle, req); + } else { + /* Send failed due to an error. */ + return WSAGetLastError(); + } + + return 0; +} + + +void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, + uv_req_t* req) { + uv_buf_t buf; + int partial; + + assert(handle->type == UV_UDP); + + handle->flags &= ~UV_HANDLE_READ_PENDING; + + if (!REQ_SUCCESS(req)) { + DWORD err = GET_REQ_SOCK_ERROR(req); + if (err == WSAEMSGSIZE) { + /* Not a real error, it just indicates that the received packet */ + /* was bigger than the receive buffer. */ + } else if (err == WSAECONNRESET || err == WSAENETRESET) { + /* A previous sendto operation failed; ignore this error. If */ + /* zero-reading we need to call WSARecv/WSARecvFrom _without_ the */ + /* MSG_PEEK flag to clear out the error queue. For nonzero reads, */ + /* immediately queue a new receive. */ + if (!(handle->flags & UV_HANDLE_ZERO_READ)) { + goto done; + } + } else { + /* A real error occurred. Report the error to the user only if we're */ + /* currently reading. */ + if (handle->flags & UV_HANDLE_READING) { + uv_udp_recv_stop(handle); + buf = (handle->flags & UV_HANDLE_ZERO_READ) ? + uv_buf_init(NULL, 0) : handle->recv_buffer; + handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0); + } + goto done; + } + } + + if (!(handle->flags & UV_HANDLE_ZERO_READ)) { + /* Successful read */ + partial = !REQ_SUCCESS(req); + handle->recv_cb(handle, + req->u.io.overlapped.InternalHigh, + &handle->recv_buffer, + (const struct sockaddr*) &handle->recv_from, + partial ? UV_UDP_PARTIAL : 0); + } else if (handle->flags & UV_HANDLE_READING) { + DWORD bytes, err, flags; + struct sockaddr_storage from; + int from_len; + + /* Do a nonblocking receive */ + /* TODO: try to read multiple datagrams at once. FIONREAD maybe? */ + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); + if (buf.base == NULL || buf.len == 0) { + handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); + goto done; + } + assert(buf.base != NULL); + + memset(&from, 0, sizeof from); + from_len = sizeof from; + + flags = 0; + + if (WSARecvFrom(handle->socket, + (WSABUF*)&buf, + 1, + &bytes, + &flags, + (struct sockaddr*) &from, + &from_len, + NULL, + NULL) != SOCKET_ERROR) { + + /* Message received */ + handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0); + } else { + err = WSAGetLastError(); + if (err == WSAEMSGSIZE) { + /* Message truncated */ + handle->recv_cb(handle, + bytes, + &buf, + (const struct sockaddr*) &from, + UV_UDP_PARTIAL); + } else if (err == WSAEWOULDBLOCK) { + /* Kernel buffer empty */ + handle->recv_cb(handle, 0, &buf, NULL, 0); + } else if (err == WSAECONNRESET || err == WSAENETRESET) { + /* WSAECONNRESET/WSANETRESET is ignored because this just indicates + * that a previous sendto operation failed. + */ + handle->recv_cb(handle, 0, &buf, NULL, 0); + } else { + /* Any other error that we want to report back to the user. */ + uv_udp_recv_stop(handle); + handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0); + } + } + } + +done: + /* Post another read if still reading and not closing. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_udp_queue_recv(loop, handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, + uv_udp_send_t* req) { + int err; + + assert(handle->type == UV_UDP); + + assert(handle->send_queue_size >= req->u.io.queued_bytes); + assert(handle->send_queue_count >= 1); + handle->send_queue_size -= req->u.io.queued_bytes; + handle->send_queue_count--; + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (req->cb) { + err = 0; + if (!REQ_SUCCESS(req)) { + err = GET_REQ_SOCK_ERROR(req); + } + req->cb(req, uv_translate_sys_error(err)); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +static int uv__udp_set_membership4(uv_udp_t* handle, + const struct sockaddr_in* multicast_addr, + const char* interface_addr, + uv_membership membership) { + int err; + int optname; + struct ip_mreq mreq; + + if (handle->flags & UV_HANDLE_IPV6) + return UV_EINVAL; + + /* If the socket is unbound, bind to inaddr_any. */ + err = uv_udp_maybe_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + UV_UDP_REUSEADDR); + if (err) + return uv_translate_sys_error(err); + + memset(&mreq, 0, sizeof mreq); + + if (interface_addr) { + err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr); + if (err) + return err; + } else { + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + } + + mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr; + + switch (membership) { + case UV_JOIN_GROUP: + optname = IP_ADD_MEMBERSHIP; + break; + case UV_LEAVE_GROUP: + optname = IP_DROP_MEMBERSHIP; + break; + default: + return UV_EINVAL; + } + + if (setsockopt(handle->socket, + IPPROTO_IP, + optname, + (char*) &mreq, + sizeof mreq) == SOCKET_ERROR) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +int uv__udp_set_membership6(uv_udp_t* handle, + const struct sockaddr_in6* multicast_addr, + const char* interface_addr, + uv_membership membership) { + int optname; + int err; + struct ipv6_mreq mreq; + struct sockaddr_in6 addr6; + + if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6)) + return UV_EINVAL; + + err = uv_udp_maybe_bind(handle, + (const struct sockaddr*) &uv_addr_ip6_any_, + sizeof(uv_addr_ip6_any_), + UV_UDP_REUSEADDR); + + if (err) + return uv_translate_sys_error(err); + + memset(&mreq, 0, sizeof(mreq)); + + if (interface_addr) { + if (uv_ip6_addr(interface_addr, 0, &addr6)) + return UV_EINVAL; + mreq.ipv6mr_interface = addr6.sin6_scope_id; + } else { + mreq.ipv6mr_interface = 0; + } + + mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr; + + switch (membership) { + case UV_JOIN_GROUP: + optname = IPV6_ADD_MEMBERSHIP; + break; + case UV_LEAVE_GROUP: + optname = IPV6_DROP_MEMBERSHIP; + break; + default: + return UV_EINVAL; + } + + if (setsockopt(handle->socket, + IPPROTO_IPV6, + optname, + (char*) &mreq, + sizeof mreq) == SOCKET_ERROR) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +int uv_udp_set_membership(uv_udp_t* handle, + const char* multicast_addr, + const char* interface_addr, + uv_membership membership) { + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; + + if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0) + return uv__udp_set_membership4(handle, &addr4, interface_addr, membership); + else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0) + return uv__udp_set_membership6(handle, &addr6, interface_addr, membership); + else + return UV_EINVAL; +} + + +int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) { + struct sockaddr_storage addr_st; + struct sockaddr_in* addr4; + struct sockaddr_in6* addr6; + + addr4 = (struct sockaddr_in*) &addr_st; + addr6 = (struct sockaddr_in6*) &addr_st; + + if (!interface_addr) { + memset(&addr_st, 0, sizeof addr_st); + if (handle->flags & UV_HANDLE_IPV6) { + addr_st.ss_family = AF_INET6; + addr6->sin6_scope_id = 0; + } else { + addr_st.ss_family = AF_INET; + addr4->sin_addr.s_addr = htonl(INADDR_ANY); + } + } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) { + /* nothing, address was parsed */ + } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) { + /* nothing, address was parsed */ + } else { + return UV_EINVAL; + } + + if (!(handle->flags & UV_HANDLE_BOUND)) + return UV_EBADF; + + if (addr_st.ss_family == AF_INET) { + if (setsockopt(handle->socket, + IPPROTO_IP, + IP_MULTICAST_IF, + (char*) &addr4->sin_addr, + sizeof(addr4->sin_addr)) == SOCKET_ERROR) { + return uv_translate_sys_error(WSAGetLastError()); + } + } else if (addr_st.ss_family == AF_INET6) { + if (setsockopt(handle->socket, + IPPROTO_IPV6, + IPV6_MULTICAST_IF, + (char*) &addr6->sin6_scope_id, + sizeof(addr6->sin6_scope_id)) == SOCKET_ERROR) { + return uv_translate_sys_error(WSAGetLastError()); + } + } else { + assert(0 && "unexpected address family"); + abort(); + } + + return 0; +} + + +int uv_udp_set_broadcast(uv_udp_t* handle, int value) { + BOOL optval = (BOOL) value; + + if (!(handle->flags & UV_HANDLE_BOUND)) + return UV_EBADF; + + if (setsockopt(handle->socket, + SOL_SOCKET, + SO_BROADCAST, + (char*) &optval, + sizeof optval)) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { + WSAPROTOCOL_INFOW protocol_info; + int opt_len; + int err; + + /* Detect the address family of the socket. */ + opt_len = (int) sizeof protocol_info; + if (getsockopt(sock, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &opt_len) == SOCKET_ERROR) { + return uv_translate_sys_error(GetLastError()); + } + + err = uv_udp_set_socket(handle->loop, + handle, + sock, + protocol_info.iAddressFamily); + return uv_translate_sys_error(err); +} + + +#define SOCKOPT_SETTER(name, option4, option6, validate) \ + int uv_udp_set_##name(uv_udp_t* handle, int value) { \ + DWORD optval = (DWORD) value; \ + \ + if (!(validate(value))) { \ + return UV_EINVAL; \ + } \ + \ + if (!(handle->flags & UV_HANDLE_BOUND)) \ + return UV_EBADF; \ + \ + if (!(handle->flags & UV_HANDLE_IPV6)) { \ + /* Set IPv4 socket option */ \ + if (setsockopt(handle->socket, \ + IPPROTO_IP, \ + option4, \ + (char*) &optval, \ + sizeof optval)) { \ + return uv_translate_sys_error(WSAGetLastError()); \ + } \ + } else { \ + /* Set IPv6 socket option */ \ + if (setsockopt(handle->socket, \ + IPPROTO_IPV6, \ + option6, \ + (char*) &optval, \ + sizeof optval)) { \ + return uv_translate_sys_error(WSAGetLastError()); \ + } \ + } \ + return 0; \ + } + +#define VALIDATE_TTL(value) ((value) >= 1 && (value) <= 255) +#define VALIDATE_MULTICAST_TTL(value) ((value) >= -1 && (value) <= 255) +#define VALIDATE_MULTICAST_LOOP(value) (1) + +SOCKOPT_SETTER(ttl, + IP_TTL, + IPV6_HOPLIMIT, + VALIDATE_TTL) +SOCKOPT_SETTER(multicast_ttl, + IP_MULTICAST_TTL, + IPV6_MULTICAST_HOPS, + VALIDATE_MULTICAST_TTL) +SOCKOPT_SETTER(multicast_loop, + IP_MULTICAST_LOOP, + IPV6_MULTICAST_LOOP, + VALIDATE_MULTICAST_LOOP) + +#undef SOCKOPT_SETTER +#undef VALIDATE_TTL +#undef VALIDATE_MULTICAST_TTL +#undef VALIDATE_MULTICAST_LOOP + + +/* This function is an egress point, i.e. it returns libuv errors rather than + * system errors. + */ +int uv__udp_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + int err; + + err = uv_udp_maybe_bind(handle, addr, addrlen, flags); + if (err) + return uv_translate_sys_error(err); + + return 0; +} + + +/* This function is an egress point, i.e. it returns libuv errors rather than + * system errors. + */ +int uv__udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen, + uv_udp_send_cb send_cb) { + const struct sockaddr* bind_addr; + int err; + + if (!(handle->flags & UV_HANDLE_BOUND)) { + if (addrlen == sizeof(uv_addr_ip4_any_)) { + bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_; + } else if (addrlen == sizeof(uv_addr_ip6_any_)) { + bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_; + } else { + abort(); + } + err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); + if (err) + return uv_translate_sys_error(err); + } + + err = uv__send(req, handle, bufs, nbufs, addr, addrlen, send_cb); + if (err) + return uv_translate_sys_error(err); + + return 0; +} + + +int uv__udp_try_send(uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen) { + return UV_ENOSYS; +} diff --git a/src/win/util.c b/src/win/util.c new file mode 100644 index 0000000..4a2e501 --- /dev/null +++ b/src/win/util.c @@ -0,0 +1,1380 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include +#include + + +/* + * Max title length; the only thing MSDN tells us about the maximum length + * of the console title is that it is smaller than 64K. However in practice + * it is much smaller, and there is no way to figure out what the exact length + * of the title is or can be, at least not on XP. To make it even more + * annoying, GetConsoleTitle fails when the buffer to be read into is bigger + * than the actual maximum length. So we make a conservative guess here; + * just don't put the novel you're writing in the title, unless the plot + * survives truncation. + */ +#define MAX_TITLE_LENGTH 8192 + +/* The number of nanoseconds in one second. */ +#define UV__NANOSEC 1000000000 + +/* Max user name length, from iphlpapi.h */ +#ifndef UNLEN +# define UNLEN 256 +#endif + +/* Cached copy of the process title, plus a mutex guarding it. */ +static char *process_title; +static CRITICAL_SECTION process_title_lock; + +/* Cached copy of the process id, written once. */ +static DWORD current_pid = 0; + + +/* Interval (in seconds) of the high-resolution clock. */ +static double hrtime_interval_ = 0; + + +/* + * One-time initialization code for functionality defined in util.c. + */ +void uv__util_init() { + LARGE_INTEGER perf_frequency; + + /* Initialize process title access mutex. */ + InitializeCriticalSection(&process_title_lock); + + /* Retrieve high-resolution timer frequency + * and precompute its reciprocal. + */ + if (QueryPerformanceFrequency(&perf_frequency)) { + hrtime_interval_ = 1.0 / perf_frequency.QuadPart; + } else { + hrtime_interval_= 0; + } +} + + +int uv_exepath(char* buffer, size_t* size_ptr) { + int utf8_len, utf16_buffer_len, utf16_len; + WCHAR* utf16_buffer; + int err; + + if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) { + return UV_EINVAL; + } + + if (*size_ptr > 32768) { + /* Windows paths can never be longer than this. */ + utf16_buffer_len = 32768; + } else { + utf16_buffer_len = (int) *size_ptr; + } + + utf16_buffer = (WCHAR*) uv__malloc(sizeof(WCHAR) * utf16_buffer_len); + if (!utf16_buffer) { + return UV_ENOMEM; + } + + /* Get the path as UTF-16. */ + utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len); + if (utf16_len <= 0) { + err = GetLastError(); + goto error; + } + + /* utf16_len contains the length, *not* including the terminating null. */ + utf16_buffer[utf16_len] = L'\0'; + + /* Convert to UTF-8 */ + utf8_len = WideCharToMultiByte(CP_UTF8, + 0, + utf16_buffer, + -1, + buffer, + (int) *size_ptr, + NULL, + NULL); + if (utf8_len == 0) { + err = GetLastError(); + goto error; + } + + uv__free(utf16_buffer); + + /* utf8_len *does* include the terminating null at this point, but the */ + /* returned size shouldn't. */ + *size_ptr = utf8_len - 1; + return 0; + + error: + uv__free(utf16_buffer); + return uv_translate_sys_error(err); +} + + +int uv_cwd(char* buffer, size_t* size) { + DWORD utf16_len; + WCHAR utf16_buffer[MAX_PATH]; + int r; + + if (buffer == NULL || size == NULL) { + return UV_EINVAL; + } + + utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer); + if (utf16_len == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (utf16_len > MAX_PATH) { + /* This should be impossible; however the CRT has a code path to deal */ + /* with this scenario, so I added a check anyway. */ + return UV_EIO; + } + + /* utf16_len contains the length, *not* including the terminating null. */ + utf16_buffer[utf16_len] = L'\0'; + + /* The returned directory should not have a trailing slash, unless it */ + /* points at a drive root, like c:\. Remove it if needed.*/ + if (utf16_buffer[utf16_len - 1] == L'\\' && + !(utf16_len == 3 && utf16_buffer[1] == L':')) { + utf16_len--; + utf16_buffer[utf16_len] = L'\0'; + } + + /* Check how much space we need */ + r = WideCharToMultiByte(CP_UTF8, + 0, + utf16_buffer, + -1, + NULL, + 0, + NULL, + NULL); + if (r == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (r > (int) *size) { + *size = r; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + r = WideCharToMultiByte(CP_UTF8, + 0, + utf16_buffer, + -1, + buffer, + *size > INT_MAX ? INT_MAX : (int) *size, + NULL, + NULL); + if (r == 0) { + return uv_translate_sys_error(GetLastError()); + } + + *size = r - 1; + return 0; +} + + +int uv_chdir(const char* dir) { + WCHAR utf16_buffer[MAX_PATH]; + size_t utf16_len; + WCHAR drive_letter, env_var[4]; + + if (dir == NULL) { + return UV_EINVAL; + } + + if (MultiByteToWideChar(CP_UTF8, + 0, + dir, + -1, + utf16_buffer, + MAX_PATH) == 0) { + DWORD error = GetLastError(); + /* The maximum length of the current working directory is 260 chars, */ + /* including terminating null. If it doesn't fit, the path name must be */ + /* too long. */ + if (error == ERROR_INSUFFICIENT_BUFFER) { + return UV_ENAMETOOLONG; + } else { + return uv_translate_sys_error(error); + } + } + + if (!SetCurrentDirectoryW(utf16_buffer)) { + return uv_translate_sys_error(GetLastError()); + } + + /* Windows stores the drive-local path in an "hidden" environment variable, */ + /* which has the form "=C:=C:\Windows". SetCurrentDirectory does not */ + /* update this, so we'll have to do it. */ + utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer); + if (utf16_len == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (utf16_len > MAX_PATH) { + return UV_EIO; + } + + /* The returned directory should not have a trailing slash, unless it */ + /* points at a drive root, like c:\. Remove it if needed. */ + if (utf16_buffer[utf16_len - 1] == L'\\' && + !(utf16_len == 3 && utf16_buffer[1] == L':')) { + utf16_len--; + utf16_buffer[utf16_len] = L'\0'; + } + + if (utf16_len < 2 || utf16_buffer[1] != L':') { + /* Doesn't look like a drive letter could be there - probably an UNC */ + /* path. TODO: Need to handle win32 namespaces like \\?\C:\ ? */ + drive_letter = 0; + } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') { + drive_letter = utf16_buffer[0]; + } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') { + /* Convert to uppercase. */ + drive_letter = utf16_buffer[0] - L'a' + L'A'; + } else { + /* Not valid. */ + drive_letter = 0; + } + + if (drive_letter != 0) { + /* Construct the environment variable name and set it. */ + env_var[0] = L'='; + env_var[1] = drive_letter; + env_var[2] = L':'; + env_var[3] = L'\0'; + + if (!SetEnvironmentVariableW(env_var, utf16_buffer)) { + return uv_translate_sys_error(GetLastError()); + } + } + + return 0; +} + + +void uv_loadavg(double avg[3]) { + /* Can't be implemented */ + avg[0] = avg[1] = avg[2] = 0; +} + + +uint64_t uv_get_free_memory(void) { + MEMORYSTATUSEX memory_status; + memory_status.dwLength = sizeof(memory_status); + + if (!GlobalMemoryStatusEx(&memory_status)) { + return -1; + } + + return (uint64_t)memory_status.ullAvailPhys; +} + + +uint64_t uv_get_total_memory(void) { + MEMORYSTATUSEX memory_status; + memory_status.dwLength = sizeof(memory_status); + + if (!GlobalMemoryStatusEx(&memory_status)) { + return -1; + } + + return (uint64_t)memory_status.ullTotalPhys; +} + + +int uv_parent_pid() { + int parent_pid = -1; + HANDLE handle; + PROCESSENTRY32 pe; + DWORD current_pid = GetCurrentProcessId(); + + pe.dwSize = sizeof(PROCESSENTRY32); + handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + + if (Process32First(handle, &pe)) { + do { + if (pe.th32ProcessID == current_pid) { + parent_pid = pe.th32ParentProcessID; + break; + } + } while( Process32Next(handle, &pe)); + } + + CloseHandle(handle); + return parent_pid; +} + + +int uv_current_pid() { + if (current_pid == 0) { + current_pid = GetCurrentProcessId(); + } + return current_pid; +} + + +char** uv_setup_args(int argc, char** argv) { + return argv; +} + + +int uv_set_process_title(const char* title) { + int err; + int length; + WCHAR* title_w = NULL; + + uv__once_init(); + + /* Find out how big the buffer for the wide-char title must be */ + length = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0); + if (!length) { + err = GetLastError(); + goto done; + } + + /* Convert to wide-char string */ + title_w = (WCHAR*)uv__malloc(sizeof(WCHAR) * length); + if (!title_w) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + length = MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, length); + if (!length) { + err = GetLastError(); + goto done; + } + + /* If the title must be truncated insert a \0 terminator there */ + if (length > MAX_TITLE_LENGTH) { + title_w[MAX_TITLE_LENGTH - 1] = L'\0'; + } + + if (!SetConsoleTitleW(title_w)) { + err = GetLastError(); + goto done; + } + + EnterCriticalSection(&process_title_lock); + uv__free(process_title); + process_title = uv__strdup(title); + LeaveCriticalSection(&process_title_lock); + + err = 0; + +done: + uv__free(title_w); + return uv_translate_sys_error(err); +} + + +static int uv__get_process_title() { + WCHAR title_w[MAX_TITLE_LENGTH]; + + if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) { + return -1; + } + + if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0) + return -1; + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return UV_EINVAL; + + uv__once_init(); + + EnterCriticalSection(&process_title_lock); + /* + * If the process_title was never read before nor explicitly set, + * we must query it with getConsoleTitleW + */ + if (!process_title && uv__get_process_title() == -1) { + LeaveCriticalSection(&process_title_lock); + return uv_translate_sys_error(GetLastError()); + } + + assert(process_title); + len = strlen(process_title) + 1; + + if (size < len) { + LeaveCriticalSection(&process_title_lock); + return UV_ENOBUFS; + } + + memcpy(buffer, process_title, len); + LeaveCriticalSection(&process_title_lock); + + return 0; +} + + +uint64_t uv_hrtime(void) { + uv__once_init(); + return uv__hrtime(UV__NANOSEC); +} + +uint64_t uv__hrtime(double scale) { + LARGE_INTEGER counter; + + /* If the performance interval is zero, there's no support. */ + if (hrtime_interval_ == 0) { + return 0; + } + + if (!QueryPerformanceCounter(&counter)) { + return 0; + } + + /* Because we have no guarantee about the order of magnitude of the + * performance counter interval, integer math could cause this computation + * to overflow. Therefore we resort to floating point math. + */ + return (uint64_t) ((double) counter.QuadPart * hrtime_interval_ * scale); +} + + +int uv_resident_set_memory(size_t* rss) { + HANDLE current_process; + PROCESS_MEMORY_COUNTERS pmc; + + current_process = GetCurrentProcess(); + + if (!GetProcessMemoryInfo(current_process, &pmc, sizeof(pmc))) { + return uv_translate_sys_error(GetLastError()); + } + + *rss = pmc.WorkingSetSize; + + return 0; +} + + +int uv_uptime(double* uptime) { + BYTE stack_buffer[4096]; + BYTE* malloced_buffer = NULL; + BYTE* buffer = (BYTE*) stack_buffer; + size_t buffer_size = sizeof(stack_buffer); + DWORD data_size; + + PERF_DATA_BLOCK* data_block; + PERF_OBJECT_TYPE* object_type; + PERF_COUNTER_DEFINITION* counter_definition; + + DWORD i; + + for (;;) { + LONG result; + + data_size = (DWORD) buffer_size; + result = RegQueryValueExW(HKEY_PERFORMANCE_DATA, + L"2", + NULL, + NULL, + buffer, + &data_size); + if (result == ERROR_SUCCESS) { + break; + } else if (result != ERROR_MORE_DATA) { + *uptime = 0; + return uv_translate_sys_error(result); + } + + buffer_size *= 2; + /* Don't let the buffer grow infinitely. */ + if (buffer_size > 1 << 20) { + goto internalError; + } + + uv__free(malloced_buffer); + + buffer = malloced_buffer = (BYTE*) uv__malloc(buffer_size); + if (malloced_buffer == NULL) { + *uptime = 0; + return UV_ENOMEM; + } + } + + if (data_size < sizeof(*data_block)) + goto internalError; + + data_block = (PERF_DATA_BLOCK*) buffer; + + if (wmemcmp(data_block->Signature, L"PERF", 4) != 0) + goto internalError; + + if (data_size < data_block->HeaderLength + sizeof(*object_type)) + goto internalError; + + object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength); + + if (object_type->NumInstances != PERF_NO_INSTANCES) + goto internalError; + + counter_definition = (PERF_COUNTER_DEFINITION*) (buffer + + data_block->HeaderLength + object_type->HeaderLength); + for (i = 0; i < object_type->NumCounters; i++) { + if ((BYTE*) counter_definition + sizeof(*counter_definition) > + buffer + data_size) { + break; + } + + if (counter_definition->CounterNameTitleIndex == 674 && + counter_definition->CounterSize == sizeof(uint64_t)) { + if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size || + !(counter_definition->CounterType & PERF_OBJECT_TIMER)) { + goto internalError; + } else { + BYTE* address = (BYTE*) object_type + object_type->DefinitionLength + + counter_definition->CounterOffset; + uint64_t value = *((uint64_t*) address); + *uptime = (double) (object_type->PerfTime.QuadPart - value) / + (double) object_type->PerfFreq.QuadPart; + uv__free(malloced_buffer); + return 0; + } + } + + counter_definition = (PERF_COUNTER_DEFINITION*) + ((BYTE*) counter_definition + counter_definition->ByteLength); + } + + /* If we get here, the uptime value was not found. */ + uv__free(malloced_buffer); + *uptime = 0; + return UV_ENOSYS; + + internalError: + uv__free(malloced_buffer); + *uptime = 0; + return UV_EIO; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { + uv_cpu_info_t* cpu_infos; + SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi; + DWORD sppi_size; + SYSTEM_INFO system_info; + DWORD cpu_count, r, i; + NTSTATUS status; + ULONG result_size; + int err; + uv_cpu_info_t* cpu_info; + + cpu_infos = NULL; + cpu_count = 0; + sppi = NULL; + + uv__once_init(); + + GetSystemInfo(&system_info); + cpu_count = system_info.dwNumberOfProcessors; + + cpu_infos = uv__calloc(cpu_count, sizeof *cpu_infos); + if (cpu_infos == NULL) { + err = ERROR_OUTOFMEMORY; + goto error; + } + + sppi_size = cpu_count * sizeof(*sppi); + sppi = uv__malloc(sppi_size); + if (sppi == NULL) { + err = ERROR_OUTOFMEMORY; + goto error; + } + + status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, + sppi, + sppi_size, + &result_size); + if (!NT_SUCCESS(status)) { + err = pRtlNtStatusToDosError(status); + goto error; + } + + assert(result_size == sppi_size); + + for (i = 0; i < cpu_count; i++) { + WCHAR key_name[128]; + HKEY processor_key; + DWORD cpu_speed; + DWORD cpu_speed_size = sizeof(cpu_speed); + WCHAR cpu_brand[256]; + DWORD cpu_brand_size = sizeof(cpu_brand); + size_t len; + + len = _snwprintf(key_name, + ARRAY_SIZE(key_name), + L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", + i); + + assert(len > 0 && len < ARRAY_SIZE(key_name)); + + r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + key_name, + 0, + KEY_QUERY_VALUE, + &processor_key); + if (r != ERROR_SUCCESS) { + err = GetLastError(); + goto error; + } + + if (RegQueryValueExW(processor_key, + L"~MHz", + NULL, + NULL, + (BYTE*) &cpu_speed, + &cpu_speed_size) != ERROR_SUCCESS) { + err = GetLastError(); + RegCloseKey(processor_key); + goto error; + } + + if (RegQueryValueExW(processor_key, + L"ProcessorNameString", + NULL, + NULL, + (BYTE*) &cpu_brand, + &cpu_brand_size) != ERROR_SUCCESS) { + err = GetLastError(); + RegCloseKey(processor_key); + goto error; + } + + RegCloseKey(processor_key); + + cpu_info = &cpu_infos[i]; + cpu_info->speed = cpu_speed; + cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000; + cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart - + sppi[i].IdleTime.QuadPart) / 10000; + cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000; + cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000; + cpu_info->cpu_times.nice = 0; + + uv__convert_utf16_to_utf8(cpu_brand, + cpu_brand_size / sizeof(WCHAR), + &(cpu_info->model)); + } + + uv__free(sppi); + + *cpu_count_ptr = cpu_count; + *cpu_infos_ptr = cpu_infos; + + return 0; + + error: + /* This is safe because the cpu_infos array is zeroed on allocation. */ + for (i = 0; i < cpu_count; i++) + uv__free(cpu_infos[i].model); + + uv__free(cpu_infos); + uv__free(sppi); + + return uv_translate_sys_error(err); +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +static int is_windows_version_or_greater(DWORD os_major, + DWORD os_minor, + WORD service_pack_major, + WORD service_pack_minor) { + OSVERSIONINFOEX osvi; + DWORDLONG condition_mask = 0; + int op = VER_GREATER_EQUAL; + + /* Initialize the OSVERSIONINFOEX structure. */ + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + osvi.dwMajorVersion = os_major; + osvi.dwMinorVersion = os_minor; + osvi.wServicePackMajor = service_pack_major; + osvi.wServicePackMinor = service_pack_minor; + + /* Initialize the condition mask. */ + VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op); + VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op); + VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op); + VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op); + + /* Perform the test. */ + return (int) VerifyVersionInfo( + &osvi, + VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, + condition_mask); +} + + +static int address_prefix_match(int family, + struct sockaddr* address, + struct sockaddr* prefix_address, + int prefix_len) { + uint8_t* address_data; + uint8_t* prefix_address_data; + int i; + + assert(address->sa_family == family); + assert(prefix_address->sa_family == family); + + if (family == AF_INET6) { + address_data = (uint8_t*) &(((struct sockaddr_in6 *) address)->sin6_addr); + prefix_address_data = + (uint8_t*) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr); + } else { + address_data = (uint8_t*) &(((struct sockaddr_in *) address)->sin_addr); + prefix_address_data = + (uint8_t*) &(((struct sockaddr_in *) prefix_address)->sin_addr); + } + + for (i = 0; i < prefix_len >> 3; i++) { + if (address_data[i] != prefix_address_data[i]) + return 0; + } + + if (prefix_len % 8) + return prefix_address_data[i] == + (address_data[i] & (0xff << (8 - prefix_len % 8))); + + return 1; +} + + +int uv_interface_addresses(uv_interface_address_t** addresses_ptr, + int* count_ptr) { + IP_ADAPTER_ADDRESSES* win_address_buf; + ULONG win_address_buf_size; + IP_ADAPTER_ADDRESSES* adapter; + + uv_interface_address_t* uv_address_buf; + char* name_buf; + size_t uv_address_buf_size; + uv_interface_address_t* uv_address; + + int count; + + int is_vista_or_greater; + ULONG flags; + + is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0); + if (is_vista_or_greater) { + flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | + GAA_FLAG_SKIP_DNS_SERVER; + } else { + /* We need at least XP SP1. */ + if (!is_windows_version_or_greater(5, 1, 1, 0)) + return UV_ENOTSUP; + + flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | + GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX; + } + + + /* Fetch the size of the adapters reported by windows, and then get the */ + /* list itself. */ + win_address_buf_size = 0; + win_address_buf = NULL; + + for (;;) { + ULONG r; + + /* If win_address_buf is 0, then GetAdaptersAddresses will fail with */ + /* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */ + /* win_address_buf_size. */ + r = GetAdaptersAddresses(AF_UNSPEC, + flags, + NULL, + win_address_buf, + &win_address_buf_size); + + if (r == ERROR_SUCCESS) + break; + + uv__free(win_address_buf); + + switch (r) { + case ERROR_BUFFER_OVERFLOW: + /* This happens when win_address_buf is NULL or too small to hold */ + /* all adapters. */ + win_address_buf = uv__malloc(win_address_buf_size); + if (win_address_buf == NULL) + return UV_ENOMEM; + + continue; + + case ERROR_NO_DATA: { + /* No adapters were found. */ + uv_address_buf = uv__malloc(1); + if (uv_address_buf == NULL) + return UV_ENOMEM; + + *count_ptr = 0; + *addresses_ptr = uv_address_buf; + + return 0; + } + + case ERROR_ADDRESS_NOT_ASSOCIATED: + return UV_EAGAIN; + + case ERROR_INVALID_PARAMETER: + /* MSDN says: + * "This error is returned for any of the following conditions: the + * SizePointer parameter is NULL, the Address parameter is not + * AF_INET, AF_INET6, or AF_UNSPEC, or the address information for + * the parameters requested is greater than ULONG_MAX." + * Since the first two conditions are not met, it must be that the + * adapter data is too big. + */ + return UV_ENOBUFS; + + default: + /* Other (unspecified) errors can happen, but we don't have any */ + /* special meaning for them. */ + assert(r != ERROR_SUCCESS); + return uv_translate_sys_error(r); + } + } + + /* Count the number of enabled interfaces and compute how much space is */ + /* needed to store their info. */ + count = 0; + uv_address_buf_size = 0; + + for (adapter = win_address_buf; + adapter != NULL; + adapter = adapter->Next) { + IP_ADAPTER_UNICAST_ADDRESS* unicast_address; + int name_size; + + /* Interfaces that are not 'up' should not be reported. Also skip */ + /* interfaces that have no associated unicast address, as to avoid */ + /* allocating space for the name for this interface. */ + if (adapter->OperStatus != IfOperStatusUp || + adapter->FirstUnicastAddress == NULL) + continue; + + /* Compute the size of the interface name. */ + name_size = WideCharToMultiByte(CP_UTF8, + 0, + adapter->FriendlyName, + -1, + NULL, + 0, + NULL, + FALSE); + if (name_size <= 0) { + uv__free(win_address_buf); + return uv_translate_sys_error(GetLastError()); + } + uv_address_buf_size += name_size; + + /* Count the number of addresses associated with this interface, and */ + /* compute the size. */ + for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*) + adapter->FirstUnicastAddress; + unicast_address != NULL; + unicast_address = unicast_address->Next) { + count++; + uv_address_buf_size += sizeof(uv_interface_address_t); + } + } + + /* Allocate space to store interface data plus adapter names. */ + uv_address_buf = uv__malloc(uv_address_buf_size); + if (uv_address_buf == NULL) { + uv__free(win_address_buf); + return UV_ENOMEM; + } + + /* Compute the start of the uv_interface_address_t array, and the place in */ + /* the buffer where the interface names will be stored. */ + uv_address = uv_address_buf; + name_buf = (char*) (uv_address_buf + count); + + /* Fill out the output buffer. */ + for (adapter = win_address_buf; + adapter != NULL; + adapter = adapter->Next) { + IP_ADAPTER_UNICAST_ADDRESS* unicast_address; + int name_size; + size_t max_name_size; + + if (adapter->OperStatus != IfOperStatusUp || + adapter->FirstUnicastAddress == NULL) + continue; + + /* Convert the interface name to UTF8. */ + max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf; + if (max_name_size > (size_t) INT_MAX) + max_name_size = INT_MAX; + name_size = WideCharToMultiByte(CP_UTF8, + 0, + adapter->FriendlyName, + -1, + name_buf, + (int) max_name_size, + NULL, + FALSE); + if (name_size <= 0) { + uv__free(win_address_buf); + uv__free(uv_address_buf); + return uv_translate_sys_error(GetLastError()); + } + + /* Add an uv_interface_address_t element for every unicast address. */ + for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*) + adapter->FirstUnicastAddress; + unicast_address != NULL; + unicast_address = unicast_address->Next) { + struct sockaddr* sa; + ULONG prefix_len; + + sa = unicast_address->Address.lpSockaddr; + + /* XP has no OnLinkPrefixLength field. */ + if (is_vista_or_greater) { + prefix_len = + ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength; + } else { + /* Prior to Windows Vista the FirstPrefix pointed to the list with + * single prefix for each IP address assigned to the adapter. + * Order of FirstPrefix does not match order of FirstUnicastAddress, + * so we need to find corresponding prefix. + */ + IP_ADAPTER_PREFIX* prefix; + prefix_len = 0; + + for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) { + /* We want the longest matching prefix. */ + if (prefix->Address.lpSockaddr->sa_family != sa->sa_family || + prefix->PrefixLength <= prefix_len) + continue; + + if (address_prefix_match(sa->sa_family, sa, + prefix->Address.lpSockaddr, prefix->PrefixLength)) { + prefix_len = prefix->PrefixLength; + } + } + + /* If there is no matching prefix information, return a single-host + * subnet mask (e.g. 255.255.255.255 for IPv4). + */ + if (!prefix_len) + prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32; + } + + memset(uv_address, 0, sizeof *uv_address); + + uv_address->name = name_buf; + + if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) { + memcpy(uv_address->phys_addr, + adapter->PhysicalAddress, + sizeof(uv_address->phys_addr)); + } + + uv_address->is_internal = + (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK); + + if (sa->sa_family == AF_INET6) { + uv_address->address.address6 = *((struct sockaddr_in6 *) sa); + + uv_address->netmask.netmask6.sin6_family = AF_INET6; + memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3); + /* This check ensures that we don't write past the size of the data. */ + if (prefix_len % 8) { + uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] = + 0xff << (8 - prefix_len % 8); + } + + } else { + uv_address->address.address4 = *((struct sockaddr_in *) sa); + + uv_address->netmask.netmask4.sin_family = AF_INET; + uv_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ? + htonl(0xffffffff << (32 - prefix_len)) : 0; + } + + uv_address++; + } + + name_buf += name_size; + } + + uv__free(win_address_buf); + + *addresses_ptr = uv_address_buf; + *count_ptr = count; + + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + uv__free(addresses); +} + + +int uv_getrusage(uv_rusage_t *uv_rusage) { + FILETIME createTime, exitTime, kernelTime, userTime; + SYSTEMTIME kernelSystemTime, userSystemTime; + PROCESS_MEMORY_COUNTERS memCounters; + int ret; + + ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + ret = FileTimeToSystemTime(&userTime, &userSystemTime); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + ret = GetProcessMemoryInfo(GetCurrentProcess(), + &memCounters, + sizeof(memCounters)); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + memset(uv_rusage, 0, sizeof(*uv_rusage)); + + uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 + + userSystemTime.wMinute * 60 + + userSystemTime.wSecond; + uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000; + + uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 + + kernelSystemTime.wMinute * 60 + + kernelSystemTime.wSecond; + uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000; + + uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount; + uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024; + + return 0; +} + + +int uv_os_homedir(char* buffer, size_t* size) { + uv_passwd_t pwd; + wchar_t path[MAX_PATH]; + DWORD bufsize; + size_t len; + int r; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + /* Check if the USERPROFILE environment variable is set first */ + len = GetEnvironmentVariableW(L"USERPROFILE", path, MAX_PATH); + + if (len == 0) { + r = GetLastError(); + + /* Don't return an error if USERPROFILE was not found */ + if (r != ERROR_ENVVAR_NOT_FOUND) + return uv_translate_sys_error(r); + } else if (len > MAX_PATH) { + /* This should not be possible */ + return UV_EIO; + } else { + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; + } + + /* USERPROFILE is not set, so call uv__getpwuid_r() */ + r = uv__getpwuid_r(&pwd); + + if (r != 0) { + return r; + } + + len = strlen(pwd.homedir); + + if (len >= *size) { + *size = len + 1; + uv_os_free_passwd(&pwd); + return UV_ENOBUFS; + } + + memcpy(buffer, pwd.homedir, len + 1); + *size = len; + uv_os_free_passwd(&pwd); + + return 0; +} + + +int uv_os_tmpdir(char* buffer, size_t* size) { + wchar_t path[MAX_PATH + 1]; + DWORD bufsize; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + len = GetTempPathW(MAX_PATH + 1, path); + + if (len == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (len > MAX_PATH + 1) { + /* This should not be possible */ + return UV_EIO; + } + + /* The returned directory should not have a trailing slash, unless it */ + /* points at a drive root, like c:\. Remove it if needed.*/ + if (path[len - 1] == L'\\' && + !(len == 3 && path[1] == L':')) { + len--; + path[len] = L'\0'; + } + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; +} + + +void uv_os_free_passwd(uv_passwd_t* pwd) { + if (pwd == NULL) + return; + + uv__free(pwd->username); + uv__free(pwd->homedir); + pwd->username = NULL; + pwd->homedir = NULL; +} + + +/* + * Converts a UTF-16 string into a UTF-8 one. The resulting string is + * null-terminated. + * + * If utf16 is null terminated, utf16len can be set to -1, otherwise it must + * be specified. + */ +int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) { + DWORD bufsize; + + if (utf16 == NULL) + return UV_EINVAL; + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + utf16len, + NULL, + 0, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + /* Allocate the destination buffer adding an extra byte for the terminating + * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so + * we do it ourselves always, just in case. */ + *utf8 = uv__malloc(bufsize + 1); + + if (*utf8 == NULL) + return UV_ENOMEM; + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + utf16len, + *utf8, + bufsize, + NULL, + NULL); + + if (bufsize == 0) { + uv__free(*utf8); + *utf8 = NULL; + return uv_translate_sys_error(GetLastError()); + } + + (*utf8)[bufsize] = '\0'; + return 0; +} + + +int uv__getpwuid_r(uv_passwd_t* pwd) { + HANDLE token; + wchar_t username[UNLEN + 1]; + wchar_t path[MAX_PATH]; + DWORD bufsize; + int r; + + if (pwd == NULL) + return UV_EINVAL; + + /* Get the home directory using GetUserProfileDirectoryW() */ + if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0) + return uv_translate_sys_error(GetLastError()); + + bufsize = sizeof(path); + if (!GetUserProfileDirectoryW(token, path, &bufsize)) { + r = GetLastError(); + CloseHandle(token); + + /* This should not be possible */ + if (r == ERROR_INSUFFICIENT_BUFFER) + return UV_ENOMEM; + + return uv_translate_sys_error(r); + } + + CloseHandle(token); + + /* Get the username using GetUserNameW() */ + bufsize = sizeof(username); + if (!GetUserNameW(username, &bufsize)) { + r = GetLastError(); + + /* This should not be possible */ + if (r == ERROR_INSUFFICIENT_BUFFER) + return UV_ENOMEM; + + return uv_translate_sys_error(r); + } + + pwd->homedir = NULL; + r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir); + + if (r != 0) + return r; + + pwd->username = NULL; + r = uv__convert_utf16_to_utf8(username, -1, &pwd->username); + + if (r != 0) { + uv__free(pwd->homedir); + return r; + } + + pwd->shell = NULL; + pwd->uid = -1; + pwd->gid = -1; + + return 0; +} + + +int uv_os_get_passwd(uv_passwd_t* pwd) { + return uv__getpwuid_r(pwd); +} diff --git a/src/win/winapi.c b/src/win/winapi.c new file mode 100644 index 0000000..1fa179b --- /dev/null +++ b/src/win/winapi.c @@ -0,0 +1,159 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include + +#include "uv.h" +#include "internal.h" + + +/* Ntdll function pointers */ +sRtlNtStatusToDosError pRtlNtStatusToDosError; +sNtDeviceIoControlFile pNtDeviceIoControlFile; +sNtQueryInformationFile pNtQueryInformationFile; +sNtSetInformationFile pNtSetInformationFile; +sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile; +sNtQueryDirectoryFile pNtQueryDirectoryFile; +sNtQuerySystemInformation pNtQuerySystemInformation; + + +/* Kernel32 function pointers */ +sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; +sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; +sCreateSymbolicLinkW pCreateSymbolicLinkW; +sCancelIoEx pCancelIoEx; +sInitializeConditionVariable pInitializeConditionVariable; +sSleepConditionVariableCS pSleepConditionVariableCS; +sSleepConditionVariableSRW pSleepConditionVariableSRW; +sWakeAllConditionVariable pWakeAllConditionVariable; +sWakeConditionVariable pWakeConditionVariable; +sCancelSynchronousIo pCancelSynchronousIo; +sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; + + +/* Powrprof.dll function pointer */ +sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; + + +void uv_winapi_init() { + HMODULE ntdll_module; + HMODULE kernel32_module; + HMODULE powrprof_module; + + ntdll_module = GetModuleHandleA("ntdll.dll"); + if (ntdll_module == NULL) { + uv_fatal_error(GetLastError(), "GetModuleHandleA"); + } + + pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress( + ntdll_module, + "RtlNtStatusToDosError"); + if (pRtlNtStatusToDosError == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtDeviceIoControlFile = (sNtDeviceIoControlFile) GetProcAddress( + ntdll_module, + "NtDeviceIoControlFile"); + if (pNtDeviceIoControlFile == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress( + ntdll_module, + "NtQueryInformationFile"); + if (pNtQueryInformationFile == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtSetInformationFile = (sNtSetInformationFile) GetProcAddress( + ntdll_module, + "NtSetInformationFile"); + if (pNtSetInformationFile == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtQueryVolumeInformationFile = (sNtQueryVolumeInformationFile) + GetProcAddress(ntdll_module, "NtQueryVolumeInformationFile"); + if (pNtQueryVolumeInformationFile == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtQueryDirectoryFile = (sNtQueryDirectoryFile) + GetProcAddress(ntdll_module, "NtQueryDirectoryFile"); + if (pNtQueryVolumeInformationFile == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress( + ntdll_module, + "NtQuerySystemInformation"); + if (pNtQuerySystemInformation == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + kernel32_module = GetModuleHandleA("kernel32.dll"); + if (kernel32_module == NULL) { + uv_fatal_error(GetLastError(), "GetModuleHandleA"); + } + + pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress( + kernel32_module, + "GetQueuedCompletionStatusEx"); + + pSetFileCompletionNotificationModes = (sSetFileCompletionNotificationModes) + GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes"); + + pCreateSymbolicLinkW = (sCreateSymbolicLinkW) + GetProcAddress(kernel32_module, "CreateSymbolicLinkW"); + + pCancelIoEx = (sCancelIoEx) + GetProcAddress(kernel32_module, "CancelIoEx"); + + pInitializeConditionVariable = (sInitializeConditionVariable) + GetProcAddress(kernel32_module, "InitializeConditionVariable"); + + pSleepConditionVariableCS = (sSleepConditionVariableCS) + GetProcAddress(kernel32_module, "SleepConditionVariableCS"); + + pSleepConditionVariableSRW = (sSleepConditionVariableSRW) + GetProcAddress(kernel32_module, "SleepConditionVariableSRW"); + + pWakeAllConditionVariable = (sWakeAllConditionVariable) + GetProcAddress(kernel32_module, "WakeAllConditionVariable"); + + pWakeConditionVariable = (sWakeConditionVariable) + GetProcAddress(kernel32_module, "WakeConditionVariable"); + + pCancelSynchronousIo = (sCancelSynchronousIo) + GetProcAddress(kernel32_module, "CancelSynchronousIo"); + + pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW) + GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW"); + + + powrprof_module = LoadLibraryA("powrprof.dll"); + if (powrprof_module != NULL) { + pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) + GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification"); + } + +} diff --git a/src/win/winapi.h b/src/win/winapi.h new file mode 100644 index 0000000..16d9365 --- /dev/null +++ b/src/win/winapi.h @@ -0,0 +1,4748 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_WIN_WINAPI_H_ +#define UV_WIN_WINAPI_H_ + +#include + + +/* + * Ntdll headers + */ +#ifndef STATUS_SEVERITY_SUCCESS +# define STATUS_SEVERITY_SUCCESS 0x0 +#endif + +#ifndef STATUS_SEVERITY_INFORMATIONAL +# define STATUS_SEVERITY_INFORMATIONAL 0x1 +#endif + +#ifndef STATUS_SEVERITY_WARNING +# define STATUS_SEVERITY_WARNING 0x2 +#endif + +#ifndef STATUS_SEVERITY_ERROR +# define STATUS_SEVERITY_ERROR 0x3 +#endif + +#ifndef FACILITY_NTWIN32 +# define FACILITY_NTWIN32 0x7 +#endif + +#ifndef NT_SUCCESS +# define NT_SUCCESS(status) (((NTSTATUS) (status)) >= 0) +#endif + +#ifndef NT_INFORMATION +# define NT_INFORMATION(status) ((((ULONG) (status)) >> 30) == 1) +#endif + +#ifndef NT_WARNING +# define NT_WARNING(status) ((((ULONG) (status)) >> 30) == 2) +#endif + +#ifndef NT_ERROR +# define NT_ERROR(status) ((((ULONG) (status)) >> 30) == 3) +#endif + +#ifndef STATUS_SUCCESS +# define STATUS_SUCCESS ((NTSTATUS) 0x00000000L) +#endif + +#ifndef STATUS_WAIT_0 +# define STATUS_WAIT_0 ((NTSTATUS) 0x00000000L) +#endif + +#ifndef STATUS_WAIT_1 +# define STATUS_WAIT_1 ((NTSTATUS) 0x00000001L) +#endif + +#ifndef STATUS_WAIT_2 +# define STATUS_WAIT_2 ((NTSTATUS) 0x00000002L) +#endif + +#ifndef STATUS_WAIT_3 +# define STATUS_WAIT_3 ((NTSTATUS) 0x00000003L) +#endif + +#ifndef STATUS_WAIT_63 +# define STATUS_WAIT_63 ((NTSTATUS) 0x0000003FL) +#endif + +#ifndef STATUS_ABANDONED +# define STATUS_ABANDONED ((NTSTATUS) 0x00000080L) +#endif + +#ifndef STATUS_ABANDONED_WAIT_0 +# define STATUS_ABANDONED_WAIT_0 ((NTSTATUS) 0x00000080L) +#endif + +#ifndef STATUS_ABANDONED_WAIT_63 +# define STATUS_ABANDONED_WAIT_63 ((NTSTATUS) 0x000000BFL) +#endif + +#ifndef STATUS_USER_APC +# define STATUS_USER_APC ((NTSTATUS) 0x000000C0L) +#endif + +#ifndef STATUS_KERNEL_APC +# define STATUS_KERNEL_APC ((NTSTATUS) 0x00000100L) +#endif + +#ifndef STATUS_ALERTED +# define STATUS_ALERTED ((NTSTATUS) 0x00000101L) +#endif + +#ifndef STATUS_TIMEOUT +# define STATUS_TIMEOUT ((NTSTATUS) 0x00000102L) +#endif + +#ifndef STATUS_PENDING +# define STATUS_PENDING ((NTSTATUS) 0x00000103L) +#endif + +#ifndef STATUS_REPARSE +# define STATUS_REPARSE ((NTSTATUS) 0x00000104L) +#endif + +#ifndef STATUS_MORE_ENTRIES +# define STATUS_MORE_ENTRIES ((NTSTATUS) 0x00000105L) +#endif + +#ifndef STATUS_NOT_ALL_ASSIGNED +# define STATUS_NOT_ALL_ASSIGNED ((NTSTATUS) 0x00000106L) +#endif + +#ifndef STATUS_SOME_NOT_MAPPED +# define STATUS_SOME_NOT_MAPPED ((NTSTATUS) 0x00000107L) +#endif + +#ifndef STATUS_OPLOCK_BREAK_IN_PROGRESS +# define STATUS_OPLOCK_BREAK_IN_PROGRESS ((NTSTATUS) 0x00000108L) +#endif + +#ifndef STATUS_VOLUME_MOUNTED +# define STATUS_VOLUME_MOUNTED ((NTSTATUS) 0x00000109L) +#endif + +#ifndef STATUS_RXACT_COMMITTED +# define STATUS_RXACT_COMMITTED ((NTSTATUS) 0x0000010AL) +#endif + +#ifndef STATUS_NOTIFY_CLEANUP +# define STATUS_NOTIFY_CLEANUP ((NTSTATUS) 0x0000010BL) +#endif + +#ifndef STATUS_NOTIFY_ENUM_DIR +# define STATUS_NOTIFY_ENUM_DIR ((NTSTATUS) 0x0000010CL) +#endif + +#ifndef STATUS_NO_QUOTAS_FOR_ACCOUNT +# define STATUS_NO_QUOTAS_FOR_ACCOUNT ((NTSTATUS) 0x0000010DL) +#endif + +#ifndef STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED +# define STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED ((NTSTATUS) 0x0000010EL) +#endif + +#ifndef STATUS_PAGE_FAULT_TRANSITION +# define STATUS_PAGE_FAULT_TRANSITION ((NTSTATUS) 0x00000110L) +#endif + +#ifndef STATUS_PAGE_FAULT_DEMAND_ZERO +# define STATUS_PAGE_FAULT_DEMAND_ZERO ((NTSTATUS) 0x00000111L) +#endif + +#ifndef STATUS_PAGE_FAULT_COPY_ON_WRITE +# define STATUS_PAGE_FAULT_COPY_ON_WRITE ((NTSTATUS) 0x00000112L) +#endif + +#ifndef STATUS_PAGE_FAULT_GUARD_PAGE +# define STATUS_PAGE_FAULT_GUARD_PAGE ((NTSTATUS) 0x00000113L) +#endif + +#ifndef STATUS_PAGE_FAULT_PAGING_FILE +# define STATUS_PAGE_FAULT_PAGING_FILE ((NTSTATUS) 0x00000114L) +#endif + +#ifndef STATUS_CACHE_PAGE_LOCKED +# define STATUS_CACHE_PAGE_LOCKED ((NTSTATUS) 0x00000115L) +#endif + +#ifndef STATUS_CRASH_DUMP +# define STATUS_CRASH_DUMP ((NTSTATUS) 0x00000116L) +#endif + +#ifndef STATUS_BUFFER_ALL_ZEROS +# define STATUS_BUFFER_ALL_ZEROS ((NTSTATUS) 0x00000117L) +#endif + +#ifndef STATUS_REPARSE_OBJECT +# define STATUS_REPARSE_OBJECT ((NTSTATUS) 0x00000118L) +#endif + +#ifndef STATUS_RESOURCE_REQUIREMENTS_CHANGED +# define STATUS_RESOURCE_REQUIREMENTS_CHANGED ((NTSTATUS) 0x00000119L) +#endif + +#ifndef STATUS_TRANSLATION_COMPLETE +# define STATUS_TRANSLATION_COMPLETE ((NTSTATUS) 0x00000120L) +#endif + +#ifndef STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY +# define STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY ((NTSTATUS) 0x00000121L) +#endif + +#ifndef STATUS_NOTHING_TO_TERMINATE +# define STATUS_NOTHING_TO_TERMINATE ((NTSTATUS) 0x00000122L) +#endif + +#ifndef STATUS_PROCESS_NOT_IN_JOB +# define STATUS_PROCESS_NOT_IN_JOB ((NTSTATUS) 0x00000123L) +#endif + +#ifndef STATUS_PROCESS_IN_JOB +# define STATUS_PROCESS_IN_JOB ((NTSTATUS) 0x00000124L) +#endif + +#ifndef STATUS_VOLSNAP_HIBERNATE_READY +# define STATUS_VOLSNAP_HIBERNATE_READY ((NTSTATUS) 0x00000125L) +#endif + +#ifndef STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY +# define STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY ((NTSTATUS) 0x00000126L) +#endif + +#ifndef STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED +# define STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED ((NTSTATUS) 0x00000127L) +#endif + +#ifndef STATUS_INTERRUPT_STILL_CONNECTED +# define STATUS_INTERRUPT_STILL_CONNECTED ((NTSTATUS) 0x00000128L) +#endif + +#ifndef STATUS_PROCESS_CLONED +# define STATUS_PROCESS_CLONED ((NTSTATUS) 0x00000129L) +#endif + +#ifndef STATUS_FILE_LOCKED_WITH_ONLY_READERS +# define STATUS_FILE_LOCKED_WITH_ONLY_READERS ((NTSTATUS) 0x0000012AL) +#endif + +#ifndef STATUS_FILE_LOCKED_WITH_WRITERS +# define STATUS_FILE_LOCKED_WITH_WRITERS ((NTSTATUS) 0x0000012BL) +#endif + +#ifndef STATUS_RESOURCEMANAGER_READ_ONLY +# define STATUS_RESOURCEMANAGER_READ_ONLY ((NTSTATUS) 0x00000202L) +#endif + +#ifndef STATUS_RING_PREVIOUSLY_EMPTY +# define STATUS_RING_PREVIOUSLY_EMPTY ((NTSTATUS) 0x00000210L) +#endif + +#ifndef STATUS_RING_PREVIOUSLY_FULL +# define STATUS_RING_PREVIOUSLY_FULL ((NTSTATUS) 0x00000211L) +#endif + +#ifndef STATUS_RING_PREVIOUSLY_ABOVE_QUOTA +# define STATUS_RING_PREVIOUSLY_ABOVE_QUOTA ((NTSTATUS) 0x00000212L) +#endif + +#ifndef STATUS_RING_NEWLY_EMPTY +# define STATUS_RING_NEWLY_EMPTY ((NTSTATUS) 0x00000213L) +#endif + +#ifndef STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT +# define STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT ((NTSTATUS) 0x00000214L) +#endif + +#ifndef STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE +# define STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE ((NTSTATUS) 0x00000215L) +#endif + +#ifndef STATUS_OPLOCK_HANDLE_CLOSED +# define STATUS_OPLOCK_HANDLE_CLOSED ((NTSTATUS) 0x00000216L) +#endif + +#ifndef STATUS_WAIT_FOR_OPLOCK +# define STATUS_WAIT_FOR_OPLOCK ((NTSTATUS) 0x00000367L) +#endif + +#ifndef STATUS_OBJECT_NAME_EXISTS +# define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS) 0x40000000L) +#endif + +#ifndef STATUS_THREAD_WAS_SUSPENDED +# define STATUS_THREAD_WAS_SUSPENDED ((NTSTATUS) 0x40000001L) +#endif + +#ifndef STATUS_WORKING_SET_LIMIT_RANGE +# define STATUS_WORKING_SET_LIMIT_RANGE ((NTSTATUS) 0x40000002L) +#endif + +#ifndef STATUS_IMAGE_NOT_AT_BASE +# define STATUS_IMAGE_NOT_AT_BASE ((NTSTATUS) 0x40000003L) +#endif + +#ifndef STATUS_RXACT_STATE_CREATED +# define STATUS_RXACT_STATE_CREATED ((NTSTATUS) 0x40000004L) +#endif + +#ifndef STATUS_SEGMENT_NOTIFICATION +# define STATUS_SEGMENT_NOTIFICATION ((NTSTATUS) 0x40000005L) +#endif + +#ifndef STATUS_LOCAL_USER_SESSION_KEY +# define STATUS_LOCAL_USER_SESSION_KEY ((NTSTATUS) 0x40000006L) +#endif + +#ifndef STATUS_BAD_CURRENT_DIRECTORY +# define STATUS_BAD_CURRENT_DIRECTORY ((NTSTATUS) 0x40000007L) +#endif + +#ifndef STATUS_SERIAL_MORE_WRITES +# define STATUS_SERIAL_MORE_WRITES ((NTSTATUS) 0x40000008L) +#endif + +#ifndef STATUS_REGISTRY_RECOVERED +# define STATUS_REGISTRY_RECOVERED ((NTSTATUS) 0x40000009L) +#endif + +#ifndef STATUS_FT_READ_RECOVERY_FROM_BACKUP +# define STATUS_FT_READ_RECOVERY_FROM_BACKUP ((NTSTATUS) 0x4000000AL) +#endif + +#ifndef STATUS_FT_WRITE_RECOVERY +# define STATUS_FT_WRITE_RECOVERY ((NTSTATUS) 0x4000000BL) +#endif + +#ifndef STATUS_SERIAL_COUNTER_TIMEOUT +# define STATUS_SERIAL_COUNTER_TIMEOUT ((NTSTATUS) 0x4000000CL) +#endif + +#ifndef STATUS_NULL_LM_PASSWORD +# define STATUS_NULL_LM_PASSWORD ((NTSTATUS) 0x4000000DL) +#endif + +#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH +# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH ((NTSTATUS) 0x4000000EL) +#endif + +#ifndef STATUS_RECEIVE_PARTIAL +# define STATUS_RECEIVE_PARTIAL ((NTSTATUS) 0x4000000FL) +#endif + +#ifndef STATUS_RECEIVE_EXPEDITED +# define STATUS_RECEIVE_EXPEDITED ((NTSTATUS) 0x40000010L) +#endif + +#ifndef STATUS_RECEIVE_PARTIAL_EXPEDITED +# define STATUS_RECEIVE_PARTIAL_EXPEDITED ((NTSTATUS) 0x40000011L) +#endif + +#ifndef STATUS_EVENT_DONE +# define STATUS_EVENT_DONE ((NTSTATUS) 0x40000012L) +#endif + +#ifndef STATUS_EVENT_PENDING +# define STATUS_EVENT_PENDING ((NTSTATUS) 0x40000013L) +#endif + +#ifndef STATUS_CHECKING_FILE_SYSTEM +# define STATUS_CHECKING_FILE_SYSTEM ((NTSTATUS) 0x40000014L) +#endif + +#ifndef STATUS_FATAL_APP_EXIT +# define STATUS_FATAL_APP_EXIT ((NTSTATUS) 0x40000015L) +#endif + +#ifndef STATUS_PREDEFINED_HANDLE +# define STATUS_PREDEFINED_HANDLE ((NTSTATUS) 0x40000016L) +#endif + +#ifndef STATUS_WAS_UNLOCKED +# define STATUS_WAS_UNLOCKED ((NTSTATUS) 0x40000017L) +#endif + +#ifndef STATUS_SERVICE_NOTIFICATION +# define STATUS_SERVICE_NOTIFICATION ((NTSTATUS) 0x40000018L) +#endif + +#ifndef STATUS_WAS_LOCKED +# define STATUS_WAS_LOCKED ((NTSTATUS) 0x40000019L) +#endif + +#ifndef STATUS_LOG_HARD_ERROR +# define STATUS_LOG_HARD_ERROR ((NTSTATUS) 0x4000001AL) +#endif + +#ifndef STATUS_ALREADY_WIN32 +# define STATUS_ALREADY_WIN32 ((NTSTATUS) 0x4000001BL) +#endif + +#ifndef STATUS_WX86_UNSIMULATE +# define STATUS_WX86_UNSIMULATE ((NTSTATUS) 0x4000001CL) +#endif + +#ifndef STATUS_WX86_CONTINUE +# define STATUS_WX86_CONTINUE ((NTSTATUS) 0x4000001DL) +#endif + +#ifndef STATUS_WX86_SINGLE_STEP +# define STATUS_WX86_SINGLE_STEP ((NTSTATUS) 0x4000001EL) +#endif + +#ifndef STATUS_WX86_BREAKPOINT +# define STATUS_WX86_BREAKPOINT ((NTSTATUS) 0x4000001FL) +#endif + +#ifndef STATUS_WX86_EXCEPTION_CONTINUE +# define STATUS_WX86_EXCEPTION_CONTINUE ((NTSTATUS) 0x40000020L) +#endif + +#ifndef STATUS_WX86_EXCEPTION_LASTCHANCE +# define STATUS_WX86_EXCEPTION_LASTCHANCE ((NTSTATUS) 0x40000021L) +#endif + +#ifndef STATUS_WX86_EXCEPTION_CHAIN +# define STATUS_WX86_EXCEPTION_CHAIN ((NTSTATUS) 0x40000022L) +#endif + +#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE +# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE ((NTSTATUS) 0x40000023L) +#endif + +#ifndef STATUS_NO_YIELD_PERFORMED +# define STATUS_NO_YIELD_PERFORMED ((NTSTATUS) 0x40000024L) +#endif + +#ifndef STATUS_TIMER_RESUME_IGNORED +# define STATUS_TIMER_RESUME_IGNORED ((NTSTATUS) 0x40000025L) +#endif + +#ifndef STATUS_ARBITRATION_UNHANDLED +# define STATUS_ARBITRATION_UNHANDLED ((NTSTATUS) 0x40000026L) +#endif + +#ifndef STATUS_CARDBUS_NOT_SUPPORTED +# define STATUS_CARDBUS_NOT_SUPPORTED ((NTSTATUS) 0x40000027L) +#endif + +#ifndef STATUS_WX86_CREATEWX86TIB +# define STATUS_WX86_CREATEWX86TIB ((NTSTATUS) 0x40000028L) +#endif + +#ifndef STATUS_MP_PROCESSOR_MISMATCH +# define STATUS_MP_PROCESSOR_MISMATCH ((NTSTATUS) 0x40000029L) +#endif + +#ifndef STATUS_HIBERNATED +# define STATUS_HIBERNATED ((NTSTATUS) 0x4000002AL) +#endif + +#ifndef STATUS_RESUME_HIBERNATION +# define STATUS_RESUME_HIBERNATION ((NTSTATUS) 0x4000002BL) +#endif + +#ifndef STATUS_FIRMWARE_UPDATED +# define STATUS_FIRMWARE_UPDATED ((NTSTATUS) 0x4000002CL) +#endif + +#ifndef STATUS_DRIVERS_LEAKING_LOCKED_PAGES +# define STATUS_DRIVERS_LEAKING_LOCKED_PAGES ((NTSTATUS) 0x4000002DL) +#endif + +#ifndef STATUS_MESSAGE_RETRIEVED +# define STATUS_MESSAGE_RETRIEVED ((NTSTATUS) 0x4000002EL) +#endif + +#ifndef STATUS_SYSTEM_POWERSTATE_TRANSITION +# define STATUS_SYSTEM_POWERSTATE_TRANSITION ((NTSTATUS) 0x4000002FL) +#endif + +#ifndef STATUS_ALPC_CHECK_COMPLETION_LIST +# define STATUS_ALPC_CHECK_COMPLETION_LIST ((NTSTATUS) 0x40000030L) +#endif + +#ifndef STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION +# define STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION ((NTSTATUS) 0x40000031L) +#endif + +#ifndef STATUS_ACCESS_AUDIT_BY_POLICY +# define STATUS_ACCESS_AUDIT_BY_POLICY ((NTSTATUS) 0x40000032L) +#endif + +#ifndef STATUS_ABANDON_HIBERFILE +# define STATUS_ABANDON_HIBERFILE ((NTSTATUS) 0x40000033L) +#endif + +#ifndef STATUS_BIZRULES_NOT_ENABLED +# define STATUS_BIZRULES_NOT_ENABLED ((NTSTATUS) 0x40000034L) +#endif + +#ifndef STATUS_GUARD_PAGE_VIOLATION +# define STATUS_GUARD_PAGE_VIOLATION ((NTSTATUS) 0x80000001L) +#endif + +#ifndef STATUS_DATATYPE_MISALIGNMENT +# define STATUS_DATATYPE_MISALIGNMENT ((NTSTATUS) 0x80000002L) +#endif + +#ifndef STATUS_BREAKPOINT +# define STATUS_BREAKPOINT ((NTSTATUS) 0x80000003L) +#endif + +#ifndef STATUS_SINGLE_STEP +# define STATUS_SINGLE_STEP ((NTSTATUS) 0x80000004L) +#endif + +#ifndef STATUS_BUFFER_OVERFLOW +# define STATUS_BUFFER_OVERFLOW ((NTSTATUS) 0x80000005L) +#endif + +#ifndef STATUS_NO_MORE_FILES +# define STATUS_NO_MORE_FILES ((NTSTATUS) 0x80000006L) +#endif + +#ifndef STATUS_WAKE_SYSTEM_DEBUGGER +# define STATUS_WAKE_SYSTEM_DEBUGGER ((NTSTATUS) 0x80000007L) +#endif + +#ifndef STATUS_HANDLES_CLOSED +# define STATUS_HANDLES_CLOSED ((NTSTATUS) 0x8000000AL) +#endif + +#ifndef STATUS_NO_INHERITANCE +# define STATUS_NO_INHERITANCE ((NTSTATUS) 0x8000000BL) +#endif + +#ifndef STATUS_GUID_SUBSTITUTION_MADE +# define STATUS_GUID_SUBSTITUTION_MADE ((NTSTATUS) 0x8000000CL) +#endif + +#ifndef STATUS_PARTIAL_COPY +# define STATUS_PARTIAL_COPY ((NTSTATUS) 0x8000000DL) +#endif + +#ifndef STATUS_DEVICE_PAPER_EMPTY +# define STATUS_DEVICE_PAPER_EMPTY ((NTSTATUS) 0x8000000EL) +#endif + +#ifndef STATUS_DEVICE_POWERED_OFF +# define STATUS_DEVICE_POWERED_OFF ((NTSTATUS) 0x8000000FL) +#endif + +#ifndef STATUS_DEVICE_OFF_LINE +# define STATUS_DEVICE_OFF_LINE ((NTSTATUS) 0x80000010L) +#endif + +#ifndef STATUS_DEVICE_BUSY +# define STATUS_DEVICE_BUSY ((NTSTATUS) 0x80000011L) +#endif + +#ifndef STATUS_NO_MORE_EAS +# define STATUS_NO_MORE_EAS ((NTSTATUS) 0x80000012L) +#endif + +#ifndef STATUS_INVALID_EA_NAME +# define STATUS_INVALID_EA_NAME ((NTSTATUS) 0x80000013L) +#endif + +#ifndef STATUS_EA_LIST_INCONSISTENT +# define STATUS_EA_LIST_INCONSISTENT ((NTSTATUS) 0x80000014L) +#endif + +#ifndef STATUS_INVALID_EA_FLAG +# define STATUS_INVALID_EA_FLAG ((NTSTATUS) 0x80000015L) +#endif + +#ifndef STATUS_VERIFY_REQUIRED +# define STATUS_VERIFY_REQUIRED ((NTSTATUS) 0x80000016L) +#endif + +#ifndef STATUS_EXTRANEOUS_INFORMATION +# define STATUS_EXTRANEOUS_INFORMATION ((NTSTATUS) 0x80000017L) +#endif + +#ifndef STATUS_RXACT_COMMIT_NECESSARY +# define STATUS_RXACT_COMMIT_NECESSARY ((NTSTATUS) 0x80000018L) +#endif + +#ifndef STATUS_NO_MORE_ENTRIES +# define STATUS_NO_MORE_ENTRIES ((NTSTATUS) 0x8000001AL) +#endif + +#ifndef STATUS_FILEMARK_DETECTED +# define STATUS_FILEMARK_DETECTED ((NTSTATUS) 0x8000001BL) +#endif + +#ifndef STATUS_MEDIA_CHANGED +# define STATUS_MEDIA_CHANGED ((NTSTATUS) 0x8000001CL) +#endif + +#ifndef STATUS_BUS_RESET +# define STATUS_BUS_RESET ((NTSTATUS) 0x8000001DL) +#endif + +#ifndef STATUS_END_OF_MEDIA +# define STATUS_END_OF_MEDIA ((NTSTATUS) 0x8000001EL) +#endif + +#ifndef STATUS_BEGINNING_OF_MEDIA +# define STATUS_BEGINNING_OF_MEDIA ((NTSTATUS) 0x8000001FL) +#endif + +#ifndef STATUS_MEDIA_CHECK +# define STATUS_MEDIA_CHECK ((NTSTATUS) 0x80000020L) +#endif + +#ifndef STATUS_SETMARK_DETECTED +# define STATUS_SETMARK_DETECTED ((NTSTATUS) 0x80000021L) +#endif + +#ifndef STATUS_NO_DATA_DETECTED +# define STATUS_NO_DATA_DETECTED ((NTSTATUS) 0x80000022L) +#endif + +#ifndef STATUS_REDIRECTOR_HAS_OPEN_HANDLES +# define STATUS_REDIRECTOR_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000023L) +#endif + +#ifndef STATUS_SERVER_HAS_OPEN_HANDLES +# define STATUS_SERVER_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000024L) +#endif + +#ifndef STATUS_ALREADY_DISCONNECTED +# define STATUS_ALREADY_DISCONNECTED ((NTSTATUS) 0x80000025L) +#endif + +#ifndef STATUS_LONGJUMP +# define STATUS_LONGJUMP ((NTSTATUS) 0x80000026L) +#endif + +#ifndef STATUS_CLEANER_CARTRIDGE_INSTALLED +# define STATUS_CLEANER_CARTRIDGE_INSTALLED ((NTSTATUS) 0x80000027L) +#endif + +#ifndef STATUS_PLUGPLAY_QUERY_VETOED +# define STATUS_PLUGPLAY_QUERY_VETOED ((NTSTATUS) 0x80000028L) +#endif + +#ifndef STATUS_UNWIND_CONSOLIDATE +# define STATUS_UNWIND_CONSOLIDATE ((NTSTATUS) 0x80000029L) +#endif + +#ifndef STATUS_REGISTRY_HIVE_RECOVERED +# define STATUS_REGISTRY_HIVE_RECOVERED ((NTSTATUS) 0x8000002AL) +#endif + +#ifndef STATUS_DLL_MIGHT_BE_INSECURE +# define STATUS_DLL_MIGHT_BE_INSECURE ((NTSTATUS) 0x8000002BL) +#endif + +#ifndef STATUS_DLL_MIGHT_BE_INCOMPATIBLE +# define STATUS_DLL_MIGHT_BE_INCOMPATIBLE ((NTSTATUS) 0x8000002CL) +#endif + +#ifndef STATUS_STOPPED_ON_SYMLINK +# define STATUS_STOPPED_ON_SYMLINK ((NTSTATUS) 0x8000002DL) +#endif + +#ifndef STATUS_CANNOT_GRANT_REQUESTED_OPLOCK +# define STATUS_CANNOT_GRANT_REQUESTED_OPLOCK ((NTSTATUS) 0x8000002EL) +#endif + +#ifndef STATUS_NO_ACE_CONDITION +# define STATUS_NO_ACE_CONDITION ((NTSTATUS) 0x8000002FL) +#endif + +#ifndef STATUS_UNSUCCESSFUL +# define STATUS_UNSUCCESSFUL ((NTSTATUS) 0xC0000001L) +#endif + +#ifndef STATUS_NOT_IMPLEMENTED +# define STATUS_NOT_IMPLEMENTED ((NTSTATUS) 0xC0000002L) +#endif + +#ifndef STATUS_INVALID_INFO_CLASS +# define STATUS_INVALID_INFO_CLASS ((NTSTATUS) 0xC0000003L) +#endif + +#ifndef STATUS_INFO_LENGTH_MISMATCH +# define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xC0000004L) +#endif + +#ifndef STATUS_ACCESS_VIOLATION +# define STATUS_ACCESS_VIOLATION ((NTSTATUS) 0xC0000005L) +#endif + +#ifndef STATUS_IN_PAGE_ERROR +# define STATUS_IN_PAGE_ERROR ((NTSTATUS) 0xC0000006L) +#endif + +#ifndef STATUS_PAGEFILE_QUOTA +# define STATUS_PAGEFILE_QUOTA ((NTSTATUS) 0xC0000007L) +#endif + +#ifndef STATUS_INVALID_HANDLE +# define STATUS_INVALID_HANDLE ((NTSTATUS) 0xC0000008L) +#endif + +#ifndef STATUS_BAD_INITIAL_STACK +# define STATUS_BAD_INITIAL_STACK ((NTSTATUS) 0xC0000009L) +#endif + +#ifndef STATUS_BAD_INITIAL_PC +# define STATUS_BAD_INITIAL_PC ((NTSTATUS) 0xC000000AL) +#endif + +#ifndef STATUS_INVALID_CID +# define STATUS_INVALID_CID ((NTSTATUS) 0xC000000BL) +#endif + +#ifndef STATUS_TIMER_NOT_CANCELED +# define STATUS_TIMER_NOT_CANCELED ((NTSTATUS) 0xC000000CL) +#endif + +#ifndef STATUS_INVALID_PARAMETER +# define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xC000000DL) +#endif + +#ifndef STATUS_NO_SUCH_DEVICE +# define STATUS_NO_SUCH_DEVICE ((NTSTATUS) 0xC000000EL) +#endif + +#ifndef STATUS_NO_SUCH_FILE +# define STATUS_NO_SUCH_FILE ((NTSTATUS) 0xC000000FL) +#endif + +#ifndef STATUS_INVALID_DEVICE_REQUEST +# define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS) 0xC0000010L) +#endif + +#ifndef STATUS_END_OF_FILE +# define STATUS_END_OF_FILE ((NTSTATUS) 0xC0000011L) +#endif + +#ifndef STATUS_WRONG_VOLUME +# define STATUS_WRONG_VOLUME ((NTSTATUS) 0xC0000012L) +#endif + +#ifndef STATUS_NO_MEDIA_IN_DEVICE +# define STATUS_NO_MEDIA_IN_DEVICE ((NTSTATUS) 0xC0000013L) +#endif + +#ifndef STATUS_UNRECOGNIZED_MEDIA +# define STATUS_UNRECOGNIZED_MEDIA ((NTSTATUS) 0xC0000014L) +#endif + +#ifndef STATUS_NONEXISTENT_SECTOR +# define STATUS_NONEXISTENT_SECTOR ((NTSTATUS) 0xC0000015L) +#endif + +#ifndef STATUS_MORE_PROCESSING_REQUIRED +# define STATUS_MORE_PROCESSING_REQUIRED ((NTSTATUS) 0xC0000016L) +#endif + +#ifndef STATUS_NO_MEMORY +# define STATUS_NO_MEMORY ((NTSTATUS) 0xC0000017L) +#endif + +#ifndef STATUS_CONFLICTING_ADDRESSES +# define STATUS_CONFLICTING_ADDRESSES ((NTSTATUS) 0xC0000018L) +#endif + +#ifndef STATUS_NOT_MAPPED_VIEW +# define STATUS_NOT_MAPPED_VIEW ((NTSTATUS) 0xC0000019L) +#endif + +#ifndef STATUS_UNABLE_TO_FREE_VM +# define STATUS_UNABLE_TO_FREE_VM ((NTSTATUS) 0xC000001AL) +#endif + +#ifndef STATUS_UNABLE_TO_DELETE_SECTION +# define STATUS_UNABLE_TO_DELETE_SECTION ((NTSTATUS) 0xC000001BL) +#endif + +#ifndef STATUS_INVALID_SYSTEM_SERVICE +# define STATUS_INVALID_SYSTEM_SERVICE ((NTSTATUS) 0xC000001CL) +#endif + +#ifndef STATUS_ILLEGAL_INSTRUCTION +# define STATUS_ILLEGAL_INSTRUCTION ((NTSTATUS) 0xC000001DL) +#endif + +#ifndef STATUS_INVALID_LOCK_SEQUENCE +# define STATUS_INVALID_LOCK_SEQUENCE ((NTSTATUS) 0xC000001EL) +#endif + +#ifndef STATUS_INVALID_VIEW_SIZE +# define STATUS_INVALID_VIEW_SIZE ((NTSTATUS) 0xC000001FL) +#endif + +#ifndef STATUS_INVALID_FILE_FOR_SECTION +# define STATUS_INVALID_FILE_FOR_SECTION ((NTSTATUS) 0xC0000020L) +#endif + +#ifndef STATUS_ALREADY_COMMITTED +# define STATUS_ALREADY_COMMITTED ((NTSTATUS) 0xC0000021L) +#endif + +#ifndef STATUS_ACCESS_DENIED +# define STATUS_ACCESS_DENIED ((NTSTATUS) 0xC0000022L) +#endif + +#ifndef STATUS_BUFFER_TOO_SMALL +# define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xC0000023L) +#endif + +#ifndef STATUS_OBJECT_TYPE_MISMATCH +# define STATUS_OBJECT_TYPE_MISMATCH ((NTSTATUS) 0xC0000024L) +#endif + +#ifndef STATUS_NONCONTINUABLE_EXCEPTION +# define STATUS_NONCONTINUABLE_EXCEPTION ((NTSTATUS) 0xC0000025L) +#endif + +#ifndef STATUS_INVALID_DISPOSITION +# define STATUS_INVALID_DISPOSITION ((NTSTATUS) 0xC0000026L) +#endif + +#ifndef STATUS_UNWIND +# define STATUS_UNWIND ((NTSTATUS) 0xC0000027L) +#endif + +#ifndef STATUS_BAD_STACK +# define STATUS_BAD_STACK ((NTSTATUS) 0xC0000028L) +#endif + +#ifndef STATUS_INVALID_UNWIND_TARGET +# define STATUS_INVALID_UNWIND_TARGET ((NTSTATUS) 0xC0000029L) +#endif + +#ifndef STATUS_NOT_LOCKED +# define STATUS_NOT_LOCKED ((NTSTATUS) 0xC000002AL) +#endif + +#ifndef STATUS_PARITY_ERROR +# define STATUS_PARITY_ERROR ((NTSTATUS) 0xC000002BL) +#endif + +#ifndef STATUS_UNABLE_TO_DECOMMIT_VM +# define STATUS_UNABLE_TO_DECOMMIT_VM ((NTSTATUS) 0xC000002CL) +#endif + +#ifndef STATUS_NOT_COMMITTED +# define STATUS_NOT_COMMITTED ((NTSTATUS) 0xC000002DL) +#endif + +#ifndef STATUS_INVALID_PORT_ATTRIBUTES +# define STATUS_INVALID_PORT_ATTRIBUTES ((NTSTATUS) 0xC000002EL) +#endif + +#ifndef STATUS_PORT_MESSAGE_TOO_LONG +# define STATUS_PORT_MESSAGE_TOO_LONG ((NTSTATUS) 0xC000002FL) +#endif + +#ifndef STATUS_INVALID_PARAMETER_MIX +# define STATUS_INVALID_PARAMETER_MIX ((NTSTATUS) 0xC0000030L) +#endif + +#ifndef STATUS_INVALID_QUOTA_LOWER +# define STATUS_INVALID_QUOTA_LOWER ((NTSTATUS) 0xC0000031L) +#endif + +#ifndef STATUS_DISK_CORRUPT_ERROR +# define STATUS_DISK_CORRUPT_ERROR ((NTSTATUS) 0xC0000032L) +#endif + +#ifndef STATUS_OBJECT_NAME_INVALID +# define STATUS_OBJECT_NAME_INVALID ((NTSTATUS) 0xC0000033L) +#endif + +#ifndef STATUS_OBJECT_NAME_NOT_FOUND +# define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xC0000034L) +#endif + +#ifndef STATUS_OBJECT_NAME_COLLISION +# define STATUS_OBJECT_NAME_COLLISION ((NTSTATUS) 0xC0000035L) +#endif + +#ifndef STATUS_PORT_DISCONNECTED +# define STATUS_PORT_DISCONNECTED ((NTSTATUS) 0xC0000037L) +#endif + +#ifndef STATUS_DEVICE_ALREADY_ATTACHED +# define STATUS_DEVICE_ALREADY_ATTACHED ((NTSTATUS) 0xC0000038L) +#endif + +#ifndef STATUS_OBJECT_PATH_INVALID +# define STATUS_OBJECT_PATH_INVALID ((NTSTATUS) 0xC0000039L) +#endif + +#ifndef STATUS_OBJECT_PATH_NOT_FOUND +# define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS) 0xC000003AL) +#endif + +#ifndef STATUS_OBJECT_PATH_SYNTAX_BAD +# define STATUS_OBJECT_PATH_SYNTAX_BAD ((NTSTATUS) 0xC000003BL) +#endif + +#ifndef STATUS_DATA_OVERRUN +# define STATUS_DATA_OVERRUN ((NTSTATUS) 0xC000003CL) +#endif + +#ifndef STATUS_DATA_LATE_ERROR +# define STATUS_DATA_LATE_ERROR ((NTSTATUS) 0xC000003DL) +#endif + +#ifndef STATUS_DATA_ERROR +# define STATUS_DATA_ERROR ((NTSTATUS) 0xC000003EL) +#endif + +#ifndef STATUS_CRC_ERROR +# define STATUS_CRC_ERROR ((NTSTATUS) 0xC000003FL) +#endif + +#ifndef STATUS_SECTION_TOO_BIG +# define STATUS_SECTION_TOO_BIG ((NTSTATUS) 0xC0000040L) +#endif + +#ifndef STATUS_PORT_CONNECTION_REFUSED +# define STATUS_PORT_CONNECTION_REFUSED ((NTSTATUS) 0xC0000041L) +#endif + +#ifndef STATUS_INVALID_PORT_HANDLE +# define STATUS_INVALID_PORT_HANDLE ((NTSTATUS) 0xC0000042L) +#endif + +#ifndef STATUS_SHARING_VIOLATION +# define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xC0000043L) +#endif + +#ifndef STATUS_QUOTA_EXCEEDED +# define STATUS_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000044L) +#endif + +#ifndef STATUS_INVALID_PAGE_PROTECTION +# define STATUS_INVALID_PAGE_PROTECTION ((NTSTATUS) 0xC0000045L) +#endif + +#ifndef STATUS_MUTANT_NOT_OWNED +# define STATUS_MUTANT_NOT_OWNED ((NTSTATUS) 0xC0000046L) +#endif + +#ifndef STATUS_SEMAPHORE_LIMIT_EXCEEDED +# define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000047L) +#endif + +#ifndef STATUS_PORT_ALREADY_SET +# define STATUS_PORT_ALREADY_SET ((NTSTATUS) 0xC0000048L) +#endif + +#ifndef STATUS_SECTION_NOT_IMAGE +# define STATUS_SECTION_NOT_IMAGE ((NTSTATUS) 0xC0000049L) +#endif + +#ifndef STATUS_SUSPEND_COUNT_EXCEEDED +# define STATUS_SUSPEND_COUNT_EXCEEDED ((NTSTATUS) 0xC000004AL) +#endif + +#ifndef STATUS_THREAD_IS_TERMINATING +# define STATUS_THREAD_IS_TERMINATING ((NTSTATUS) 0xC000004BL) +#endif + +#ifndef STATUS_BAD_WORKING_SET_LIMIT +# define STATUS_BAD_WORKING_SET_LIMIT ((NTSTATUS) 0xC000004CL) +#endif + +#ifndef STATUS_INCOMPATIBLE_FILE_MAP +# define STATUS_INCOMPATIBLE_FILE_MAP ((NTSTATUS) 0xC000004DL) +#endif + +#ifndef STATUS_SECTION_PROTECTION +# define STATUS_SECTION_PROTECTION ((NTSTATUS) 0xC000004EL) +#endif + +#ifndef STATUS_EAS_NOT_SUPPORTED +# define STATUS_EAS_NOT_SUPPORTED ((NTSTATUS) 0xC000004FL) +#endif + +#ifndef STATUS_EA_TOO_LARGE +# define STATUS_EA_TOO_LARGE ((NTSTATUS) 0xC0000050L) +#endif + +#ifndef STATUS_NONEXISTENT_EA_ENTRY +# define STATUS_NONEXISTENT_EA_ENTRY ((NTSTATUS) 0xC0000051L) +#endif + +#ifndef STATUS_NO_EAS_ON_FILE +# define STATUS_NO_EAS_ON_FILE ((NTSTATUS) 0xC0000052L) +#endif + +#ifndef STATUS_EA_CORRUPT_ERROR +# define STATUS_EA_CORRUPT_ERROR ((NTSTATUS) 0xC0000053L) +#endif + +#ifndef STATUS_FILE_LOCK_CONFLICT +# define STATUS_FILE_LOCK_CONFLICT ((NTSTATUS) 0xC0000054L) +#endif + +#ifndef STATUS_LOCK_NOT_GRANTED +# define STATUS_LOCK_NOT_GRANTED ((NTSTATUS) 0xC0000055L) +#endif + +#ifndef STATUS_DELETE_PENDING +# define STATUS_DELETE_PENDING ((NTSTATUS) 0xC0000056L) +#endif + +#ifndef STATUS_CTL_FILE_NOT_SUPPORTED +# define STATUS_CTL_FILE_NOT_SUPPORTED ((NTSTATUS) 0xC0000057L) +#endif + +#ifndef STATUS_UNKNOWN_REVISION +# define STATUS_UNKNOWN_REVISION ((NTSTATUS) 0xC0000058L) +#endif + +#ifndef STATUS_REVISION_MISMATCH +# define STATUS_REVISION_MISMATCH ((NTSTATUS) 0xC0000059L) +#endif + +#ifndef STATUS_INVALID_OWNER +# define STATUS_INVALID_OWNER ((NTSTATUS) 0xC000005AL) +#endif + +#ifndef STATUS_INVALID_PRIMARY_GROUP +# define STATUS_INVALID_PRIMARY_GROUP ((NTSTATUS) 0xC000005BL) +#endif + +#ifndef STATUS_NO_IMPERSONATION_TOKEN +# define STATUS_NO_IMPERSONATION_TOKEN ((NTSTATUS) 0xC000005CL) +#endif + +#ifndef STATUS_CANT_DISABLE_MANDATORY +# define STATUS_CANT_DISABLE_MANDATORY ((NTSTATUS) 0xC000005DL) +#endif + +#ifndef STATUS_NO_LOGON_SERVERS +# define STATUS_NO_LOGON_SERVERS ((NTSTATUS) 0xC000005EL) +#endif + +#ifndef STATUS_NO_SUCH_LOGON_SESSION +# define STATUS_NO_SUCH_LOGON_SESSION ((NTSTATUS) 0xC000005FL) +#endif + +#ifndef STATUS_NO_SUCH_PRIVILEGE +# define STATUS_NO_SUCH_PRIVILEGE ((NTSTATUS) 0xC0000060L) +#endif + +#ifndef STATUS_PRIVILEGE_NOT_HELD +# define STATUS_PRIVILEGE_NOT_HELD ((NTSTATUS) 0xC0000061L) +#endif + +#ifndef STATUS_INVALID_ACCOUNT_NAME +# define STATUS_INVALID_ACCOUNT_NAME ((NTSTATUS) 0xC0000062L) +#endif + +#ifndef STATUS_USER_EXISTS +# define STATUS_USER_EXISTS ((NTSTATUS) 0xC0000063L) +#endif + +#ifndef STATUS_NO_SUCH_USER +# define STATUS_NO_SUCH_USER ((NTSTATUS) 0xC0000064L) +#endif + +#ifndef STATUS_GROUP_EXISTS +# define STATUS_GROUP_EXISTS ((NTSTATUS) 0xC0000065L) +#endif + +#ifndef STATUS_NO_SUCH_GROUP +# define STATUS_NO_SUCH_GROUP ((NTSTATUS) 0xC0000066L) +#endif + +#ifndef STATUS_MEMBER_IN_GROUP +# define STATUS_MEMBER_IN_GROUP ((NTSTATUS) 0xC0000067L) +#endif + +#ifndef STATUS_MEMBER_NOT_IN_GROUP +# define STATUS_MEMBER_NOT_IN_GROUP ((NTSTATUS) 0xC0000068L) +#endif + +#ifndef STATUS_LAST_ADMIN +# define STATUS_LAST_ADMIN ((NTSTATUS) 0xC0000069L) +#endif + +#ifndef STATUS_WRONG_PASSWORD +# define STATUS_WRONG_PASSWORD ((NTSTATUS) 0xC000006AL) +#endif + +#ifndef STATUS_ILL_FORMED_PASSWORD +# define STATUS_ILL_FORMED_PASSWORD ((NTSTATUS) 0xC000006BL) +#endif + +#ifndef STATUS_PASSWORD_RESTRICTION +# define STATUS_PASSWORD_RESTRICTION ((NTSTATUS) 0xC000006CL) +#endif + +#ifndef STATUS_LOGON_FAILURE +# define STATUS_LOGON_FAILURE ((NTSTATUS) 0xC000006DL) +#endif + +#ifndef STATUS_ACCOUNT_RESTRICTION +# define STATUS_ACCOUNT_RESTRICTION ((NTSTATUS) 0xC000006EL) +#endif + +#ifndef STATUS_INVALID_LOGON_HOURS +# define STATUS_INVALID_LOGON_HOURS ((NTSTATUS) 0xC000006FL) +#endif + +#ifndef STATUS_INVALID_WORKSTATION +# define STATUS_INVALID_WORKSTATION ((NTSTATUS) 0xC0000070L) +#endif + +#ifndef STATUS_PASSWORD_EXPIRED +# define STATUS_PASSWORD_EXPIRED ((NTSTATUS) 0xC0000071L) +#endif + +#ifndef STATUS_ACCOUNT_DISABLED +# define STATUS_ACCOUNT_DISABLED ((NTSTATUS) 0xC0000072L) +#endif + +#ifndef STATUS_NONE_MAPPED +# define STATUS_NONE_MAPPED ((NTSTATUS) 0xC0000073L) +#endif + +#ifndef STATUS_TOO_MANY_LUIDS_REQUESTED +# define STATUS_TOO_MANY_LUIDS_REQUESTED ((NTSTATUS) 0xC0000074L) +#endif + +#ifndef STATUS_LUIDS_EXHAUSTED +# define STATUS_LUIDS_EXHAUSTED ((NTSTATUS) 0xC0000075L) +#endif + +#ifndef STATUS_INVALID_SUB_AUTHORITY +# define STATUS_INVALID_SUB_AUTHORITY ((NTSTATUS) 0xC0000076L) +#endif + +#ifndef STATUS_INVALID_ACL +# define STATUS_INVALID_ACL ((NTSTATUS) 0xC0000077L) +#endif + +#ifndef STATUS_INVALID_SID +# define STATUS_INVALID_SID ((NTSTATUS) 0xC0000078L) +#endif + +#ifndef STATUS_INVALID_SECURITY_DESCR +# define STATUS_INVALID_SECURITY_DESCR ((NTSTATUS) 0xC0000079L) +#endif + +#ifndef STATUS_PROCEDURE_NOT_FOUND +# define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS) 0xC000007AL) +#endif + +#ifndef STATUS_INVALID_IMAGE_FORMAT +# define STATUS_INVALID_IMAGE_FORMAT ((NTSTATUS) 0xC000007BL) +#endif + +#ifndef STATUS_NO_TOKEN +# define STATUS_NO_TOKEN ((NTSTATUS) 0xC000007CL) +#endif + +#ifndef STATUS_BAD_INHERITANCE_ACL +# define STATUS_BAD_INHERITANCE_ACL ((NTSTATUS) 0xC000007DL) +#endif + +#ifndef STATUS_RANGE_NOT_LOCKED +# define STATUS_RANGE_NOT_LOCKED ((NTSTATUS) 0xC000007EL) +#endif + +#ifndef STATUS_DISK_FULL +# define STATUS_DISK_FULL ((NTSTATUS) 0xC000007FL) +#endif + +#ifndef STATUS_SERVER_DISABLED +# define STATUS_SERVER_DISABLED ((NTSTATUS) 0xC0000080L) +#endif + +#ifndef STATUS_SERVER_NOT_DISABLED +# define STATUS_SERVER_NOT_DISABLED ((NTSTATUS) 0xC0000081L) +#endif + +#ifndef STATUS_TOO_MANY_GUIDS_REQUESTED +# define STATUS_TOO_MANY_GUIDS_REQUESTED ((NTSTATUS) 0xC0000082L) +#endif + +#ifndef STATUS_GUIDS_EXHAUSTED +# define STATUS_GUIDS_EXHAUSTED ((NTSTATUS) 0xC0000083L) +#endif + +#ifndef STATUS_INVALID_ID_AUTHORITY +# define STATUS_INVALID_ID_AUTHORITY ((NTSTATUS) 0xC0000084L) +#endif + +#ifndef STATUS_AGENTS_EXHAUSTED +# define STATUS_AGENTS_EXHAUSTED ((NTSTATUS) 0xC0000085L) +#endif + +#ifndef STATUS_INVALID_VOLUME_LABEL +# define STATUS_INVALID_VOLUME_LABEL ((NTSTATUS) 0xC0000086L) +#endif + +#ifndef STATUS_SECTION_NOT_EXTENDED +# define STATUS_SECTION_NOT_EXTENDED ((NTSTATUS) 0xC0000087L) +#endif + +#ifndef STATUS_NOT_MAPPED_DATA +# define STATUS_NOT_MAPPED_DATA ((NTSTATUS) 0xC0000088L) +#endif + +#ifndef STATUS_RESOURCE_DATA_NOT_FOUND +# define STATUS_RESOURCE_DATA_NOT_FOUND ((NTSTATUS) 0xC0000089L) +#endif + +#ifndef STATUS_RESOURCE_TYPE_NOT_FOUND +# define STATUS_RESOURCE_TYPE_NOT_FOUND ((NTSTATUS) 0xC000008AL) +#endif + +#ifndef STATUS_RESOURCE_NAME_NOT_FOUND +# define STATUS_RESOURCE_NAME_NOT_FOUND ((NTSTATUS) 0xC000008BL) +#endif + +#ifndef STATUS_ARRAY_BOUNDS_EXCEEDED +# define STATUS_ARRAY_BOUNDS_EXCEEDED ((NTSTATUS) 0xC000008CL) +#endif + +#ifndef STATUS_FLOAT_DENORMAL_OPERAND +# define STATUS_FLOAT_DENORMAL_OPERAND ((NTSTATUS) 0xC000008DL) +#endif + +#ifndef STATUS_FLOAT_DIVIDE_BY_ZERO +# define STATUS_FLOAT_DIVIDE_BY_ZERO ((NTSTATUS) 0xC000008EL) +#endif + +#ifndef STATUS_FLOAT_INEXACT_RESULT +# define STATUS_FLOAT_INEXACT_RESULT ((NTSTATUS) 0xC000008FL) +#endif + +#ifndef STATUS_FLOAT_INVALID_OPERATION +# define STATUS_FLOAT_INVALID_OPERATION ((NTSTATUS) 0xC0000090L) +#endif + +#ifndef STATUS_FLOAT_OVERFLOW +# define STATUS_FLOAT_OVERFLOW ((NTSTATUS) 0xC0000091L) +#endif + +#ifndef STATUS_FLOAT_STACK_CHECK +# define STATUS_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000092L) +#endif + +#ifndef STATUS_FLOAT_UNDERFLOW +# define STATUS_FLOAT_UNDERFLOW ((NTSTATUS) 0xC0000093L) +#endif + +#ifndef STATUS_INTEGER_DIVIDE_BY_ZERO +# define STATUS_INTEGER_DIVIDE_BY_ZERO ((NTSTATUS) 0xC0000094L) +#endif + +#ifndef STATUS_INTEGER_OVERFLOW +# define STATUS_INTEGER_OVERFLOW ((NTSTATUS) 0xC0000095L) +#endif + +#ifndef STATUS_PRIVILEGED_INSTRUCTION +# define STATUS_PRIVILEGED_INSTRUCTION ((NTSTATUS) 0xC0000096L) +#endif + +#ifndef STATUS_TOO_MANY_PAGING_FILES +# define STATUS_TOO_MANY_PAGING_FILES ((NTSTATUS) 0xC0000097L) +#endif + +#ifndef STATUS_FILE_INVALID +# define STATUS_FILE_INVALID ((NTSTATUS) 0xC0000098L) +#endif + +#ifndef STATUS_ALLOTTED_SPACE_EXCEEDED +# define STATUS_ALLOTTED_SPACE_EXCEEDED ((NTSTATUS) 0xC0000099L) +#endif + +#ifndef STATUS_INSUFFICIENT_RESOURCES +# define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS) 0xC000009AL) +#endif + +#ifndef STATUS_DFS_EXIT_PATH_FOUND +# define STATUS_DFS_EXIT_PATH_FOUND ((NTSTATUS) 0xC000009BL) +#endif + +#ifndef STATUS_DEVICE_DATA_ERROR +# define STATUS_DEVICE_DATA_ERROR ((NTSTATUS) 0xC000009CL) +#endif + +#ifndef STATUS_DEVICE_NOT_CONNECTED +# define STATUS_DEVICE_NOT_CONNECTED ((NTSTATUS) 0xC000009DL) +#endif + +#ifndef STATUS_DEVICE_POWER_FAILURE +# define STATUS_DEVICE_POWER_FAILURE ((NTSTATUS) 0xC000009EL) +#endif + +#ifndef STATUS_FREE_VM_NOT_AT_BASE +# define STATUS_FREE_VM_NOT_AT_BASE ((NTSTATUS) 0xC000009FL) +#endif + +#ifndef STATUS_MEMORY_NOT_ALLOCATED +# define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS) 0xC00000A0L) +#endif + +#ifndef STATUS_WORKING_SET_QUOTA +# define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xC00000A1L) +#endif + +#ifndef STATUS_MEDIA_WRITE_PROTECTED +# define STATUS_MEDIA_WRITE_PROTECTED ((NTSTATUS) 0xC00000A2L) +#endif + +#ifndef STATUS_DEVICE_NOT_READY +# define STATUS_DEVICE_NOT_READY ((NTSTATUS) 0xC00000A3L) +#endif + +#ifndef STATUS_INVALID_GROUP_ATTRIBUTES +# define STATUS_INVALID_GROUP_ATTRIBUTES ((NTSTATUS) 0xC00000A4L) +#endif + +#ifndef STATUS_BAD_IMPERSONATION_LEVEL +# define STATUS_BAD_IMPERSONATION_LEVEL ((NTSTATUS) 0xC00000A5L) +#endif + +#ifndef STATUS_CANT_OPEN_ANONYMOUS +# define STATUS_CANT_OPEN_ANONYMOUS ((NTSTATUS) 0xC00000A6L) +#endif + +#ifndef STATUS_BAD_VALIDATION_CLASS +# define STATUS_BAD_VALIDATION_CLASS ((NTSTATUS) 0xC00000A7L) +#endif + +#ifndef STATUS_BAD_TOKEN_TYPE +# define STATUS_BAD_TOKEN_TYPE ((NTSTATUS) 0xC00000A8L) +#endif + +#ifndef STATUS_BAD_MASTER_BOOT_RECORD +# define STATUS_BAD_MASTER_BOOT_RECORD ((NTSTATUS) 0xC00000A9L) +#endif + +#ifndef STATUS_INSTRUCTION_MISALIGNMENT +# define STATUS_INSTRUCTION_MISALIGNMENT ((NTSTATUS) 0xC00000AAL) +#endif + +#ifndef STATUS_INSTANCE_NOT_AVAILABLE +# define STATUS_INSTANCE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ABL) +#endif + +#ifndef STATUS_PIPE_NOT_AVAILABLE +# define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ACL) +#endif + +#ifndef STATUS_INVALID_PIPE_STATE +# define STATUS_INVALID_PIPE_STATE ((NTSTATUS) 0xC00000ADL) +#endif + +#ifndef STATUS_PIPE_BUSY +# define STATUS_PIPE_BUSY ((NTSTATUS) 0xC00000AEL) +#endif + +#ifndef STATUS_ILLEGAL_FUNCTION +# define STATUS_ILLEGAL_FUNCTION ((NTSTATUS) 0xC00000AFL) +#endif + +#ifndef STATUS_PIPE_DISCONNECTED +# define STATUS_PIPE_DISCONNECTED ((NTSTATUS) 0xC00000B0L) +#endif + +#ifndef STATUS_PIPE_CLOSING +# define STATUS_PIPE_CLOSING ((NTSTATUS) 0xC00000B1L) +#endif + +#ifndef STATUS_PIPE_CONNECTED +# define STATUS_PIPE_CONNECTED ((NTSTATUS) 0xC00000B2L) +#endif + +#ifndef STATUS_PIPE_LISTENING +# define STATUS_PIPE_LISTENING ((NTSTATUS) 0xC00000B3L) +#endif + +#ifndef STATUS_INVALID_READ_MODE +# define STATUS_INVALID_READ_MODE ((NTSTATUS) 0xC00000B4L) +#endif + +#ifndef STATUS_IO_TIMEOUT +# define STATUS_IO_TIMEOUT ((NTSTATUS) 0xC00000B5L) +#endif + +#ifndef STATUS_FILE_FORCED_CLOSED +# define STATUS_FILE_FORCED_CLOSED ((NTSTATUS) 0xC00000B6L) +#endif + +#ifndef STATUS_PROFILING_NOT_STARTED +# define STATUS_PROFILING_NOT_STARTED ((NTSTATUS) 0xC00000B7L) +#endif + +#ifndef STATUS_PROFILING_NOT_STOPPED +# define STATUS_PROFILING_NOT_STOPPED ((NTSTATUS) 0xC00000B8L) +#endif + +#ifndef STATUS_COULD_NOT_INTERPRET +# define STATUS_COULD_NOT_INTERPRET ((NTSTATUS) 0xC00000B9L) +#endif + +#ifndef STATUS_FILE_IS_A_DIRECTORY +# define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS) 0xC00000BAL) +#endif + +#ifndef STATUS_NOT_SUPPORTED +# define STATUS_NOT_SUPPORTED ((NTSTATUS) 0xC00000BBL) +#endif + +#ifndef STATUS_REMOTE_NOT_LISTENING +# define STATUS_REMOTE_NOT_LISTENING ((NTSTATUS) 0xC00000BCL) +#endif + +#ifndef STATUS_DUPLICATE_NAME +# define STATUS_DUPLICATE_NAME ((NTSTATUS) 0xC00000BDL) +#endif + +#ifndef STATUS_BAD_NETWORK_PATH +# define STATUS_BAD_NETWORK_PATH ((NTSTATUS) 0xC00000BEL) +#endif + +#ifndef STATUS_NETWORK_BUSY +# define STATUS_NETWORK_BUSY ((NTSTATUS) 0xC00000BFL) +#endif + +#ifndef STATUS_DEVICE_DOES_NOT_EXIST +# define STATUS_DEVICE_DOES_NOT_EXIST ((NTSTATUS) 0xC00000C0L) +#endif + +#ifndef STATUS_TOO_MANY_COMMANDS +# define STATUS_TOO_MANY_COMMANDS ((NTSTATUS) 0xC00000C1L) +#endif + +#ifndef STATUS_ADAPTER_HARDWARE_ERROR +# define STATUS_ADAPTER_HARDWARE_ERROR ((NTSTATUS) 0xC00000C2L) +#endif + +#ifndef STATUS_INVALID_NETWORK_RESPONSE +# define STATUS_INVALID_NETWORK_RESPONSE ((NTSTATUS) 0xC00000C3L) +#endif + +#ifndef STATUS_UNEXPECTED_NETWORK_ERROR +# define STATUS_UNEXPECTED_NETWORK_ERROR ((NTSTATUS) 0xC00000C4L) +#endif + +#ifndef STATUS_BAD_REMOTE_ADAPTER +# define STATUS_BAD_REMOTE_ADAPTER ((NTSTATUS) 0xC00000C5L) +#endif + +#ifndef STATUS_PRINT_QUEUE_FULL +# define STATUS_PRINT_QUEUE_FULL ((NTSTATUS) 0xC00000C6L) +#endif + +#ifndef STATUS_NO_SPOOL_SPACE +# define STATUS_NO_SPOOL_SPACE ((NTSTATUS) 0xC00000C7L) +#endif + +#ifndef STATUS_PRINT_CANCELLED +# define STATUS_PRINT_CANCELLED ((NTSTATUS) 0xC00000C8L) +#endif + +#ifndef STATUS_NETWORK_NAME_DELETED +# define STATUS_NETWORK_NAME_DELETED ((NTSTATUS) 0xC00000C9L) +#endif + +#ifndef STATUS_NETWORK_ACCESS_DENIED +# define STATUS_NETWORK_ACCESS_DENIED ((NTSTATUS) 0xC00000CAL) +#endif + +#ifndef STATUS_BAD_DEVICE_TYPE +# define STATUS_BAD_DEVICE_TYPE ((NTSTATUS) 0xC00000CBL) +#endif + +#ifndef STATUS_BAD_NETWORK_NAME +# define STATUS_BAD_NETWORK_NAME ((NTSTATUS) 0xC00000CCL) +#endif + +#ifndef STATUS_TOO_MANY_NAMES +# define STATUS_TOO_MANY_NAMES ((NTSTATUS) 0xC00000CDL) +#endif + +#ifndef STATUS_TOO_MANY_SESSIONS +# define STATUS_TOO_MANY_SESSIONS ((NTSTATUS) 0xC00000CEL) +#endif + +#ifndef STATUS_SHARING_PAUSED +# define STATUS_SHARING_PAUSED ((NTSTATUS) 0xC00000CFL) +#endif + +#ifndef STATUS_REQUEST_NOT_ACCEPTED +# define STATUS_REQUEST_NOT_ACCEPTED ((NTSTATUS) 0xC00000D0L) +#endif + +#ifndef STATUS_REDIRECTOR_PAUSED +# define STATUS_REDIRECTOR_PAUSED ((NTSTATUS) 0xC00000D1L) +#endif + +#ifndef STATUS_NET_WRITE_FAULT +# define STATUS_NET_WRITE_FAULT ((NTSTATUS) 0xC00000D2L) +#endif + +#ifndef STATUS_PROFILING_AT_LIMIT +# define STATUS_PROFILING_AT_LIMIT ((NTSTATUS) 0xC00000D3L) +#endif + +#ifndef STATUS_NOT_SAME_DEVICE +# define STATUS_NOT_SAME_DEVICE ((NTSTATUS) 0xC00000D4L) +#endif + +#ifndef STATUS_FILE_RENAMED +# define STATUS_FILE_RENAMED ((NTSTATUS) 0xC00000D5L) +#endif + +#ifndef STATUS_VIRTUAL_CIRCUIT_CLOSED +# define STATUS_VIRTUAL_CIRCUIT_CLOSED ((NTSTATUS) 0xC00000D6L) +#endif + +#ifndef STATUS_NO_SECURITY_ON_OBJECT +# define STATUS_NO_SECURITY_ON_OBJECT ((NTSTATUS) 0xC00000D7L) +#endif + +#ifndef STATUS_CANT_WAIT +# define STATUS_CANT_WAIT ((NTSTATUS) 0xC00000D8L) +#endif + +#ifndef STATUS_PIPE_EMPTY +# define STATUS_PIPE_EMPTY ((NTSTATUS) 0xC00000D9L) +#endif + +#ifndef STATUS_CANT_ACCESS_DOMAIN_INFO +# define STATUS_CANT_ACCESS_DOMAIN_INFO ((NTSTATUS) 0xC00000DAL) +#endif + +#ifndef STATUS_CANT_TERMINATE_SELF +# define STATUS_CANT_TERMINATE_SELF ((NTSTATUS) 0xC00000DBL) +#endif + +#ifndef STATUS_INVALID_SERVER_STATE +# define STATUS_INVALID_SERVER_STATE ((NTSTATUS) 0xC00000DCL) +#endif + +#ifndef STATUS_INVALID_DOMAIN_STATE +# define STATUS_INVALID_DOMAIN_STATE ((NTSTATUS) 0xC00000DDL) +#endif + +#ifndef STATUS_INVALID_DOMAIN_ROLE +# define STATUS_INVALID_DOMAIN_ROLE ((NTSTATUS) 0xC00000DEL) +#endif + +#ifndef STATUS_NO_SUCH_DOMAIN +# define STATUS_NO_SUCH_DOMAIN ((NTSTATUS) 0xC00000DFL) +#endif + +#ifndef STATUS_DOMAIN_EXISTS +# define STATUS_DOMAIN_EXISTS ((NTSTATUS) 0xC00000E0L) +#endif + +#ifndef STATUS_DOMAIN_LIMIT_EXCEEDED +# define STATUS_DOMAIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00000E1L) +#endif + +#ifndef STATUS_OPLOCK_NOT_GRANTED +# define STATUS_OPLOCK_NOT_GRANTED ((NTSTATUS) 0xC00000E2L) +#endif + +#ifndef STATUS_INVALID_OPLOCK_PROTOCOL +# define STATUS_INVALID_OPLOCK_PROTOCOL ((NTSTATUS) 0xC00000E3L) +#endif + +#ifndef STATUS_INTERNAL_DB_CORRUPTION +# define STATUS_INTERNAL_DB_CORRUPTION ((NTSTATUS) 0xC00000E4L) +#endif + +#ifndef STATUS_INTERNAL_ERROR +# define STATUS_INTERNAL_ERROR ((NTSTATUS) 0xC00000E5L) +#endif + +#ifndef STATUS_GENERIC_NOT_MAPPED +# define STATUS_GENERIC_NOT_MAPPED ((NTSTATUS) 0xC00000E6L) +#endif + +#ifndef STATUS_BAD_DESCRIPTOR_FORMAT +# define STATUS_BAD_DESCRIPTOR_FORMAT ((NTSTATUS) 0xC00000E7L) +#endif + +#ifndef STATUS_INVALID_USER_BUFFER +# define STATUS_INVALID_USER_BUFFER ((NTSTATUS) 0xC00000E8L) +#endif + +#ifndef STATUS_UNEXPECTED_IO_ERROR +# define STATUS_UNEXPECTED_IO_ERROR ((NTSTATUS) 0xC00000E9L) +#endif + +#ifndef STATUS_UNEXPECTED_MM_CREATE_ERR +# define STATUS_UNEXPECTED_MM_CREATE_ERR ((NTSTATUS) 0xC00000EAL) +#endif + +#ifndef STATUS_UNEXPECTED_MM_MAP_ERROR +# define STATUS_UNEXPECTED_MM_MAP_ERROR ((NTSTATUS) 0xC00000EBL) +#endif + +#ifndef STATUS_UNEXPECTED_MM_EXTEND_ERR +# define STATUS_UNEXPECTED_MM_EXTEND_ERR ((NTSTATUS) 0xC00000ECL) +#endif + +#ifndef STATUS_NOT_LOGON_PROCESS +# define STATUS_NOT_LOGON_PROCESS ((NTSTATUS) 0xC00000EDL) +#endif + +#ifndef STATUS_LOGON_SESSION_EXISTS +# define STATUS_LOGON_SESSION_EXISTS ((NTSTATUS) 0xC00000EEL) +#endif + +#ifndef STATUS_INVALID_PARAMETER_1 +# define STATUS_INVALID_PARAMETER_1 ((NTSTATUS) 0xC00000EFL) +#endif + +#ifndef STATUS_INVALID_PARAMETER_2 +# define STATUS_INVALID_PARAMETER_2 ((NTSTATUS) 0xC00000F0L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_3 +# define STATUS_INVALID_PARAMETER_3 ((NTSTATUS) 0xC00000F1L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_4 +# define STATUS_INVALID_PARAMETER_4 ((NTSTATUS) 0xC00000F2L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_5 +# define STATUS_INVALID_PARAMETER_5 ((NTSTATUS) 0xC00000F3L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_6 +# define STATUS_INVALID_PARAMETER_6 ((NTSTATUS) 0xC00000F4L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_7 +# define STATUS_INVALID_PARAMETER_7 ((NTSTATUS) 0xC00000F5L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_8 +# define STATUS_INVALID_PARAMETER_8 ((NTSTATUS) 0xC00000F6L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_9 +# define STATUS_INVALID_PARAMETER_9 ((NTSTATUS) 0xC00000F7L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_10 +# define STATUS_INVALID_PARAMETER_10 ((NTSTATUS) 0xC00000F8L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_11 +# define STATUS_INVALID_PARAMETER_11 ((NTSTATUS) 0xC00000F9L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_12 +# define STATUS_INVALID_PARAMETER_12 ((NTSTATUS) 0xC00000FAL) +#endif + +#ifndef STATUS_REDIRECTOR_NOT_STARTED +# define STATUS_REDIRECTOR_NOT_STARTED ((NTSTATUS) 0xC00000FBL) +#endif + +#ifndef STATUS_REDIRECTOR_STARTED +# define STATUS_REDIRECTOR_STARTED ((NTSTATUS) 0xC00000FCL) +#endif + +#ifndef STATUS_STACK_OVERFLOW +# define STATUS_STACK_OVERFLOW ((NTSTATUS) 0xC00000FDL) +#endif + +#ifndef STATUS_NO_SUCH_PACKAGE +# define STATUS_NO_SUCH_PACKAGE ((NTSTATUS) 0xC00000FEL) +#endif + +#ifndef STATUS_BAD_FUNCTION_TABLE +# define STATUS_BAD_FUNCTION_TABLE ((NTSTATUS) 0xC00000FFL) +#endif + +#ifndef STATUS_VARIABLE_NOT_FOUND +# define STATUS_VARIABLE_NOT_FOUND ((NTSTATUS) 0xC0000100L) +#endif + +#ifndef STATUS_DIRECTORY_NOT_EMPTY +# define STATUS_DIRECTORY_NOT_EMPTY ((NTSTATUS) 0xC0000101L) +#endif + +#ifndef STATUS_FILE_CORRUPT_ERROR +# define STATUS_FILE_CORRUPT_ERROR ((NTSTATUS) 0xC0000102L) +#endif + +#ifndef STATUS_NOT_A_DIRECTORY +# define STATUS_NOT_A_DIRECTORY ((NTSTATUS) 0xC0000103L) +#endif + +#ifndef STATUS_BAD_LOGON_SESSION_STATE +# define STATUS_BAD_LOGON_SESSION_STATE ((NTSTATUS) 0xC0000104L) +#endif + +#ifndef STATUS_LOGON_SESSION_COLLISION +# define STATUS_LOGON_SESSION_COLLISION ((NTSTATUS) 0xC0000105L) +#endif + +#ifndef STATUS_NAME_TOO_LONG +# define STATUS_NAME_TOO_LONG ((NTSTATUS) 0xC0000106L) +#endif + +#ifndef STATUS_FILES_OPEN +# define STATUS_FILES_OPEN ((NTSTATUS) 0xC0000107L) +#endif + +#ifndef STATUS_CONNECTION_IN_USE +# define STATUS_CONNECTION_IN_USE ((NTSTATUS) 0xC0000108L) +#endif + +#ifndef STATUS_MESSAGE_NOT_FOUND +# define STATUS_MESSAGE_NOT_FOUND ((NTSTATUS) 0xC0000109L) +#endif + +#ifndef STATUS_PROCESS_IS_TERMINATING +# define STATUS_PROCESS_IS_TERMINATING ((NTSTATUS) 0xC000010AL) +#endif + +#ifndef STATUS_INVALID_LOGON_TYPE +# define STATUS_INVALID_LOGON_TYPE ((NTSTATUS) 0xC000010BL) +#endif + +#ifndef STATUS_NO_GUID_TRANSLATION +# define STATUS_NO_GUID_TRANSLATION ((NTSTATUS) 0xC000010CL) +#endif + +#ifndef STATUS_CANNOT_IMPERSONATE +# define STATUS_CANNOT_IMPERSONATE ((NTSTATUS) 0xC000010DL) +#endif + +#ifndef STATUS_IMAGE_ALREADY_LOADED +# define STATUS_IMAGE_ALREADY_LOADED ((NTSTATUS) 0xC000010EL) +#endif + +#ifndef STATUS_ABIOS_NOT_PRESENT +# define STATUS_ABIOS_NOT_PRESENT ((NTSTATUS) 0xC000010FL) +#endif + +#ifndef STATUS_ABIOS_LID_NOT_EXIST +# define STATUS_ABIOS_LID_NOT_EXIST ((NTSTATUS) 0xC0000110L) +#endif + +#ifndef STATUS_ABIOS_LID_ALREADY_OWNED +# define STATUS_ABIOS_LID_ALREADY_OWNED ((NTSTATUS) 0xC0000111L) +#endif + +#ifndef STATUS_ABIOS_NOT_LID_OWNER +# define STATUS_ABIOS_NOT_LID_OWNER ((NTSTATUS) 0xC0000112L) +#endif + +#ifndef STATUS_ABIOS_INVALID_COMMAND +# define STATUS_ABIOS_INVALID_COMMAND ((NTSTATUS) 0xC0000113L) +#endif + +#ifndef STATUS_ABIOS_INVALID_LID +# define STATUS_ABIOS_INVALID_LID ((NTSTATUS) 0xC0000114L) +#endif + +#ifndef STATUS_ABIOS_SELECTOR_NOT_AVAILABLE +# define STATUS_ABIOS_SELECTOR_NOT_AVAILABLE ((NTSTATUS) 0xC0000115L) +#endif + +#ifndef STATUS_ABIOS_INVALID_SELECTOR +# define STATUS_ABIOS_INVALID_SELECTOR ((NTSTATUS) 0xC0000116L) +#endif + +#ifndef STATUS_NO_LDT +# define STATUS_NO_LDT ((NTSTATUS) 0xC0000117L) +#endif + +#ifndef STATUS_INVALID_LDT_SIZE +# define STATUS_INVALID_LDT_SIZE ((NTSTATUS) 0xC0000118L) +#endif + +#ifndef STATUS_INVALID_LDT_OFFSET +# define STATUS_INVALID_LDT_OFFSET ((NTSTATUS) 0xC0000119L) +#endif + +#ifndef STATUS_INVALID_LDT_DESCRIPTOR +# define STATUS_INVALID_LDT_DESCRIPTOR ((NTSTATUS) 0xC000011AL) +#endif + +#ifndef STATUS_INVALID_IMAGE_NE_FORMAT +# define STATUS_INVALID_IMAGE_NE_FORMAT ((NTSTATUS) 0xC000011BL) +#endif + +#ifndef STATUS_RXACT_INVALID_STATE +# define STATUS_RXACT_INVALID_STATE ((NTSTATUS) 0xC000011CL) +#endif + +#ifndef STATUS_RXACT_COMMIT_FAILURE +# define STATUS_RXACT_COMMIT_FAILURE ((NTSTATUS) 0xC000011DL) +#endif + +#ifndef STATUS_MAPPED_FILE_SIZE_ZERO +# define STATUS_MAPPED_FILE_SIZE_ZERO ((NTSTATUS) 0xC000011EL) +#endif + +#ifndef STATUS_TOO_MANY_OPENED_FILES +# define STATUS_TOO_MANY_OPENED_FILES ((NTSTATUS) 0xC000011FL) +#endif + +#ifndef STATUS_CANCELLED +# define STATUS_CANCELLED ((NTSTATUS) 0xC0000120L) +#endif + +#ifndef STATUS_CANNOT_DELETE +# define STATUS_CANNOT_DELETE ((NTSTATUS) 0xC0000121L) +#endif + +#ifndef STATUS_INVALID_COMPUTER_NAME +# define STATUS_INVALID_COMPUTER_NAME ((NTSTATUS) 0xC0000122L) +#endif + +#ifndef STATUS_FILE_DELETED +# define STATUS_FILE_DELETED ((NTSTATUS) 0xC0000123L) +#endif + +#ifndef STATUS_SPECIAL_ACCOUNT +# define STATUS_SPECIAL_ACCOUNT ((NTSTATUS) 0xC0000124L) +#endif + +#ifndef STATUS_SPECIAL_GROUP +# define STATUS_SPECIAL_GROUP ((NTSTATUS) 0xC0000125L) +#endif + +#ifndef STATUS_SPECIAL_USER +# define STATUS_SPECIAL_USER ((NTSTATUS) 0xC0000126L) +#endif + +#ifndef STATUS_MEMBERS_PRIMARY_GROUP +# define STATUS_MEMBERS_PRIMARY_GROUP ((NTSTATUS) 0xC0000127L) +#endif + +#ifndef STATUS_FILE_CLOSED +# define STATUS_FILE_CLOSED ((NTSTATUS) 0xC0000128L) +#endif + +#ifndef STATUS_TOO_MANY_THREADS +# define STATUS_TOO_MANY_THREADS ((NTSTATUS) 0xC0000129L) +#endif + +#ifndef STATUS_THREAD_NOT_IN_PROCESS +# define STATUS_THREAD_NOT_IN_PROCESS ((NTSTATUS) 0xC000012AL) +#endif + +#ifndef STATUS_TOKEN_ALREADY_IN_USE +# define STATUS_TOKEN_ALREADY_IN_USE ((NTSTATUS) 0xC000012BL) +#endif + +#ifndef STATUS_PAGEFILE_QUOTA_EXCEEDED +# define STATUS_PAGEFILE_QUOTA_EXCEEDED ((NTSTATUS) 0xC000012CL) +#endif + +#ifndef STATUS_COMMITMENT_LIMIT +# define STATUS_COMMITMENT_LIMIT ((NTSTATUS) 0xC000012DL) +#endif + +#ifndef STATUS_INVALID_IMAGE_LE_FORMAT +# define STATUS_INVALID_IMAGE_LE_FORMAT ((NTSTATUS) 0xC000012EL) +#endif + +#ifndef STATUS_INVALID_IMAGE_NOT_MZ +# define STATUS_INVALID_IMAGE_NOT_MZ ((NTSTATUS) 0xC000012FL) +#endif + +#ifndef STATUS_INVALID_IMAGE_PROTECT +# define STATUS_INVALID_IMAGE_PROTECT ((NTSTATUS) 0xC0000130L) +#endif + +#ifndef STATUS_INVALID_IMAGE_WIN_16 +# define STATUS_INVALID_IMAGE_WIN_16 ((NTSTATUS) 0xC0000131L) +#endif + +#ifndef STATUS_LOGON_SERVER_CONFLICT +# define STATUS_LOGON_SERVER_CONFLICT ((NTSTATUS) 0xC0000132L) +#endif + +#ifndef STATUS_TIME_DIFFERENCE_AT_DC +# define STATUS_TIME_DIFFERENCE_AT_DC ((NTSTATUS) 0xC0000133L) +#endif + +#ifndef STATUS_SYNCHRONIZATION_REQUIRED +# define STATUS_SYNCHRONIZATION_REQUIRED ((NTSTATUS) 0xC0000134L) +#endif + +#ifndef STATUS_DLL_NOT_FOUND +# define STATUS_DLL_NOT_FOUND ((NTSTATUS) 0xC0000135L) +#endif + +#ifndef STATUS_OPEN_FAILED +# define STATUS_OPEN_FAILED ((NTSTATUS) 0xC0000136L) +#endif + +#ifndef STATUS_IO_PRIVILEGE_FAILED +# define STATUS_IO_PRIVILEGE_FAILED ((NTSTATUS) 0xC0000137L) +#endif + +#ifndef STATUS_ORDINAL_NOT_FOUND +# define STATUS_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000138L) +#endif + +#ifndef STATUS_ENTRYPOINT_NOT_FOUND +# define STATUS_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000139L) +#endif + +#ifndef STATUS_CONTROL_C_EXIT +# define STATUS_CONTROL_C_EXIT ((NTSTATUS) 0xC000013AL) +#endif + +#ifndef STATUS_LOCAL_DISCONNECT +# define STATUS_LOCAL_DISCONNECT ((NTSTATUS) 0xC000013BL) +#endif + +#ifndef STATUS_REMOTE_DISCONNECT +# define STATUS_REMOTE_DISCONNECT ((NTSTATUS) 0xC000013CL) +#endif + +#ifndef STATUS_REMOTE_RESOURCES +# define STATUS_REMOTE_RESOURCES ((NTSTATUS) 0xC000013DL) +#endif + +#ifndef STATUS_LINK_FAILED +# define STATUS_LINK_FAILED ((NTSTATUS) 0xC000013EL) +#endif + +#ifndef STATUS_LINK_TIMEOUT +# define STATUS_LINK_TIMEOUT ((NTSTATUS) 0xC000013FL) +#endif + +#ifndef STATUS_INVALID_CONNECTION +# define STATUS_INVALID_CONNECTION ((NTSTATUS) 0xC0000140L) +#endif + +#ifndef STATUS_INVALID_ADDRESS +# define STATUS_INVALID_ADDRESS ((NTSTATUS) 0xC0000141L) +#endif + +#ifndef STATUS_DLL_INIT_FAILED +# define STATUS_DLL_INIT_FAILED ((NTSTATUS) 0xC0000142L) +#endif + +#ifndef STATUS_MISSING_SYSTEMFILE +# define STATUS_MISSING_SYSTEMFILE ((NTSTATUS) 0xC0000143L) +#endif + +#ifndef STATUS_UNHANDLED_EXCEPTION +# define STATUS_UNHANDLED_EXCEPTION ((NTSTATUS) 0xC0000144L) +#endif + +#ifndef STATUS_APP_INIT_FAILURE +# define STATUS_APP_INIT_FAILURE ((NTSTATUS) 0xC0000145L) +#endif + +#ifndef STATUS_PAGEFILE_CREATE_FAILED +# define STATUS_PAGEFILE_CREATE_FAILED ((NTSTATUS) 0xC0000146L) +#endif + +#ifndef STATUS_NO_PAGEFILE +# define STATUS_NO_PAGEFILE ((NTSTATUS) 0xC0000147L) +#endif + +#ifndef STATUS_INVALID_LEVEL +# define STATUS_INVALID_LEVEL ((NTSTATUS) 0xC0000148L) +#endif + +#ifndef STATUS_WRONG_PASSWORD_CORE +# define STATUS_WRONG_PASSWORD_CORE ((NTSTATUS) 0xC0000149L) +#endif + +#ifndef STATUS_ILLEGAL_FLOAT_CONTEXT +# define STATUS_ILLEGAL_FLOAT_CONTEXT ((NTSTATUS) 0xC000014AL) +#endif + +#ifndef STATUS_PIPE_BROKEN +# define STATUS_PIPE_BROKEN ((NTSTATUS) 0xC000014BL) +#endif + +#ifndef STATUS_REGISTRY_CORRUPT +# define STATUS_REGISTRY_CORRUPT ((NTSTATUS) 0xC000014CL) +#endif + +#ifndef STATUS_REGISTRY_IO_FAILED +# define STATUS_REGISTRY_IO_FAILED ((NTSTATUS) 0xC000014DL) +#endif + +#ifndef STATUS_NO_EVENT_PAIR +# define STATUS_NO_EVENT_PAIR ((NTSTATUS) 0xC000014EL) +#endif + +#ifndef STATUS_UNRECOGNIZED_VOLUME +# define STATUS_UNRECOGNIZED_VOLUME ((NTSTATUS) 0xC000014FL) +#endif + +#ifndef STATUS_SERIAL_NO_DEVICE_INITED +# define STATUS_SERIAL_NO_DEVICE_INITED ((NTSTATUS) 0xC0000150L) +#endif + +#ifndef STATUS_NO_SUCH_ALIAS +# define STATUS_NO_SUCH_ALIAS ((NTSTATUS) 0xC0000151L) +#endif + +#ifndef STATUS_MEMBER_NOT_IN_ALIAS +# define STATUS_MEMBER_NOT_IN_ALIAS ((NTSTATUS) 0xC0000152L) +#endif + +#ifndef STATUS_MEMBER_IN_ALIAS +# define STATUS_MEMBER_IN_ALIAS ((NTSTATUS) 0xC0000153L) +#endif + +#ifndef STATUS_ALIAS_EXISTS +# define STATUS_ALIAS_EXISTS ((NTSTATUS) 0xC0000154L) +#endif + +#ifndef STATUS_LOGON_NOT_GRANTED +# define STATUS_LOGON_NOT_GRANTED ((NTSTATUS) 0xC0000155L) +#endif + +#ifndef STATUS_TOO_MANY_SECRETS +# define STATUS_TOO_MANY_SECRETS ((NTSTATUS) 0xC0000156L) +#endif + +#ifndef STATUS_SECRET_TOO_LONG +# define STATUS_SECRET_TOO_LONG ((NTSTATUS) 0xC0000157L) +#endif + +#ifndef STATUS_INTERNAL_DB_ERROR +# define STATUS_INTERNAL_DB_ERROR ((NTSTATUS) 0xC0000158L) +#endif + +#ifndef STATUS_FULLSCREEN_MODE +# define STATUS_FULLSCREEN_MODE ((NTSTATUS) 0xC0000159L) +#endif + +#ifndef STATUS_TOO_MANY_CONTEXT_IDS +# define STATUS_TOO_MANY_CONTEXT_IDS ((NTSTATUS) 0xC000015AL) +#endif + +#ifndef STATUS_LOGON_TYPE_NOT_GRANTED +# define STATUS_LOGON_TYPE_NOT_GRANTED ((NTSTATUS) 0xC000015BL) +#endif + +#ifndef STATUS_NOT_REGISTRY_FILE +# define STATUS_NOT_REGISTRY_FILE ((NTSTATUS) 0xC000015CL) +#endif + +#ifndef STATUS_NT_CROSS_ENCRYPTION_REQUIRED +# define STATUS_NT_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000015DL) +#endif + +#ifndef STATUS_DOMAIN_CTRLR_CONFIG_ERROR +# define STATUS_DOMAIN_CTRLR_CONFIG_ERROR ((NTSTATUS) 0xC000015EL) +#endif + +#ifndef STATUS_FT_MISSING_MEMBER +# define STATUS_FT_MISSING_MEMBER ((NTSTATUS) 0xC000015FL) +#endif + +#ifndef STATUS_ILL_FORMED_SERVICE_ENTRY +# define STATUS_ILL_FORMED_SERVICE_ENTRY ((NTSTATUS) 0xC0000160L) +#endif + +#ifndef STATUS_ILLEGAL_CHARACTER +# define STATUS_ILLEGAL_CHARACTER ((NTSTATUS) 0xC0000161L) +#endif + +#ifndef STATUS_UNMAPPABLE_CHARACTER +# define STATUS_UNMAPPABLE_CHARACTER ((NTSTATUS) 0xC0000162L) +#endif + +#ifndef STATUS_UNDEFINED_CHARACTER +# define STATUS_UNDEFINED_CHARACTER ((NTSTATUS) 0xC0000163L) +#endif + +#ifndef STATUS_FLOPPY_VOLUME +# define STATUS_FLOPPY_VOLUME ((NTSTATUS) 0xC0000164L) +#endif + +#ifndef STATUS_FLOPPY_ID_MARK_NOT_FOUND +# define STATUS_FLOPPY_ID_MARK_NOT_FOUND ((NTSTATUS) 0xC0000165L) +#endif + +#ifndef STATUS_FLOPPY_WRONG_CYLINDER +# define STATUS_FLOPPY_WRONG_CYLINDER ((NTSTATUS) 0xC0000166L) +#endif + +#ifndef STATUS_FLOPPY_UNKNOWN_ERROR +# define STATUS_FLOPPY_UNKNOWN_ERROR ((NTSTATUS) 0xC0000167L) +#endif + +#ifndef STATUS_FLOPPY_BAD_REGISTERS +# define STATUS_FLOPPY_BAD_REGISTERS ((NTSTATUS) 0xC0000168L) +#endif + +#ifndef STATUS_DISK_RECALIBRATE_FAILED +# define STATUS_DISK_RECALIBRATE_FAILED ((NTSTATUS) 0xC0000169L) +#endif + +#ifndef STATUS_DISK_OPERATION_FAILED +# define STATUS_DISK_OPERATION_FAILED ((NTSTATUS) 0xC000016AL) +#endif + +#ifndef STATUS_DISK_RESET_FAILED +# define STATUS_DISK_RESET_FAILED ((NTSTATUS) 0xC000016BL) +#endif + +#ifndef STATUS_SHARED_IRQ_BUSY +# define STATUS_SHARED_IRQ_BUSY ((NTSTATUS) 0xC000016CL) +#endif + +#ifndef STATUS_FT_ORPHANING +# define STATUS_FT_ORPHANING ((NTSTATUS) 0xC000016DL) +#endif + +#ifndef STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT +# define STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT ((NTSTATUS) 0xC000016EL) +#endif + +#ifndef STATUS_PARTITION_FAILURE +# define STATUS_PARTITION_FAILURE ((NTSTATUS) 0xC0000172L) +#endif + +#ifndef STATUS_INVALID_BLOCK_LENGTH +# define STATUS_INVALID_BLOCK_LENGTH ((NTSTATUS) 0xC0000173L) +#endif + +#ifndef STATUS_DEVICE_NOT_PARTITIONED +# define STATUS_DEVICE_NOT_PARTITIONED ((NTSTATUS) 0xC0000174L) +#endif + +#ifndef STATUS_UNABLE_TO_LOCK_MEDIA +# define STATUS_UNABLE_TO_LOCK_MEDIA ((NTSTATUS) 0xC0000175L) +#endif + +#ifndef STATUS_UNABLE_TO_UNLOAD_MEDIA +# define STATUS_UNABLE_TO_UNLOAD_MEDIA ((NTSTATUS) 0xC0000176L) +#endif + +#ifndef STATUS_EOM_OVERFLOW +# define STATUS_EOM_OVERFLOW ((NTSTATUS) 0xC0000177L) +#endif + +#ifndef STATUS_NO_MEDIA +# define STATUS_NO_MEDIA ((NTSTATUS) 0xC0000178L) +#endif + +#ifndef STATUS_NO_SUCH_MEMBER +# define STATUS_NO_SUCH_MEMBER ((NTSTATUS) 0xC000017AL) +#endif + +#ifndef STATUS_INVALID_MEMBER +# define STATUS_INVALID_MEMBER ((NTSTATUS) 0xC000017BL) +#endif + +#ifndef STATUS_KEY_DELETED +# define STATUS_KEY_DELETED ((NTSTATUS) 0xC000017CL) +#endif + +#ifndef STATUS_NO_LOG_SPACE +# define STATUS_NO_LOG_SPACE ((NTSTATUS) 0xC000017DL) +#endif + +#ifndef STATUS_TOO_MANY_SIDS +# define STATUS_TOO_MANY_SIDS ((NTSTATUS) 0xC000017EL) +#endif + +#ifndef STATUS_LM_CROSS_ENCRYPTION_REQUIRED +# define STATUS_LM_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000017FL) +#endif + +#ifndef STATUS_KEY_HAS_CHILDREN +# define STATUS_KEY_HAS_CHILDREN ((NTSTATUS) 0xC0000180L) +#endif + +#ifndef STATUS_CHILD_MUST_BE_VOLATILE +# define STATUS_CHILD_MUST_BE_VOLATILE ((NTSTATUS) 0xC0000181L) +#endif + +#ifndef STATUS_DEVICE_CONFIGURATION_ERROR +# define STATUS_DEVICE_CONFIGURATION_ERROR ((NTSTATUS) 0xC0000182L) +#endif + +#ifndef STATUS_DRIVER_INTERNAL_ERROR +# define STATUS_DRIVER_INTERNAL_ERROR ((NTSTATUS) 0xC0000183L) +#endif + +#ifndef STATUS_INVALID_DEVICE_STATE +# define STATUS_INVALID_DEVICE_STATE ((NTSTATUS) 0xC0000184L) +#endif + +#ifndef STATUS_IO_DEVICE_ERROR +# define STATUS_IO_DEVICE_ERROR ((NTSTATUS) 0xC0000185L) +#endif + +#ifndef STATUS_DEVICE_PROTOCOL_ERROR +# define STATUS_DEVICE_PROTOCOL_ERROR ((NTSTATUS) 0xC0000186L) +#endif + +#ifndef STATUS_BACKUP_CONTROLLER +# define STATUS_BACKUP_CONTROLLER ((NTSTATUS) 0xC0000187L) +#endif + +#ifndef STATUS_LOG_FILE_FULL +# define STATUS_LOG_FILE_FULL ((NTSTATUS) 0xC0000188L) +#endif + +#ifndef STATUS_TOO_LATE +# define STATUS_TOO_LATE ((NTSTATUS) 0xC0000189L) +#endif + +#ifndef STATUS_NO_TRUST_LSA_SECRET +# define STATUS_NO_TRUST_LSA_SECRET ((NTSTATUS) 0xC000018AL) +#endif + +#ifndef STATUS_NO_TRUST_SAM_ACCOUNT +# define STATUS_NO_TRUST_SAM_ACCOUNT ((NTSTATUS) 0xC000018BL) +#endif + +#ifndef STATUS_TRUSTED_DOMAIN_FAILURE +# define STATUS_TRUSTED_DOMAIN_FAILURE ((NTSTATUS) 0xC000018CL) +#endif + +#ifndef STATUS_TRUSTED_RELATIONSHIP_FAILURE +# define STATUS_TRUSTED_RELATIONSHIP_FAILURE ((NTSTATUS) 0xC000018DL) +#endif + +#ifndef STATUS_EVENTLOG_FILE_CORRUPT +# define STATUS_EVENTLOG_FILE_CORRUPT ((NTSTATUS) 0xC000018EL) +#endif + +#ifndef STATUS_EVENTLOG_CANT_START +# define STATUS_EVENTLOG_CANT_START ((NTSTATUS) 0xC000018FL) +#endif + +#ifndef STATUS_TRUST_FAILURE +# define STATUS_TRUST_FAILURE ((NTSTATUS) 0xC0000190L) +#endif + +#ifndef STATUS_MUTANT_LIMIT_EXCEEDED +# define STATUS_MUTANT_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000191L) +#endif + +#ifndef STATUS_NETLOGON_NOT_STARTED +# define STATUS_NETLOGON_NOT_STARTED ((NTSTATUS) 0xC0000192L) +#endif + +#ifndef STATUS_ACCOUNT_EXPIRED +# define STATUS_ACCOUNT_EXPIRED ((NTSTATUS) 0xC0000193L) +#endif + +#ifndef STATUS_POSSIBLE_DEADLOCK +# define STATUS_POSSIBLE_DEADLOCK ((NTSTATUS) 0xC0000194L) +#endif + +#ifndef STATUS_NETWORK_CREDENTIAL_CONFLICT +# define STATUS_NETWORK_CREDENTIAL_CONFLICT ((NTSTATUS) 0xC0000195L) +#endif + +#ifndef STATUS_REMOTE_SESSION_LIMIT +# define STATUS_REMOTE_SESSION_LIMIT ((NTSTATUS) 0xC0000196L) +#endif + +#ifndef STATUS_EVENTLOG_FILE_CHANGED +# define STATUS_EVENTLOG_FILE_CHANGED ((NTSTATUS) 0xC0000197L) +#endif + +#ifndef STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT +# define STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT ((NTSTATUS) 0xC0000198L) +#endif + +#ifndef STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT +# define STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT ((NTSTATUS) 0xC0000199L) +#endif + +#ifndef STATUS_NOLOGON_SERVER_TRUST_ACCOUNT +# define STATUS_NOLOGON_SERVER_TRUST_ACCOUNT ((NTSTATUS) 0xC000019AL) +#endif + +#ifndef STATUS_DOMAIN_TRUST_INCONSISTENT +# define STATUS_DOMAIN_TRUST_INCONSISTENT ((NTSTATUS) 0xC000019BL) +#endif + +#ifndef STATUS_FS_DRIVER_REQUIRED +# define STATUS_FS_DRIVER_REQUIRED ((NTSTATUS) 0xC000019CL) +#endif + +#ifndef STATUS_IMAGE_ALREADY_LOADED_AS_DLL +# define STATUS_IMAGE_ALREADY_LOADED_AS_DLL ((NTSTATUS) 0xC000019DL) +#endif + +#ifndef STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING +# define STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING ((NTSTATUS) 0xC000019EL) +#endif + +#ifndef STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME +# define STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME ((NTSTATUS) 0xC000019FL) +#endif + +#ifndef STATUS_SECURITY_STREAM_IS_INCONSISTENT +# define STATUS_SECURITY_STREAM_IS_INCONSISTENT ((NTSTATUS) 0xC00001A0L) +#endif + +#ifndef STATUS_INVALID_LOCK_RANGE +# define STATUS_INVALID_LOCK_RANGE ((NTSTATUS) 0xC00001A1L) +#endif + +#ifndef STATUS_INVALID_ACE_CONDITION +# define STATUS_INVALID_ACE_CONDITION ((NTSTATUS) 0xC00001A2L) +#endif + +#ifndef STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT +# define STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT ((NTSTATUS) 0xC00001A3L) +#endif + +#ifndef STATUS_NOTIFICATION_GUID_ALREADY_DEFINED +# define STATUS_NOTIFICATION_GUID_ALREADY_DEFINED ((NTSTATUS) 0xC00001A4L) +#endif + +#ifndef STATUS_NETWORK_OPEN_RESTRICTION +# define STATUS_NETWORK_OPEN_RESTRICTION ((NTSTATUS) 0xC0000201L) +#endif + +#ifndef STATUS_NO_USER_SESSION_KEY +# define STATUS_NO_USER_SESSION_KEY ((NTSTATUS) 0xC0000202L) +#endif + +#ifndef STATUS_USER_SESSION_DELETED +# define STATUS_USER_SESSION_DELETED ((NTSTATUS) 0xC0000203L) +#endif + +#ifndef STATUS_RESOURCE_LANG_NOT_FOUND +# define STATUS_RESOURCE_LANG_NOT_FOUND ((NTSTATUS) 0xC0000204L) +#endif + +#ifndef STATUS_INSUFF_SERVER_RESOURCES +# define STATUS_INSUFF_SERVER_RESOURCES ((NTSTATUS) 0xC0000205L) +#endif + +#ifndef STATUS_INVALID_BUFFER_SIZE +# define STATUS_INVALID_BUFFER_SIZE ((NTSTATUS) 0xC0000206L) +#endif + +#ifndef STATUS_INVALID_ADDRESS_COMPONENT +# define STATUS_INVALID_ADDRESS_COMPONENT ((NTSTATUS) 0xC0000207L) +#endif + +#ifndef STATUS_INVALID_ADDRESS_WILDCARD +# define STATUS_INVALID_ADDRESS_WILDCARD ((NTSTATUS) 0xC0000208L) +#endif + +#ifndef STATUS_TOO_MANY_ADDRESSES +# define STATUS_TOO_MANY_ADDRESSES ((NTSTATUS) 0xC0000209L) +#endif + +#ifndef STATUS_ADDRESS_ALREADY_EXISTS +# define STATUS_ADDRESS_ALREADY_EXISTS ((NTSTATUS) 0xC000020AL) +#endif + +#ifndef STATUS_ADDRESS_CLOSED +# define STATUS_ADDRESS_CLOSED ((NTSTATUS) 0xC000020BL) +#endif + +#ifndef STATUS_CONNECTION_DISCONNECTED +# define STATUS_CONNECTION_DISCONNECTED ((NTSTATUS) 0xC000020CL) +#endif + +#ifndef STATUS_CONNECTION_RESET +# define STATUS_CONNECTION_RESET ((NTSTATUS) 0xC000020DL) +#endif + +#ifndef STATUS_TOO_MANY_NODES +# define STATUS_TOO_MANY_NODES ((NTSTATUS) 0xC000020EL) +#endif + +#ifndef STATUS_TRANSACTION_ABORTED +# define STATUS_TRANSACTION_ABORTED ((NTSTATUS) 0xC000020FL) +#endif + +#ifndef STATUS_TRANSACTION_TIMED_OUT +# define STATUS_TRANSACTION_TIMED_OUT ((NTSTATUS) 0xC0000210L) +#endif + +#ifndef STATUS_TRANSACTION_NO_RELEASE +# define STATUS_TRANSACTION_NO_RELEASE ((NTSTATUS) 0xC0000211L) +#endif + +#ifndef STATUS_TRANSACTION_NO_MATCH +# define STATUS_TRANSACTION_NO_MATCH ((NTSTATUS) 0xC0000212L) +#endif + +#ifndef STATUS_TRANSACTION_RESPONDED +# define STATUS_TRANSACTION_RESPONDED ((NTSTATUS) 0xC0000213L) +#endif + +#ifndef STATUS_TRANSACTION_INVALID_ID +# define STATUS_TRANSACTION_INVALID_ID ((NTSTATUS) 0xC0000214L) +#endif + +#ifndef STATUS_TRANSACTION_INVALID_TYPE +# define STATUS_TRANSACTION_INVALID_TYPE ((NTSTATUS) 0xC0000215L) +#endif + +#ifndef STATUS_NOT_SERVER_SESSION +# define STATUS_NOT_SERVER_SESSION ((NTSTATUS) 0xC0000216L) +#endif + +#ifndef STATUS_NOT_CLIENT_SESSION +# define STATUS_NOT_CLIENT_SESSION ((NTSTATUS) 0xC0000217L) +#endif + +#ifndef STATUS_CANNOT_LOAD_REGISTRY_FILE +# define STATUS_CANNOT_LOAD_REGISTRY_FILE ((NTSTATUS) 0xC0000218L) +#endif + +#ifndef STATUS_DEBUG_ATTACH_FAILED +# define STATUS_DEBUG_ATTACH_FAILED ((NTSTATUS) 0xC0000219L) +#endif + +#ifndef STATUS_SYSTEM_PROCESS_TERMINATED +# define STATUS_SYSTEM_PROCESS_TERMINATED ((NTSTATUS) 0xC000021AL) +#endif + +#ifndef STATUS_DATA_NOT_ACCEPTED +# define STATUS_DATA_NOT_ACCEPTED ((NTSTATUS) 0xC000021BL) +#endif + +#ifndef STATUS_NO_BROWSER_SERVERS_FOUND +# define STATUS_NO_BROWSER_SERVERS_FOUND ((NTSTATUS) 0xC000021CL) +#endif + +#ifndef STATUS_VDM_HARD_ERROR +# define STATUS_VDM_HARD_ERROR ((NTSTATUS) 0xC000021DL) +#endif + +#ifndef STATUS_DRIVER_CANCEL_TIMEOUT +# define STATUS_DRIVER_CANCEL_TIMEOUT ((NTSTATUS) 0xC000021EL) +#endif + +#ifndef STATUS_REPLY_MESSAGE_MISMATCH +# define STATUS_REPLY_MESSAGE_MISMATCH ((NTSTATUS) 0xC000021FL) +#endif + +#ifndef STATUS_MAPPED_ALIGNMENT +# define STATUS_MAPPED_ALIGNMENT ((NTSTATUS) 0xC0000220L) +#endif + +#ifndef STATUS_IMAGE_CHECKSUM_MISMATCH +# define STATUS_IMAGE_CHECKSUM_MISMATCH ((NTSTATUS) 0xC0000221L) +#endif + +#ifndef STATUS_LOST_WRITEBEHIND_DATA +# define STATUS_LOST_WRITEBEHIND_DATA ((NTSTATUS) 0xC0000222L) +#endif + +#ifndef STATUS_CLIENT_SERVER_PARAMETERS_INVALID +# define STATUS_CLIENT_SERVER_PARAMETERS_INVALID ((NTSTATUS) 0xC0000223L) +#endif + +#ifndef STATUS_PASSWORD_MUST_CHANGE +# define STATUS_PASSWORD_MUST_CHANGE ((NTSTATUS) 0xC0000224L) +#endif + +#ifndef STATUS_NOT_FOUND +# define STATUS_NOT_FOUND ((NTSTATUS) 0xC0000225L) +#endif + +#ifndef STATUS_NOT_TINY_STREAM +# define STATUS_NOT_TINY_STREAM ((NTSTATUS) 0xC0000226L) +#endif + +#ifndef STATUS_RECOVERY_FAILURE +# define STATUS_RECOVERY_FAILURE ((NTSTATUS) 0xC0000227L) +#endif + +#ifndef STATUS_STACK_OVERFLOW_READ +# define STATUS_STACK_OVERFLOW_READ ((NTSTATUS) 0xC0000228L) +#endif + +#ifndef STATUS_FAIL_CHECK +# define STATUS_FAIL_CHECK ((NTSTATUS) 0xC0000229L) +#endif + +#ifndef STATUS_DUPLICATE_OBJECTID +# define STATUS_DUPLICATE_OBJECTID ((NTSTATUS) 0xC000022AL) +#endif + +#ifndef STATUS_OBJECTID_EXISTS +# define STATUS_OBJECTID_EXISTS ((NTSTATUS) 0xC000022BL) +#endif + +#ifndef STATUS_CONVERT_TO_LARGE +# define STATUS_CONVERT_TO_LARGE ((NTSTATUS) 0xC000022CL) +#endif + +#ifndef STATUS_RETRY +# define STATUS_RETRY ((NTSTATUS) 0xC000022DL) +#endif + +#ifndef STATUS_FOUND_OUT_OF_SCOPE +# define STATUS_FOUND_OUT_OF_SCOPE ((NTSTATUS) 0xC000022EL) +#endif + +#ifndef STATUS_ALLOCATE_BUCKET +# define STATUS_ALLOCATE_BUCKET ((NTSTATUS) 0xC000022FL) +#endif + +#ifndef STATUS_PROPSET_NOT_FOUND +# define STATUS_PROPSET_NOT_FOUND ((NTSTATUS) 0xC0000230L) +#endif + +#ifndef STATUS_MARSHALL_OVERFLOW +# define STATUS_MARSHALL_OVERFLOW ((NTSTATUS) 0xC0000231L) +#endif + +#ifndef STATUS_INVALID_VARIANT +# define STATUS_INVALID_VARIANT ((NTSTATUS) 0xC0000232L) +#endif + +#ifndef STATUS_DOMAIN_CONTROLLER_NOT_FOUND +# define STATUS_DOMAIN_CONTROLLER_NOT_FOUND ((NTSTATUS) 0xC0000233L) +#endif + +#ifndef STATUS_ACCOUNT_LOCKED_OUT +# define STATUS_ACCOUNT_LOCKED_OUT ((NTSTATUS) 0xC0000234L) +#endif + +#ifndef STATUS_HANDLE_NOT_CLOSABLE +# define STATUS_HANDLE_NOT_CLOSABLE ((NTSTATUS) 0xC0000235L) +#endif + +#ifndef STATUS_CONNECTION_REFUSED +# define STATUS_CONNECTION_REFUSED ((NTSTATUS) 0xC0000236L) +#endif + +#ifndef STATUS_GRACEFUL_DISCONNECT +# define STATUS_GRACEFUL_DISCONNECT ((NTSTATUS) 0xC0000237L) +#endif + +#ifndef STATUS_ADDRESS_ALREADY_ASSOCIATED +# define STATUS_ADDRESS_ALREADY_ASSOCIATED ((NTSTATUS) 0xC0000238L) +#endif + +#ifndef STATUS_ADDRESS_NOT_ASSOCIATED +# define STATUS_ADDRESS_NOT_ASSOCIATED ((NTSTATUS) 0xC0000239L) +#endif + +#ifndef STATUS_CONNECTION_INVALID +# define STATUS_CONNECTION_INVALID ((NTSTATUS) 0xC000023AL) +#endif + +#ifndef STATUS_CONNECTION_ACTIVE +# define STATUS_CONNECTION_ACTIVE ((NTSTATUS) 0xC000023BL) +#endif + +#ifndef STATUS_NETWORK_UNREACHABLE +# define STATUS_NETWORK_UNREACHABLE ((NTSTATUS) 0xC000023CL) +#endif + +#ifndef STATUS_HOST_UNREACHABLE +# define STATUS_HOST_UNREACHABLE ((NTSTATUS) 0xC000023DL) +#endif + +#ifndef STATUS_PROTOCOL_UNREACHABLE +# define STATUS_PROTOCOL_UNREACHABLE ((NTSTATUS) 0xC000023EL) +#endif + +#ifndef STATUS_PORT_UNREACHABLE +# define STATUS_PORT_UNREACHABLE ((NTSTATUS) 0xC000023FL) +#endif + +#ifndef STATUS_REQUEST_ABORTED +# define STATUS_REQUEST_ABORTED ((NTSTATUS) 0xC0000240L) +#endif + +#ifndef STATUS_CONNECTION_ABORTED +# define STATUS_CONNECTION_ABORTED ((NTSTATUS) 0xC0000241L) +#endif + +#ifndef STATUS_BAD_COMPRESSION_BUFFER +# define STATUS_BAD_COMPRESSION_BUFFER ((NTSTATUS) 0xC0000242L) +#endif + +#ifndef STATUS_USER_MAPPED_FILE +# define STATUS_USER_MAPPED_FILE ((NTSTATUS) 0xC0000243L) +#endif + +#ifndef STATUS_AUDIT_FAILED +# define STATUS_AUDIT_FAILED ((NTSTATUS) 0xC0000244L) +#endif + +#ifndef STATUS_TIMER_RESOLUTION_NOT_SET +# define STATUS_TIMER_RESOLUTION_NOT_SET ((NTSTATUS) 0xC0000245L) +#endif + +#ifndef STATUS_CONNECTION_COUNT_LIMIT +# define STATUS_CONNECTION_COUNT_LIMIT ((NTSTATUS) 0xC0000246L) +#endif + +#ifndef STATUS_LOGIN_TIME_RESTRICTION +# define STATUS_LOGIN_TIME_RESTRICTION ((NTSTATUS) 0xC0000247L) +#endif + +#ifndef STATUS_LOGIN_WKSTA_RESTRICTION +# define STATUS_LOGIN_WKSTA_RESTRICTION ((NTSTATUS) 0xC0000248L) +#endif + +#ifndef STATUS_IMAGE_MP_UP_MISMATCH +# define STATUS_IMAGE_MP_UP_MISMATCH ((NTSTATUS) 0xC0000249L) +#endif + +#ifndef STATUS_INSUFFICIENT_LOGON_INFO +# define STATUS_INSUFFICIENT_LOGON_INFO ((NTSTATUS) 0xC0000250L) +#endif + +#ifndef STATUS_BAD_DLL_ENTRYPOINT +# define STATUS_BAD_DLL_ENTRYPOINT ((NTSTATUS) 0xC0000251L) +#endif + +#ifndef STATUS_BAD_SERVICE_ENTRYPOINT +# define STATUS_BAD_SERVICE_ENTRYPOINT ((NTSTATUS) 0xC0000252L) +#endif + +#ifndef STATUS_LPC_REPLY_LOST +# define STATUS_LPC_REPLY_LOST ((NTSTATUS) 0xC0000253L) +#endif + +#ifndef STATUS_IP_ADDRESS_CONFLICT1 +# define STATUS_IP_ADDRESS_CONFLICT1 ((NTSTATUS) 0xC0000254L) +#endif + +#ifndef STATUS_IP_ADDRESS_CONFLICT2 +# define STATUS_IP_ADDRESS_CONFLICT2 ((NTSTATUS) 0xC0000255L) +#endif + +#ifndef STATUS_REGISTRY_QUOTA_LIMIT +# define STATUS_REGISTRY_QUOTA_LIMIT ((NTSTATUS) 0xC0000256L) +#endif + +#ifndef STATUS_PATH_NOT_COVERED +# define STATUS_PATH_NOT_COVERED ((NTSTATUS) 0xC0000257L) +#endif + +#ifndef STATUS_NO_CALLBACK_ACTIVE +# define STATUS_NO_CALLBACK_ACTIVE ((NTSTATUS) 0xC0000258L) +#endif + +#ifndef STATUS_LICENSE_QUOTA_EXCEEDED +# define STATUS_LICENSE_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000259L) +#endif + +#ifndef STATUS_PWD_TOO_SHORT +# define STATUS_PWD_TOO_SHORT ((NTSTATUS) 0xC000025AL) +#endif + +#ifndef STATUS_PWD_TOO_RECENT +# define STATUS_PWD_TOO_RECENT ((NTSTATUS) 0xC000025BL) +#endif + +#ifndef STATUS_PWD_HISTORY_CONFLICT +# define STATUS_PWD_HISTORY_CONFLICT ((NTSTATUS) 0xC000025CL) +#endif + +#ifndef STATUS_PLUGPLAY_NO_DEVICE +# define STATUS_PLUGPLAY_NO_DEVICE ((NTSTATUS) 0xC000025EL) +#endif + +#ifndef STATUS_UNSUPPORTED_COMPRESSION +# define STATUS_UNSUPPORTED_COMPRESSION ((NTSTATUS) 0xC000025FL) +#endif + +#ifndef STATUS_INVALID_HW_PROFILE +# define STATUS_INVALID_HW_PROFILE ((NTSTATUS) 0xC0000260L) +#endif + +#ifndef STATUS_INVALID_PLUGPLAY_DEVICE_PATH +# define STATUS_INVALID_PLUGPLAY_DEVICE_PATH ((NTSTATUS) 0xC0000261L) +#endif + +#ifndef STATUS_DRIVER_ORDINAL_NOT_FOUND +# define STATUS_DRIVER_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000262L) +#endif + +#ifndef STATUS_DRIVER_ENTRYPOINT_NOT_FOUND +# define STATUS_DRIVER_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000263L) +#endif + +#ifndef STATUS_RESOURCE_NOT_OWNED +# define STATUS_RESOURCE_NOT_OWNED ((NTSTATUS) 0xC0000264L) +#endif + +#ifndef STATUS_TOO_MANY_LINKS +# define STATUS_TOO_MANY_LINKS ((NTSTATUS) 0xC0000265L) +#endif + +#ifndef STATUS_QUOTA_LIST_INCONSISTENT +# define STATUS_QUOTA_LIST_INCONSISTENT ((NTSTATUS) 0xC0000266L) +#endif + +#ifndef STATUS_FILE_IS_OFFLINE +# define STATUS_FILE_IS_OFFLINE ((NTSTATUS) 0xC0000267L) +#endif + +#ifndef STATUS_EVALUATION_EXPIRATION +# define STATUS_EVALUATION_EXPIRATION ((NTSTATUS) 0xC0000268L) +#endif + +#ifndef STATUS_ILLEGAL_DLL_RELOCATION +# define STATUS_ILLEGAL_DLL_RELOCATION ((NTSTATUS) 0xC0000269L) +#endif + +#ifndef STATUS_LICENSE_VIOLATION +# define STATUS_LICENSE_VIOLATION ((NTSTATUS) 0xC000026AL) +#endif + +#ifndef STATUS_DLL_INIT_FAILED_LOGOFF +# define STATUS_DLL_INIT_FAILED_LOGOFF ((NTSTATUS) 0xC000026BL) +#endif + +#ifndef STATUS_DRIVER_UNABLE_TO_LOAD +# define STATUS_DRIVER_UNABLE_TO_LOAD ((NTSTATUS) 0xC000026CL) +#endif + +#ifndef STATUS_DFS_UNAVAILABLE +# define STATUS_DFS_UNAVAILABLE ((NTSTATUS) 0xC000026DL) +#endif + +#ifndef STATUS_VOLUME_DISMOUNTED +# define STATUS_VOLUME_DISMOUNTED ((NTSTATUS) 0xC000026EL) +#endif + +#ifndef STATUS_WX86_INTERNAL_ERROR +# define STATUS_WX86_INTERNAL_ERROR ((NTSTATUS) 0xC000026FL) +#endif + +#ifndef STATUS_WX86_FLOAT_STACK_CHECK +# define STATUS_WX86_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000270L) +#endif + +#ifndef STATUS_VALIDATE_CONTINUE +# define STATUS_VALIDATE_CONTINUE ((NTSTATUS) 0xC0000271L) +#endif + +#ifndef STATUS_NO_MATCH +# define STATUS_NO_MATCH ((NTSTATUS) 0xC0000272L) +#endif + +#ifndef STATUS_NO_MORE_MATCHES +# define STATUS_NO_MORE_MATCHES ((NTSTATUS) 0xC0000273L) +#endif + +#ifndef STATUS_NOT_A_REPARSE_POINT +# define STATUS_NOT_A_REPARSE_POINT ((NTSTATUS) 0xC0000275L) +#endif + +#ifndef STATUS_IO_REPARSE_TAG_INVALID +# define STATUS_IO_REPARSE_TAG_INVALID ((NTSTATUS) 0xC0000276L) +#endif + +#ifndef STATUS_IO_REPARSE_TAG_MISMATCH +# define STATUS_IO_REPARSE_TAG_MISMATCH ((NTSTATUS) 0xC0000277L) +#endif + +#ifndef STATUS_IO_REPARSE_DATA_INVALID +# define STATUS_IO_REPARSE_DATA_INVALID ((NTSTATUS) 0xC0000278L) +#endif + +#ifndef STATUS_IO_REPARSE_TAG_NOT_HANDLED +# define STATUS_IO_REPARSE_TAG_NOT_HANDLED ((NTSTATUS) 0xC0000279L) +#endif + +#ifndef STATUS_REPARSE_POINT_NOT_RESOLVED +# define STATUS_REPARSE_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000280L) +#endif + +#ifndef STATUS_DIRECTORY_IS_A_REPARSE_POINT +# define STATUS_DIRECTORY_IS_A_REPARSE_POINT ((NTSTATUS) 0xC0000281L) +#endif + +#ifndef STATUS_RANGE_LIST_CONFLICT +# define STATUS_RANGE_LIST_CONFLICT ((NTSTATUS) 0xC0000282L) +#endif + +#ifndef STATUS_SOURCE_ELEMENT_EMPTY +# define STATUS_SOURCE_ELEMENT_EMPTY ((NTSTATUS) 0xC0000283L) +#endif + +#ifndef STATUS_DESTINATION_ELEMENT_FULL +# define STATUS_DESTINATION_ELEMENT_FULL ((NTSTATUS) 0xC0000284L) +#endif + +#ifndef STATUS_ILLEGAL_ELEMENT_ADDRESS +# define STATUS_ILLEGAL_ELEMENT_ADDRESS ((NTSTATUS) 0xC0000285L) +#endif + +#ifndef STATUS_MAGAZINE_NOT_PRESENT +# define STATUS_MAGAZINE_NOT_PRESENT ((NTSTATUS) 0xC0000286L) +#endif + +#ifndef STATUS_REINITIALIZATION_NEEDED +# define STATUS_REINITIALIZATION_NEEDED ((NTSTATUS) 0xC0000287L) +#endif + +#ifndef STATUS_DEVICE_REQUIRES_CLEANING +# define STATUS_DEVICE_REQUIRES_CLEANING ((NTSTATUS) 0x80000288L) +#endif + +#ifndef STATUS_DEVICE_DOOR_OPEN +# define STATUS_DEVICE_DOOR_OPEN ((NTSTATUS) 0x80000289L) +#endif + +#ifndef STATUS_ENCRYPTION_FAILED +# define STATUS_ENCRYPTION_FAILED ((NTSTATUS) 0xC000028AL) +#endif + +#ifndef STATUS_DECRYPTION_FAILED +# define STATUS_DECRYPTION_FAILED ((NTSTATUS) 0xC000028BL) +#endif + +#ifndef STATUS_RANGE_NOT_FOUND +# define STATUS_RANGE_NOT_FOUND ((NTSTATUS) 0xC000028CL) +#endif + +#ifndef STATUS_NO_RECOVERY_POLICY +# define STATUS_NO_RECOVERY_POLICY ((NTSTATUS) 0xC000028DL) +#endif + +#ifndef STATUS_NO_EFS +# define STATUS_NO_EFS ((NTSTATUS) 0xC000028EL) +#endif + +#ifndef STATUS_WRONG_EFS +# define STATUS_WRONG_EFS ((NTSTATUS) 0xC000028FL) +#endif + +#ifndef STATUS_NO_USER_KEYS +# define STATUS_NO_USER_KEYS ((NTSTATUS) 0xC0000290L) +#endif + +#ifndef STATUS_FILE_NOT_ENCRYPTED +# define STATUS_FILE_NOT_ENCRYPTED ((NTSTATUS) 0xC0000291L) +#endif + +#ifndef STATUS_NOT_EXPORT_FORMAT +# define STATUS_NOT_EXPORT_FORMAT ((NTSTATUS) 0xC0000292L) +#endif + +#ifndef STATUS_FILE_ENCRYPTED +# define STATUS_FILE_ENCRYPTED ((NTSTATUS) 0xC0000293L) +#endif + +#ifndef STATUS_WAKE_SYSTEM +# define STATUS_WAKE_SYSTEM ((NTSTATUS) 0x40000294L) +#endif + +#ifndef STATUS_WMI_GUID_NOT_FOUND +# define STATUS_WMI_GUID_NOT_FOUND ((NTSTATUS) 0xC0000295L) +#endif + +#ifndef STATUS_WMI_INSTANCE_NOT_FOUND +# define STATUS_WMI_INSTANCE_NOT_FOUND ((NTSTATUS) 0xC0000296L) +#endif + +#ifndef STATUS_WMI_ITEMID_NOT_FOUND +# define STATUS_WMI_ITEMID_NOT_FOUND ((NTSTATUS) 0xC0000297L) +#endif + +#ifndef STATUS_WMI_TRY_AGAIN +# define STATUS_WMI_TRY_AGAIN ((NTSTATUS) 0xC0000298L) +#endif + +#ifndef STATUS_SHARED_POLICY +# define STATUS_SHARED_POLICY ((NTSTATUS) 0xC0000299L) +#endif + +#ifndef STATUS_POLICY_OBJECT_NOT_FOUND +# define STATUS_POLICY_OBJECT_NOT_FOUND ((NTSTATUS) 0xC000029AL) +#endif + +#ifndef STATUS_POLICY_ONLY_IN_DS +# define STATUS_POLICY_ONLY_IN_DS ((NTSTATUS) 0xC000029BL) +#endif + +#ifndef STATUS_VOLUME_NOT_UPGRADED +# define STATUS_VOLUME_NOT_UPGRADED ((NTSTATUS) 0xC000029CL) +#endif + +#ifndef STATUS_REMOTE_STORAGE_NOT_ACTIVE +# define STATUS_REMOTE_STORAGE_NOT_ACTIVE ((NTSTATUS) 0xC000029DL) +#endif + +#ifndef STATUS_REMOTE_STORAGE_MEDIA_ERROR +# define STATUS_REMOTE_STORAGE_MEDIA_ERROR ((NTSTATUS) 0xC000029EL) +#endif + +#ifndef STATUS_NO_TRACKING_SERVICE +# define STATUS_NO_TRACKING_SERVICE ((NTSTATUS) 0xC000029FL) +#endif + +#ifndef STATUS_SERVER_SID_MISMATCH +# define STATUS_SERVER_SID_MISMATCH ((NTSTATUS) 0xC00002A0L) +#endif + +#ifndef STATUS_DS_NO_ATTRIBUTE_OR_VALUE +# define STATUS_DS_NO_ATTRIBUTE_OR_VALUE ((NTSTATUS) 0xC00002A1L) +#endif + +#ifndef STATUS_DS_INVALID_ATTRIBUTE_SYNTAX +# define STATUS_DS_INVALID_ATTRIBUTE_SYNTAX ((NTSTATUS) 0xC00002A2L) +#endif + +#ifndef STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED +# define STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED ((NTSTATUS) 0xC00002A3L) +#endif + +#ifndef STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS +# define STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS ((NTSTATUS) 0xC00002A4L) +#endif + +#ifndef STATUS_DS_BUSY +# define STATUS_DS_BUSY ((NTSTATUS) 0xC00002A5L) +#endif + +#ifndef STATUS_DS_UNAVAILABLE +# define STATUS_DS_UNAVAILABLE ((NTSTATUS) 0xC00002A6L) +#endif + +#ifndef STATUS_DS_NO_RIDS_ALLOCATED +# define STATUS_DS_NO_RIDS_ALLOCATED ((NTSTATUS) 0xC00002A7L) +#endif + +#ifndef STATUS_DS_NO_MORE_RIDS +# define STATUS_DS_NO_MORE_RIDS ((NTSTATUS) 0xC00002A8L) +#endif + +#ifndef STATUS_DS_INCORRECT_ROLE_OWNER +# define STATUS_DS_INCORRECT_ROLE_OWNER ((NTSTATUS) 0xC00002A9L) +#endif + +#ifndef STATUS_DS_RIDMGR_INIT_ERROR +# define STATUS_DS_RIDMGR_INIT_ERROR ((NTSTATUS) 0xC00002AAL) +#endif + +#ifndef STATUS_DS_OBJ_CLASS_VIOLATION +# define STATUS_DS_OBJ_CLASS_VIOLATION ((NTSTATUS) 0xC00002ABL) +#endif + +#ifndef STATUS_DS_CANT_ON_NON_LEAF +# define STATUS_DS_CANT_ON_NON_LEAF ((NTSTATUS) 0xC00002ACL) +#endif + +#ifndef STATUS_DS_CANT_ON_RDN +# define STATUS_DS_CANT_ON_RDN ((NTSTATUS) 0xC00002ADL) +#endif + +#ifndef STATUS_DS_CANT_MOD_OBJ_CLASS +# define STATUS_DS_CANT_MOD_OBJ_CLASS ((NTSTATUS) 0xC00002AEL) +#endif + +#ifndef STATUS_DS_CROSS_DOM_MOVE_FAILED +# define STATUS_DS_CROSS_DOM_MOVE_FAILED ((NTSTATUS) 0xC00002AFL) +#endif + +#ifndef STATUS_DS_GC_NOT_AVAILABLE +# define STATUS_DS_GC_NOT_AVAILABLE ((NTSTATUS) 0xC00002B0L) +#endif + +#ifndef STATUS_DIRECTORY_SERVICE_REQUIRED +# define STATUS_DIRECTORY_SERVICE_REQUIRED ((NTSTATUS) 0xC00002B1L) +#endif + +#ifndef STATUS_REPARSE_ATTRIBUTE_CONFLICT +# define STATUS_REPARSE_ATTRIBUTE_CONFLICT ((NTSTATUS) 0xC00002B2L) +#endif + +#ifndef STATUS_CANT_ENABLE_DENY_ONLY +# define STATUS_CANT_ENABLE_DENY_ONLY ((NTSTATUS) 0xC00002B3L) +#endif + +#ifndef STATUS_FLOAT_MULTIPLE_FAULTS +# define STATUS_FLOAT_MULTIPLE_FAULTS ((NTSTATUS) 0xC00002B4L) +#endif + +#ifndef STATUS_FLOAT_MULTIPLE_TRAPS +# define STATUS_FLOAT_MULTIPLE_TRAPS ((NTSTATUS) 0xC00002B5L) +#endif + +#ifndef STATUS_DEVICE_REMOVED +# define STATUS_DEVICE_REMOVED ((NTSTATUS) 0xC00002B6L) +#endif + +#ifndef STATUS_JOURNAL_DELETE_IN_PROGRESS +# define STATUS_JOURNAL_DELETE_IN_PROGRESS ((NTSTATUS) 0xC00002B7L) +#endif + +#ifndef STATUS_JOURNAL_NOT_ACTIVE +# define STATUS_JOURNAL_NOT_ACTIVE ((NTSTATUS) 0xC00002B8L) +#endif + +#ifndef STATUS_NOINTERFACE +# define STATUS_NOINTERFACE ((NTSTATUS) 0xC00002B9L) +#endif + +#ifndef STATUS_DS_ADMIN_LIMIT_EXCEEDED +# define STATUS_DS_ADMIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00002C1L) +#endif + +#ifndef STATUS_DRIVER_FAILED_SLEEP +# define STATUS_DRIVER_FAILED_SLEEP ((NTSTATUS) 0xC00002C2L) +#endif + +#ifndef STATUS_MUTUAL_AUTHENTICATION_FAILED +# define STATUS_MUTUAL_AUTHENTICATION_FAILED ((NTSTATUS) 0xC00002C3L) +#endif + +#ifndef STATUS_CORRUPT_SYSTEM_FILE +# define STATUS_CORRUPT_SYSTEM_FILE ((NTSTATUS) 0xC00002C4L) +#endif + +#ifndef STATUS_DATATYPE_MISALIGNMENT_ERROR +# define STATUS_DATATYPE_MISALIGNMENT_ERROR ((NTSTATUS) 0xC00002C5L) +#endif + +#ifndef STATUS_WMI_READ_ONLY +# define STATUS_WMI_READ_ONLY ((NTSTATUS) 0xC00002C6L) +#endif + +#ifndef STATUS_WMI_SET_FAILURE +# define STATUS_WMI_SET_FAILURE ((NTSTATUS) 0xC00002C7L) +#endif + +#ifndef STATUS_COMMITMENT_MINIMUM +# define STATUS_COMMITMENT_MINIMUM ((NTSTATUS) 0xC00002C8L) +#endif + +#ifndef STATUS_REG_NAT_CONSUMPTION +# define STATUS_REG_NAT_CONSUMPTION ((NTSTATUS) 0xC00002C9L) +#endif + +#ifndef STATUS_TRANSPORT_FULL +# define STATUS_TRANSPORT_FULL ((NTSTATUS) 0xC00002CAL) +#endif + +#ifndef STATUS_DS_SAM_INIT_FAILURE +# define STATUS_DS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002CBL) +#endif + +#ifndef STATUS_ONLY_IF_CONNECTED +# define STATUS_ONLY_IF_CONNECTED ((NTSTATUS) 0xC00002CCL) +#endif + +#ifndef STATUS_DS_SENSITIVE_GROUP_VIOLATION +# define STATUS_DS_SENSITIVE_GROUP_VIOLATION ((NTSTATUS) 0xC00002CDL) +#endif + +#ifndef STATUS_PNP_RESTART_ENUMERATION +# define STATUS_PNP_RESTART_ENUMERATION ((NTSTATUS) 0xC00002CEL) +#endif + +#ifndef STATUS_JOURNAL_ENTRY_DELETED +# define STATUS_JOURNAL_ENTRY_DELETED ((NTSTATUS) 0xC00002CFL) +#endif + +#ifndef STATUS_DS_CANT_MOD_PRIMARYGROUPID +# define STATUS_DS_CANT_MOD_PRIMARYGROUPID ((NTSTATUS) 0xC00002D0L) +#endif + +#ifndef STATUS_SYSTEM_IMAGE_BAD_SIGNATURE +# define STATUS_SYSTEM_IMAGE_BAD_SIGNATURE ((NTSTATUS) 0xC00002D1L) +#endif + +#ifndef STATUS_PNP_REBOOT_REQUIRED +# define STATUS_PNP_REBOOT_REQUIRED ((NTSTATUS) 0xC00002D2L) +#endif + +#ifndef STATUS_POWER_STATE_INVALID +# define STATUS_POWER_STATE_INVALID ((NTSTATUS) 0xC00002D3L) +#endif + +#ifndef STATUS_DS_INVALID_GROUP_TYPE +# define STATUS_DS_INVALID_GROUP_TYPE ((NTSTATUS) 0xC00002D4L) +#endif + +#ifndef STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN +# define STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D5L) +#endif + +#ifndef STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN +# define STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D6L) +#endif + +#ifndef STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER +# define STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D7L) +#endif + +#ifndef STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER +# define STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC00002D8L) +#endif + +#ifndef STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER +# define STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D9L) +#endif + +#ifndef STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER +# define STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER ((NTSTATUS) 0xC00002DAL) +#endif + +#ifndef STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER +# define STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER ((NTSTATUS) 0xC00002DBL) +#endif + +#ifndef STATUS_DS_HAVE_PRIMARY_MEMBERS +# define STATUS_DS_HAVE_PRIMARY_MEMBERS ((NTSTATUS) 0xC00002DCL) +#endif + +#ifndef STATUS_WMI_NOT_SUPPORTED +# define STATUS_WMI_NOT_SUPPORTED ((NTSTATUS) 0xC00002DDL) +#endif + +#ifndef STATUS_INSUFFICIENT_POWER +# define STATUS_INSUFFICIENT_POWER ((NTSTATUS) 0xC00002DEL) +#endif + +#ifndef STATUS_SAM_NEED_BOOTKEY_PASSWORD +# define STATUS_SAM_NEED_BOOTKEY_PASSWORD ((NTSTATUS) 0xC00002DFL) +#endif + +#ifndef STATUS_SAM_NEED_BOOTKEY_FLOPPY +# define STATUS_SAM_NEED_BOOTKEY_FLOPPY ((NTSTATUS) 0xC00002E0L) +#endif + +#ifndef STATUS_DS_CANT_START +# define STATUS_DS_CANT_START ((NTSTATUS) 0xC00002E1L) +#endif + +#ifndef STATUS_DS_INIT_FAILURE +# define STATUS_DS_INIT_FAILURE ((NTSTATUS) 0xC00002E2L) +#endif + +#ifndef STATUS_SAM_INIT_FAILURE +# define STATUS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002E3L) +#endif + +#ifndef STATUS_DS_GC_REQUIRED +# define STATUS_DS_GC_REQUIRED ((NTSTATUS) 0xC00002E4L) +#endif + +#ifndef STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY +# define STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY ((NTSTATUS) 0xC00002E5L) +#endif + +#ifndef STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS +# define STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS ((NTSTATUS) 0xC00002E6L) +#endif + +#ifndef STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED +# define STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED ((NTSTATUS) 0xC00002E7L) +#endif + +#ifndef STATUS_MULTIPLE_FAULT_VIOLATION +# define STATUS_MULTIPLE_FAULT_VIOLATION ((NTSTATUS) 0xC00002E8L) +#endif + +#ifndef STATUS_CURRENT_DOMAIN_NOT_ALLOWED +# define STATUS_CURRENT_DOMAIN_NOT_ALLOWED ((NTSTATUS) 0xC00002E9L) +#endif + +#ifndef STATUS_CANNOT_MAKE +# define STATUS_CANNOT_MAKE ((NTSTATUS) 0xC00002EAL) +#endif + +#ifndef STATUS_SYSTEM_SHUTDOWN +# define STATUS_SYSTEM_SHUTDOWN ((NTSTATUS) 0xC00002EBL) +#endif + +#ifndef STATUS_DS_INIT_FAILURE_CONSOLE +# define STATUS_DS_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002ECL) +#endif + +#ifndef STATUS_DS_SAM_INIT_FAILURE_CONSOLE +# define STATUS_DS_SAM_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002EDL) +#endif + +#ifndef STATUS_UNFINISHED_CONTEXT_DELETED +# define STATUS_UNFINISHED_CONTEXT_DELETED ((NTSTATUS) 0xC00002EEL) +#endif + +#ifndef STATUS_NO_TGT_REPLY +# define STATUS_NO_TGT_REPLY ((NTSTATUS) 0xC00002EFL) +#endif + +#ifndef STATUS_OBJECTID_NOT_FOUND +# define STATUS_OBJECTID_NOT_FOUND ((NTSTATUS) 0xC00002F0L) +#endif + +#ifndef STATUS_NO_IP_ADDRESSES +# define STATUS_NO_IP_ADDRESSES ((NTSTATUS) 0xC00002F1L) +#endif + +#ifndef STATUS_WRONG_CREDENTIAL_HANDLE +# define STATUS_WRONG_CREDENTIAL_HANDLE ((NTSTATUS) 0xC00002F2L) +#endif + +#ifndef STATUS_CRYPTO_SYSTEM_INVALID +# define STATUS_CRYPTO_SYSTEM_INVALID ((NTSTATUS) 0xC00002F3L) +#endif + +#ifndef STATUS_MAX_REFERRALS_EXCEEDED +# define STATUS_MAX_REFERRALS_EXCEEDED ((NTSTATUS) 0xC00002F4L) +#endif + +#ifndef STATUS_MUST_BE_KDC +# define STATUS_MUST_BE_KDC ((NTSTATUS) 0xC00002F5L) +#endif + +#ifndef STATUS_STRONG_CRYPTO_NOT_SUPPORTED +# define STATUS_STRONG_CRYPTO_NOT_SUPPORTED ((NTSTATUS) 0xC00002F6L) +#endif + +#ifndef STATUS_TOO_MANY_PRINCIPALS +# define STATUS_TOO_MANY_PRINCIPALS ((NTSTATUS) 0xC00002F7L) +#endif + +#ifndef STATUS_NO_PA_DATA +# define STATUS_NO_PA_DATA ((NTSTATUS) 0xC00002F8L) +#endif + +#ifndef STATUS_PKINIT_NAME_MISMATCH +# define STATUS_PKINIT_NAME_MISMATCH ((NTSTATUS) 0xC00002F9L) +#endif + +#ifndef STATUS_SMARTCARD_LOGON_REQUIRED +# define STATUS_SMARTCARD_LOGON_REQUIRED ((NTSTATUS) 0xC00002FAL) +#endif + +#ifndef STATUS_KDC_INVALID_REQUEST +# define STATUS_KDC_INVALID_REQUEST ((NTSTATUS) 0xC00002FBL) +#endif + +#ifndef STATUS_KDC_UNABLE_TO_REFER +# define STATUS_KDC_UNABLE_TO_REFER ((NTSTATUS) 0xC00002FCL) +#endif + +#ifndef STATUS_KDC_UNKNOWN_ETYPE +# define STATUS_KDC_UNKNOWN_ETYPE ((NTSTATUS) 0xC00002FDL) +#endif + +#ifndef STATUS_SHUTDOWN_IN_PROGRESS +# define STATUS_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FEL) +#endif + +#ifndef STATUS_SERVER_SHUTDOWN_IN_PROGRESS +# define STATUS_SERVER_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FFL) +#endif + +#ifndef STATUS_NOT_SUPPORTED_ON_SBS +# define STATUS_NOT_SUPPORTED_ON_SBS ((NTSTATUS) 0xC0000300L) +#endif + +#ifndef STATUS_WMI_GUID_DISCONNECTED +# define STATUS_WMI_GUID_DISCONNECTED ((NTSTATUS) 0xC0000301L) +#endif + +#ifndef STATUS_WMI_ALREADY_DISABLED +# define STATUS_WMI_ALREADY_DISABLED ((NTSTATUS) 0xC0000302L) +#endif + +#ifndef STATUS_WMI_ALREADY_ENABLED +# define STATUS_WMI_ALREADY_ENABLED ((NTSTATUS) 0xC0000303L) +#endif + +#ifndef STATUS_MFT_TOO_FRAGMENTED +# define STATUS_MFT_TOO_FRAGMENTED ((NTSTATUS) 0xC0000304L) +#endif + +#ifndef STATUS_COPY_PROTECTION_FAILURE +# define STATUS_COPY_PROTECTION_FAILURE ((NTSTATUS) 0xC0000305L) +#endif + +#ifndef STATUS_CSS_AUTHENTICATION_FAILURE +# define STATUS_CSS_AUTHENTICATION_FAILURE ((NTSTATUS) 0xC0000306L) +#endif + +#ifndef STATUS_CSS_KEY_NOT_PRESENT +# define STATUS_CSS_KEY_NOT_PRESENT ((NTSTATUS) 0xC0000307L) +#endif + +#ifndef STATUS_CSS_KEY_NOT_ESTABLISHED +# define STATUS_CSS_KEY_NOT_ESTABLISHED ((NTSTATUS) 0xC0000308L) +#endif + +#ifndef STATUS_CSS_SCRAMBLED_SECTOR +# define STATUS_CSS_SCRAMBLED_SECTOR ((NTSTATUS) 0xC0000309L) +#endif + +#ifndef STATUS_CSS_REGION_MISMATCH +# define STATUS_CSS_REGION_MISMATCH ((NTSTATUS) 0xC000030AL) +#endif + +#ifndef STATUS_CSS_RESETS_EXHAUSTED +# define STATUS_CSS_RESETS_EXHAUSTED ((NTSTATUS) 0xC000030BL) +#endif + +#ifndef STATUS_PKINIT_FAILURE +# define STATUS_PKINIT_FAILURE ((NTSTATUS) 0xC0000320L) +#endif + +#ifndef STATUS_SMARTCARD_SUBSYSTEM_FAILURE +# define STATUS_SMARTCARD_SUBSYSTEM_FAILURE ((NTSTATUS) 0xC0000321L) +#endif + +#ifndef STATUS_NO_KERB_KEY +# define STATUS_NO_KERB_KEY ((NTSTATUS) 0xC0000322L) +#endif + +#ifndef STATUS_HOST_DOWN +# define STATUS_HOST_DOWN ((NTSTATUS) 0xC0000350L) +#endif + +#ifndef STATUS_UNSUPPORTED_PREAUTH +# define STATUS_UNSUPPORTED_PREAUTH ((NTSTATUS) 0xC0000351L) +#endif + +#ifndef STATUS_EFS_ALG_BLOB_TOO_BIG +# define STATUS_EFS_ALG_BLOB_TOO_BIG ((NTSTATUS) 0xC0000352L) +#endif + +#ifndef STATUS_PORT_NOT_SET +# define STATUS_PORT_NOT_SET ((NTSTATUS) 0xC0000353L) +#endif + +#ifndef STATUS_DEBUGGER_INACTIVE +# define STATUS_DEBUGGER_INACTIVE ((NTSTATUS) 0xC0000354L) +#endif + +#ifndef STATUS_DS_VERSION_CHECK_FAILURE +# define STATUS_DS_VERSION_CHECK_FAILURE ((NTSTATUS) 0xC0000355L) +#endif + +#ifndef STATUS_AUDITING_DISABLED +# define STATUS_AUDITING_DISABLED ((NTSTATUS) 0xC0000356L) +#endif + +#ifndef STATUS_PRENT4_MACHINE_ACCOUNT +# define STATUS_PRENT4_MACHINE_ACCOUNT ((NTSTATUS) 0xC0000357L) +#endif + +#ifndef STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER +# define STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC0000358L) +#endif + +#ifndef STATUS_INVALID_IMAGE_WIN_32 +# define STATUS_INVALID_IMAGE_WIN_32 ((NTSTATUS) 0xC0000359L) +#endif + +#ifndef STATUS_INVALID_IMAGE_WIN_64 +# define STATUS_INVALID_IMAGE_WIN_64 ((NTSTATUS) 0xC000035AL) +#endif + +#ifndef STATUS_BAD_BINDINGS +# define STATUS_BAD_BINDINGS ((NTSTATUS) 0xC000035BL) +#endif + +#ifndef STATUS_NETWORK_SESSION_EXPIRED +# define STATUS_NETWORK_SESSION_EXPIRED ((NTSTATUS) 0xC000035CL) +#endif + +#ifndef STATUS_APPHELP_BLOCK +# define STATUS_APPHELP_BLOCK ((NTSTATUS) 0xC000035DL) +#endif + +#ifndef STATUS_ALL_SIDS_FILTERED +# define STATUS_ALL_SIDS_FILTERED ((NTSTATUS) 0xC000035EL) +#endif + +#ifndef STATUS_NOT_SAFE_MODE_DRIVER +# define STATUS_NOT_SAFE_MODE_DRIVER ((NTSTATUS) 0xC000035FL) +#endif + +#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT +# define STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT ((NTSTATUS) 0xC0000361L) +#endif + +#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PATH +# define STATUS_ACCESS_DISABLED_BY_POLICY_PATH ((NTSTATUS) 0xC0000362L) +#endif + +#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER +# define STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER ((NTSTATUS) 0xC0000363L) +#endif + +#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_OTHER +# define STATUS_ACCESS_DISABLED_BY_POLICY_OTHER ((NTSTATUS) 0xC0000364L) +#endif + +#ifndef STATUS_FAILED_DRIVER_ENTRY +# define STATUS_FAILED_DRIVER_ENTRY ((NTSTATUS) 0xC0000365L) +#endif + +#ifndef STATUS_DEVICE_ENUMERATION_ERROR +# define STATUS_DEVICE_ENUMERATION_ERROR ((NTSTATUS) 0xC0000366L) +#endif + +#ifndef STATUS_MOUNT_POINT_NOT_RESOLVED +# define STATUS_MOUNT_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000368L) +#endif + +#ifndef STATUS_INVALID_DEVICE_OBJECT_PARAMETER +# define STATUS_INVALID_DEVICE_OBJECT_PARAMETER ((NTSTATUS) 0xC0000369L) +#endif + +#ifndef STATUS_MCA_OCCURED +# define STATUS_MCA_OCCURED ((NTSTATUS) 0xC000036AL) +#endif + +#ifndef STATUS_DRIVER_BLOCKED_CRITICAL +# define STATUS_DRIVER_BLOCKED_CRITICAL ((NTSTATUS) 0xC000036BL) +#endif + +#ifndef STATUS_DRIVER_BLOCKED +# define STATUS_DRIVER_BLOCKED ((NTSTATUS) 0xC000036CL) +#endif + +#ifndef STATUS_DRIVER_DATABASE_ERROR +# define STATUS_DRIVER_DATABASE_ERROR ((NTSTATUS) 0xC000036DL) +#endif + +#ifndef STATUS_SYSTEM_HIVE_TOO_LARGE +# define STATUS_SYSTEM_HIVE_TOO_LARGE ((NTSTATUS) 0xC000036EL) +#endif + +#ifndef STATUS_INVALID_IMPORT_OF_NON_DLL +# define STATUS_INVALID_IMPORT_OF_NON_DLL ((NTSTATUS) 0xC000036FL) +#endif + +#ifndef STATUS_DS_SHUTTING_DOWN +# define STATUS_DS_SHUTTING_DOWN ((NTSTATUS) 0x40000370L) +#endif + +#ifndef STATUS_NO_SECRETS +# define STATUS_NO_SECRETS ((NTSTATUS) 0xC0000371L) +#endif + +#ifndef STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY +# define STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY ((NTSTATUS) 0xC0000372L) +#endif + +#ifndef STATUS_FAILED_STACK_SWITCH +# define STATUS_FAILED_STACK_SWITCH ((NTSTATUS) 0xC0000373L) +#endif + +#ifndef STATUS_HEAP_CORRUPTION +# define STATUS_HEAP_CORRUPTION ((NTSTATUS) 0xC0000374L) +#endif + +#ifndef STATUS_SMARTCARD_WRONG_PIN +# define STATUS_SMARTCARD_WRONG_PIN ((NTSTATUS) 0xC0000380L) +#endif + +#ifndef STATUS_SMARTCARD_CARD_BLOCKED +# define STATUS_SMARTCARD_CARD_BLOCKED ((NTSTATUS) 0xC0000381L) +#endif + +#ifndef STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED +# define STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED ((NTSTATUS) 0xC0000382L) +#endif + +#ifndef STATUS_SMARTCARD_NO_CARD +# define STATUS_SMARTCARD_NO_CARD ((NTSTATUS) 0xC0000383L) +#endif + +#ifndef STATUS_SMARTCARD_NO_KEY_CONTAINER +# define STATUS_SMARTCARD_NO_KEY_CONTAINER ((NTSTATUS) 0xC0000384L) +#endif + +#ifndef STATUS_SMARTCARD_NO_CERTIFICATE +# define STATUS_SMARTCARD_NO_CERTIFICATE ((NTSTATUS) 0xC0000385L) +#endif + +#ifndef STATUS_SMARTCARD_NO_KEYSET +# define STATUS_SMARTCARD_NO_KEYSET ((NTSTATUS) 0xC0000386L) +#endif + +#ifndef STATUS_SMARTCARD_IO_ERROR +# define STATUS_SMARTCARD_IO_ERROR ((NTSTATUS) 0xC0000387L) +#endif + +#ifndef STATUS_DOWNGRADE_DETECTED +# define STATUS_DOWNGRADE_DETECTED ((NTSTATUS) 0xC0000388L) +#endif + +#ifndef STATUS_SMARTCARD_CERT_REVOKED +# define STATUS_SMARTCARD_CERT_REVOKED ((NTSTATUS) 0xC0000389L) +#endif + +#ifndef STATUS_ISSUING_CA_UNTRUSTED +# define STATUS_ISSUING_CA_UNTRUSTED ((NTSTATUS) 0xC000038AL) +#endif + +#ifndef STATUS_REVOCATION_OFFLINE_C +# define STATUS_REVOCATION_OFFLINE_C ((NTSTATUS) 0xC000038BL) +#endif + +#ifndef STATUS_PKINIT_CLIENT_FAILURE +# define STATUS_PKINIT_CLIENT_FAILURE ((NTSTATUS) 0xC000038CL) +#endif + +#ifndef STATUS_SMARTCARD_CERT_EXPIRED +# define STATUS_SMARTCARD_CERT_EXPIRED ((NTSTATUS) 0xC000038DL) +#endif + +#ifndef STATUS_DRIVER_FAILED_PRIOR_UNLOAD +# define STATUS_DRIVER_FAILED_PRIOR_UNLOAD ((NTSTATUS) 0xC000038EL) +#endif + +#ifndef STATUS_SMARTCARD_SILENT_CONTEXT +# define STATUS_SMARTCARD_SILENT_CONTEXT ((NTSTATUS) 0xC000038FL) +#endif + +#ifndef STATUS_PER_USER_TRUST_QUOTA_EXCEEDED +# define STATUS_PER_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000401L) +#endif + +#ifndef STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED +# define STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000402L) +#endif + +#ifndef STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED +# define STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000403L) +#endif + +#ifndef STATUS_DS_NAME_NOT_UNIQUE +# define STATUS_DS_NAME_NOT_UNIQUE ((NTSTATUS) 0xC0000404L) +#endif + +#ifndef STATUS_DS_DUPLICATE_ID_FOUND +# define STATUS_DS_DUPLICATE_ID_FOUND ((NTSTATUS) 0xC0000405L) +#endif + +#ifndef STATUS_DS_GROUP_CONVERSION_ERROR +# define STATUS_DS_GROUP_CONVERSION_ERROR ((NTSTATUS) 0xC0000406L) +#endif + +#ifndef STATUS_VOLSNAP_PREPARE_HIBERNATE +# define STATUS_VOLSNAP_PREPARE_HIBERNATE ((NTSTATUS) 0xC0000407L) +#endif + +#ifndef STATUS_USER2USER_REQUIRED +# define STATUS_USER2USER_REQUIRED ((NTSTATUS) 0xC0000408L) +#endif + +#ifndef STATUS_STACK_BUFFER_OVERRUN +# define STATUS_STACK_BUFFER_OVERRUN ((NTSTATUS) 0xC0000409L) +#endif + +#ifndef STATUS_NO_S4U_PROT_SUPPORT +# define STATUS_NO_S4U_PROT_SUPPORT ((NTSTATUS) 0xC000040AL) +#endif + +#ifndef STATUS_CROSSREALM_DELEGATION_FAILURE +# define STATUS_CROSSREALM_DELEGATION_FAILURE ((NTSTATUS) 0xC000040BL) +#endif + +#ifndef STATUS_REVOCATION_OFFLINE_KDC +# define STATUS_REVOCATION_OFFLINE_KDC ((NTSTATUS) 0xC000040CL) +#endif + +#ifndef STATUS_ISSUING_CA_UNTRUSTED_KDC +# define STATUS_ISSUING_CA_UNTRUSTED_KDC ((NTSTATUS) 0xC000040DL) +#endif + +#ifndef STATUS_KDC_CERT_EXPIRED +# define STATUS_KDC_CERT_EXPIRED ((NTSTATUS) 0xC000040EL) +#endif + +#ifndef STATUS_KDC_CERT_REVOKED +# define STATUS_KDC_CERT_REVOKED ((NTSTATUS) 0xC000040FL) +#endif + +#ifndef STATUS_PARAMETER_QUOTA_EXCEEDED +# define STATUS_PARAMETER_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000410L) +#endif + +#ifndef STATUS_HIBERNATION_FAILURE +# define STATUS_HIBERNATION_FAILURE ((NTSTATUS) 0xC0000411L) +#endif + +#ifndef STATUS_DELAY_LOAD_FAILED +# define STATUS_DELAY_LOAD_FAILED ((NTSTATUS) 0xC0000412L) +#endif + +#ifndef STATUS_AUTHENTICATION_FIREWALL_FAILED +# define STATUS_AUTHENTICATION_FIREWALL_FAILED ((NTSTATUS) 0xC0000413L) +#endif + +#ifndef STATUS_VDM_DISALLOWED +# define STATUS_VDM_DISALLOWED ((NTSTATUS) 0xC0000414L) +#endif + +#ifndef STATUS_HUNG_DISPLAY_DRIVER_THREAD +# define STATUS_HUNG_DISPLAY_DRIVER_THREAD ((NTSTATUS) 0xC0000415L) +#endif + +#ifndef STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE +# define STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE ((NTSTATUS) 0xC0000416L) +#endif + +#ifndef STATUS_INVALID_CRUNTIME_PARAMETER +# define STATUS_INVALID_CRUNTIME_PARAMETER ((NTSTATUS) 0xC0000417L) +#endif + +#ifndef STATUS_NTLM_BLOCKED +# define STATUS_NTLM_BLOCKED ((NTSTATUS) 0xC0000418L) +#endif + +#ifndef STATUS_DS_SRC_SID_EXISTS_IN_FOREST +# define STATUS_DS_SRC_SID_EXISTS_IN_FOREST ((NTSTATUS) 0xC0000419L) +#endif + +#ifndef STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST +# define STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041AL) +#endif + +#ifndef STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST +# define STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041BL) +#endif + +#ifndef STATUS_INVALID_USER_PRINCIPAL_NAME +# define STATUS_INVALID_USER_PRINCIPAL_NAME ((NTSTATUS) 0xC000041CL) +#endif + +#ifndef STATUS_FATAL_USER_CALLBACK_EXCEPTION +# define STATUS_FATAL_USER_CALLBACK_EXCEPTION ((NTSTATUS) 0xC000041DL) +#endif + +#ifndef STATUS_ASSERTION_FAILURE +# define STATUS_ASSERTION_FAILURE ((NTSTATUS) 0xC0000420L) +#endif + +#ifndef STATUS_VERIFIER_STOP +# define STATUS_VERIFIER_STOP ((NTSTATUS) 0xC0000421L) +#endif + +#ifndef STATUS_CALLBACK_POP_STACK +# define STATUS_CALLBACK_POP_STACK ((NTSTATUS) 0xC0000423L) +#endif + +#ifndef STATUS_INCOMPATIBLE_DRIVER_BLOCKED +# define STATUS_INCOMPATIBLE_DRIVER_BLOCKED ((NTSTATUS) 0xC0000424L) +#endif + +#ifndef STATUS_HIVE_UNLOADED +# define STATUS_HIVE_UNLOADED ((NTSTATUS) 0xC0000425L) +#endif + +#ifndef STATUS_COMPRESSION_DISABLED +# define STATUS_COMPRESSION_DISABLED ((NTSTATUS) 0xC0000426L) +#endif + +#ifndef STATUS_FILE_SYSTEM_LIMITATION +# define STATUS_FILE_SYSTEM_LIMITATION ((NTSTATUS) 0xC0000427L) +#endif + +#ifndef STATUS_INVALID_IMAGE_HASH +# define STATUS_INVALID_IMAGE_HASH ((NTSTATUS) 0xC0000428L) +#endif + +#ifndef STATUS_NOT_CAPABLE +# define STATUS_NOT_CAPABLE ((NTSTATUS) 0xC0000429L) +#endif + +#ifndef STATUS_REQUEST_OUT_OF_SEQUENCE +# define STATUS_REQUEST_OUT_OF_SEQUENCE ((NTSTATUS) 0xC000042AL) +#endif + +#ifndef STATUS_IMPLEMENTATION_LIMIT +# define STATUS_IMPLEMENTATION_LIMIT ((NTSTATUS) 0xC000042BL) +#endif + +#ifndef STATUS_ELEVATION_REQUIRED +# define STATUS_ELEVATION_REQUIRED ((NTSTATUS) 0xC000042CL) +#endif + +#ifndef STATUS_NO_SECURITY_CONTEXT +# define STATUS_NO_SECURITY_CONTEXT ((NTSTATUS) 0xC000042DL) +#endif + +#ifndef STATUS_PKU2U_CERT_FAILURE +# define STATUS_PKU2U_CERT_FAILURE ((NTSTATUS) 0xC000042FL) +#endif + +#ifndef STATUS_BEYOND_VDL +# define STATUS_BEYOND_VDL ((NTSTATUS) 0xC0000432L) +#endif + +#ifndef STATUS_ENCOUNTERED_WRITE_IN_PROGRESS +# define STATUS_ENCOUNTERED_WRITE_IN_PROGRESS ((NTSTATUS) 0xC0000433L) +#endif + +#ifndef STATUS_PTE_CHANGED +# define STATUS_PTE_CHANGED ((NTSTATUS) 0xC0000434L) +#endif + +#ifndef STATUS_PURGE_FAILED +# define STATUS_PURGE_FAILED ((NTSTATUS) 0xC0000435L) +#endif + +#ifndef STATUS_CRED_REQUIRES_CONFIRMATION +# define STATUS_CRED_REQUIRES_CONFIRMATION ((NTSTATUS) 0xC0000440L) +#endif + +#ifndef STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE +# define STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE ((NTSTATUS) 0xC0000441L) +#endif + +#ifndef STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER +# define STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER ((NTSTATUS) 0xC0000442L) +#endif + +#ifndef STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE +# define STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE ((NTSTATUS) 0xC0000443L) +#endif + +#ifndef STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE +# define STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE ((NTSTATUS) 0xC0000444L) +#endif + +#ifndef STATUS_CS_ENCRYPTION_FILE_NOT_CSE +# define STATUS_CS_ENCRYPTION_FILE_NOT_CSE ((NTSTATUS) 0xC0000445L) +#endif + +#ifndef STATUS_INVALID_LABEL +# define STATUS_INVALID_LABEL ((NTSTATUS) 0xC0000446L) +#endif + +#ifndef STATUS_DRIVER_PROCESS_TERMINATED +# define STATUS_DRIVER_PROCESS_TERMINATED ((NTSTATUS) 0xC0000450L) +#endif + +#ifndef STATUS_AMBIGUOUS_SYSTEM_DEVICE +# define STATUS_AMBIGUOUS_SYSTEM_DEVICE ((NTSTATUS) 0xC0000451L) +#endif + +#ifndef STATUS_SYSTEM_DEVICE_NOT_FOUND +# define STATUS_SYSTEM_DEVICE_NOT_FOUND ((NTSTATUS) 0xC0000452L) +#endif + +#ifndef STATUS_RESTART_BOOT_APPLICATION +# define STATUS_RESTART_BOOT_APPLICATION ((NTSTATUS) 0xC0000453L) +#endif + +#ifndef STATUS_INSUFFICIENT_NVRAM_RESOURCES +# define STATUS_INSUFFICIENT_NVRAM_RESOURCES ((NTSTATUS) 0xC0000454L) +#endif + +#ifndef STATUS_INVALID_TASK_NAME +# define STATUS_INVALID_TASK_NAME ((NTSTATUS) 0xC0000500L) +#endif + +#ifndef STATUS_INVALID_TASK_INDEX +# define STATUS_INVALID_TASK_INDEX ((NTSTATUS) 0xC0000501L) +#endif + +#ifndef STATUS_THREAD_ALREADY_IN_TASK +# define STATUS_THREAD_ALREADY_IN_TASK ((NTSTATUS) 0xC0000502L) +#endif + +#ifndef STATUS_CALLBACK_BYPASS +# define STATUS_CALLBACK_BYPASS ((NTSTATUS) 0xC0000503L) +#endif + +#ifndef STATUS_FAIL_FAST_EXCEPTION +# define STATUS_FAIL_FAST_EXCEPTION ((NTSTATUS) 0xC0000602L) +#endif + +#ifndef STATUS_IMAGE_CERT_REVOKED +# define STATUS_IMAGE_CERT_REVOKED ((NTSTATUS) 0xC0000603L) +#endif + +#ifndef STATUS_PORT_CLOSED +# define STATUS_PORT_CLOSED ((NTSTATUS) 0xC0000700L) +#endif + +#ifndef STATUS_MESSAGE_LOST +# define STATUS_MESSAGE_LOST ((NTSTATUS) 0xC0000701L) +#endif + +#ifndef STATUS_INVALID_MESSAGE +# define STATUS_INVALID_MESSAGE ((NTSTATUS) 0xC0000702L) +#endif + +#ifndef STATUS_REQUEST_CANCELED +# define STATUS_REQUEST_CANCELED ((NTSTATUS) 0xC0000703L) +#endif + +#ifndef STATUS_RECURSIVE_DISPATCH +# define STATUS_RECURSIVE_DISPATCH ((NTSTATUS) 0xC0000704L) +#endif + +#ifndef STATUS_LPC_RECEIVE_BUFFER_EXPECTED +# define STATUS_LPC_RECEIVE_BUFFER_EXPECTED ((NTSTATUS) 0xC0000705L) +#endif + +#ifndef STATUS_LPC_INVALID_CONNECTION_USAGE +# define STATUS_LPC_INVALID_CONNECTION_USAGE ((NTSTATUS) 0xC0000706L) +#endif + +#ifndef STATUS_LPC_REQUESTS_NOT_ALLOWED +# define STATUS_LPC_REQUESTS_NOT_ALLOWED ((NTSTATUS) 0xC0000707L) +#endif + +#ifndef STATUS_RESOURCE_IN_USE +# define STATUS_RESOURCE_IN_USE ((NTSTATUS) 0xC0000708L) +#endif + +#ifndef STATUS_HARDWARE_MEMORY_ERROR +# define STATUS_HARDWARE_MEMORY_ERROR ((NTSTATUS) 0xC0000709L) +#endif + +#ifndef STATUS_THREADPOOL_HANDLE_EXCEPTION +# define STATUS_THREADPOOL_HANDLE_EXCEPTION ((NTSTATUS) 0xC000070AL) +#endif + +#ifndef STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED +# define STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070BL) +#endif + +#ifndef STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED +# define STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070CL) +#endif + +#ifndef STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED +# define STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070DL) +#endif + +#ifndef STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED +# define STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070EL) +#endif + +#ifndef STATUS_THREADPOOL_RELEASED_DURING_OPERATION +# define STATUS_THREADPOOL_RELEASED_DURING_OPERATION ((NTSTATUS) 0xC000070FL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING +# define STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000710L) +#endif + +#ifndef STATUS_APC_RETURNED_WHILE_IMPERSONATING +# define STATUS_APC_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000711L) +#endif + +#ifndef STATUS_PROCESS_IS_PROTECTED +# define STATUS_PROCESS_IS_PROTECTED ((NTSTATUS) 0xC0000712L) +#endif + +#ifndef STATUS_MCA_EXCEPTION +# define STATUS_MCA_EXCEPTION ((NTSTATUS) 0xC0000713L) +#endif + +#ifndef STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE +# define STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE ((NTSTATUS) 0xC0000714L) +#endif + +#ifndef STATUS_SYMLINK_CLASS_DISABLED +# define STATUS_SYMLINK_CLASS_DISABLED ((NTSTATUS) 0xC0000715L) +#endif + +#ifndef STATUS_INVALID_IDN_NORMALIZATION +# define STATUS_INVALID_IDN_NORMALIZATION ((NTSTATUS) 0xC0000716L) +#endif + +#ifndef STATUS_NO_UNICODE_TRANSLATION +# define STATUS_NO_UNICODE_TRANSLATION ((NTSTATUS) 0xC0000717L) +#endif + +#ifndef STATUS_ALREADY_REGISTERED +# define STATUS_ALREADY_REGISTERED ((NTSTATUS) 0xC0000718L) +#endif + +#ifndef STATUS_CONTEXT_MISMATCH +# define STATUS_CONTEXT_MISMATCH ((NTSTATUS) 0xC0000719L) +#endif + +#ifndef STATUS_PORT_ALREADY_HAS_COMPLETION_LIST +# define STATUS_PORT_ALREADY_HAS_COMPLETION_LIST ((NTSTATUS) 0xC000071AL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_THREAD_PRIORITY +# define STATUS_CALLBACK_RETURNED_THREAD_PRIORITY ((NTSTATUS) 0xC000071BL) +#endif + +#ifndef STATUS_INVALID_THREAD +# define STATUS_INVALID_THREAD ((NTSTATUS) 0xC000071CL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_TRANSACTION +# define STATUS_CALLBACK_RETURNED_TRANSACTION ((NTSTATUS) 0xC000071DL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_LDR_LOCK +# define STATUS_CALLBACK_RETURNED_LDR_LOCK ((NTSTATUS) 0xC000071EL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_LANG +# define STATUS_CALLBACK_RETURNED_LANG ((NTSTATUS) 0xC000071FL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_PRI_BACK +# define STATUS_CALLBACK_RETURNED_PRI_BACK ((NTSTATUS) 0xC0000720L) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_THREAD_AFFINITY +# define STATUS_CALLBACK_RETURNED_THREAD_AFFINITY ((NTSTATUS) 0xC0000721L) +#endif + +#ifndef STATUS_DISK_REPAIR_DISABLED +# define STATUS_DISK_REPAIR_DISABLED ((NTSTATUS) 0xC0000800L) +#endif + +#ifndef STATUS_DS_DOMAIN_RENAME_IN_PROGRESS +# define STATUS_DS_DOMAIN_RENAME_IN_PROGRESS ((NTSTATUS) 0xC0000801L) +#endif + +#ifndef STATUS_DISK_QUOTA_EXCEEDED +# define STATUS_DISK_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000802L) +#endif + +#ifndef STATUS_DATA_LOST_REPAIR +# define STATUS_DATA_LOST_REPAIR ((NTSTATUS) 0x80000803L) +#endif + +#ifndef STATUS_CONTENT_BLOCKED +# define STATUS_CONTENT_BLOCKED ((NTSTATUS) 0xC0000804L) +#endif + +#ifndef STATUS_BAD_CLUSTERS +# define STATUS_BAD_CLUSTERS ((NTSTATUS) 0xC0000805L) +#endif + +#ifndef STATUS_VOLUME_DIRTY +# define STATUS_VOLUME_DIRTY ((NTSTATUS) 0xC0000806L) +#endif + +#ifndef STATUS_FILE_CHECKED_OUT +# define STATUS_FILE_CHECKED_OUT ((NTSTATUS) 0xC0000901L) +#endif + +#ifndef STATUS_CHECKOUT_REQUIRED +# define STATUS_CHECKOUT_REQUIRED ((NTSTATUS) 0xC0000902L) +#endif + +#ifndef STATUS_BAD_FILE_TYPE +# define STATUS_BAD_FILE_TYPE ((NTSTATUS) 0xC0000903L) +#endif + +#ifndef STATUS_FILE_TOO_LARGE +# define STATUS_FILE_TOO_LARGE ((NTSTATUS) 0xC0000904L) +#endif + +#ifndef STATUS_FORMS_AUTH_REQUIRED +# define STATUS_FORMS_AUTH_REQUIRED ((NTSTATUS) 0xC0000905L) +#endif + +#ifndef STATUS_VIRUS_INFECTED +# define STATUS_VIRUS_INFECTED ((NTSTATUS) 0xC0000906L) +#endif + +#ifndef STATUS_VIRUS_DELETED +# define STATUS_VIRUS_DELETED ((NTSTATUS) 0xC0000907L) +#endif + +#ifndef STATUS_BAD_MCFG_TABLE +# define STATUS_BAD_MCFG_TABLE ((NTSTATUS) 0xC0000908L) +#endif + +#ifndef STATUS_CANNOT_BREAK_OPLOCK +# define STATUS_CANNOT_BREAK_OPLOCK ((NTSTATUS) 0xC0000909L) +#endif + +#ifndef STATUS_WOW_ASSERTION +# define STATUS_WOW_ASSERTION ((NTSTATUS) 0xC0009898L) +#endif + +#ifndef STATUS_INVALID_SIGNATURE +# define STATUS_INVALID_SIGNATURE ((NTSTATUS) 0xC000A000L) +#endif + +#ifndef STATUS_HMAC_NOT_SUPPORTED +# define STATUS_HMAC_NOT_SUPPORTED ((NTSTATUS) 0xC000A001L) +#endif + +#ifndef STATUS_AUTH_TAG_MISMATCH +# define STATUS_AUTH_TAG_MISMATCH ((NTSTATUS) 0xC000A002L) +#endif + +#ifndef STATUS_IPSEC_QUEUE_OVERFLOW +# define STATUS_IPSEC_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A010L) +#endif + +#ifndef STATUS_ND_QUEUE_OVERFLOW +# define STATUS_ND_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A011L) +#endif + +#ifndef STATUS_HOPLIMIT_EXCEEDED +# define STATUS_HOPLIMIT_EXCEEDED ((NTSTATUS) 0xC000A012L) +#endif + +#ifndef STATUS_PROTOCOL_NOT_SUPPORTED +# define STATUS_PROTOCOL_NOT_SUPPORTED ((NTSTATUS) 0xC000A013L) +#endif + +#ifndef STATUS_FASTPATH_REJECTED +# define STATUS_FASTPATH_REJECTED ((NTSTATUS) 0xC000A014L) +#endif + +#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED +# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED ((NTSTATUS) 0xC000A080L) +#endif + +#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR +# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR ((NTSTATUS) 0xC000A081L) +#endif + +#ifndef STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR +# define STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR ((NTSTATUS) 0xC000A082L) +#endif + +#ifndef STATUS_XML_PARSE_ERROR +# define STATUS_XML_PARSE_ERROR ((NTSTATUS) 0xC000A083L) +#endif + +#ifndef STATUS_XMLDSIG_ERROR +# define STATUS_XMLDSIG_ERROR ((NTSTATUS) 0xC000A084L) +#endif + +#ifndef STATUS_WRONG_COMPARTMENT +# define STATUS_WRONG_COMPARTMENT ((NTSTATUS) 0xC000A085L) +#endif + +#ifndef STATUS_AUTHIP_FAILURE +# define STATUS_AUTHIP_FAILURE ((NTSTATUS) 0xC000A086L) +#endif + +#ifndef STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS +# define STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS ((NTSTATUS) 0xC000A087L) +#endif + +#ifndef STATUS_DS_OID_NOT_FOUND +# define STATUS_DS_OID_NOT_FOUND ((NTSTATUS) 0xC000A088L) +#endif + +#ifndef STATUS_HASH_NOT_SUPPORTED +# define STATUS_HASH_NOT_SUPPORTED ((NTSTATUS) 0xC000A100L) +#endif + +#ifndef STATUS_HASH_NOT_PRESENT +# define STATUS_HASH_NOT_PRESENT ((NTSTATUS) 0xC000A101L) +#endif + +/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the */ +/* DDK got it wrong! */ +#ifdef NTSTATUS_FROM_WIN32 +# undef NTSTATUS_FROM_WIN32 +#endif +#define NTSTATUS_FROM_WIN32(error) ((NTSTATUS) (error) <= 0 ? \ + ((NTSTATUS) (error)) : ((NTSTATUS) (((error) & 0x0000FFFF) | \ + (FACILITY_NTWIN32 << 16) | ERROR_SEVERITY_WARNING))) + +#ifndef JOB_OBJECT_LIMIT_PROCESS_MEMORY +# define JOB_OBJECT_LIMIT_PROCESS_MEMORY 0x00000100 +#endif +#ifndef JOB_OBJECT_LIMIT_JOB_MEMORY +# define JOB_OBJECT_LIMIT_JOB_MEMORY 0x00000200 +#endif +#ifndef JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION +# define JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x00000400 +#endif +#ifndef JOB_OBJECT_LIMIT_BREAKAWAY_OK +# define JOB_OBJECT_LIMIT_BREAKAWAY_OK 0x00000800 +#endif +#ifndef JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK +# define JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 0x00001000 +#endif +#ifndef JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE +# define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000 +#endif + +/* from winternl.h */ +typedef struct _UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING, *PUNICODE_STRING; + +typedef const UNICODE_STRING *PCUNICODE_STRING; + +/* from ntifs.h */ +#ifndef DEVICE_TYPE +# define DEVICE_TYPE DWORD +#endif + +/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does + * not. + */ +#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) + typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + } DUMMYUNIONNAME; + } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; +#endif + +typedef struct _IO_STATUS_BLOCK { + union { + NTSTATUS Status; + PVOID Pointer; + } DUMMYUNIONNAME; + ULONG_PTR Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + +typedef enum _FILE_INFORMATION_CLASS { + FileDirectoryInformation = 1, + FileFullDirectoryInformation, + FileBothDirectoryInformation, + FileBasicInformation, + FileStandardInformation, + FileInternalInformation, + FileEaInformation, + FileAccessInformation, + FileNameInformation, + FileRenameInformation, + FileLinkInformation, + FileNamesInformation, + FileDispositionInformation, + FilePositionInformation, + FileFullEaInformation, + FileModeInformation, + FileAlignmentInformation, + FileAllInformation, + FileAllocationInformation, + FileEndOfFileInformation, + FileAlternateNameInformation, + FileStreamInformation, + FilePipeInformation, + FilePipeLocalInformation, + FilePipeRemoteInformation, + FileMailslotQueryInformation, + FileMailslotSetInformation, + FileCompressionInformation, + FileObjectIdInformation, + FileCompletionInformation, + FileMoveClusterInformation, + FileQuotaInformation, + FileReparsePointInformation, + FileNetworkOpenInformation, + FileAttributeTagInformation, + FileTrackingInformation, + FileIdBothDirectoryInformation, + FileIdFullDirectoryInformation, + FileValidDataLengthInformation, + FileShortNameInformation, + FileIoCompletionNotificationInformation, + FileIoStatusBlockRangeInformation, + FileIoPriorityHintInformation, + FileSfioReserveInformation, + FileSfioVolumeInformation, + FileHardLinkInformation, + FileProcessIdsUsingFileInformation, + FileNormalizedNameInformation, + FileNetworkPhysicalNameInformation, + FileIdGlobalTxDirectoryInformation, + FileIsRemoteDeviceInformation, + FileAttributeCacheInformation, + FileNumaNodeInformation, + FileStandardLinkInformation, + FileRemoteProtocolInformation, + FileMaximumInformation +} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; + +typedef struct _FILE_DIRECTORY_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION; + +typedef struct _FILE_BOTH_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[1]; +} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; + +typedef struct _FILE_BASIC_INFORMATION { + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + DWORD FileAttributes; +} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; + +typedef struct _FILE_STANDARD_INFORMATION { + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; + +typedef struct _FILE_INTERNAL_INFORMATION { + LARGE_INTEGER IndexNumber; +} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION; + +typedef struct _FILE_EA_INFORMATION { + ULONG EaSize; +} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION; + +typedef struct _FILE_ACCESS_INFORMATION { + ACCESS_MASK AccessFlags; +} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION; + +typedef struct _FILE_POSITION_INFORMATION { + LARGE_INTEGER CurrentByteOffset; +} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; + +typedef struct _FILE_MODE_INFORMATION { + ULONG Mode; +} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION; + +typedef struct _FILE_ALIGNMENT_INFORMATION { + ULONG AlignmentRequirement; +} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION; + +typedef struct _FILE_NAME_INFORMATION { + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; + +typedef struct _FILE_END_OF_FILE_INFORMATION { + LARGE_INTEGER EndOfFile; +} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; + +typedef struct _FILE_ALL_INFORMATION { + FILE_BASIC_INFORMATION BasicInformation; + FILE_STANDARD_INFORMATION StandardInformation; + FILE_INTERNAL_INFORMATION InternalInformation; + FILE_EA_INFORMATION EaInformation; + FILE_ACCESS_INFORMATION AccessInformation; + FILE_POSITION_INFORMATION PositionInformation; + FILE_MODE_INFORMATION ModeInformation; + FILE_ALIGNMENT_INFORMATION AlignmentInformation; + FILE_NAME_INFORMATION NameInformation; +} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION; + +typedef struct _FILE_DISPOSITION_INFORMATION { + BOOLEAN DeleteFile; +} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION; + +typedef struct _FILE_PIPE_LOCAL_INFORMATION { + ULONG NamedPipeType; + ULONG NamedPipeConfiguration; + ULONG MaximumInstances; + ULONG CurrentInstances; + ULONG InboundQuota; + ULONG ReadDataAvailable; + ULONG OutboundQuota; + ULONG WriteQuotaAvailable; + ULONG NamedPipeState; + ULONG NamedPipeEnd; +} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION; + +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 + +typedef enum _FS_INFORMATION_CLASS { + FileFsVolumeInformation = 1, + FileFsLabelInformation = 2, + FileFsSizeInformation = 3, + FileFsDeviceInformation = 4, + FileFsAttributeInformation = 5, + FileFsControlInformation = 6, + FileFsFullSizeInformation = 7, + FileFsObjectIdInformation = 8, + FileFsDriverPathInformation = 9, + FileFsVolumeFlagsInformation = 10, + FileFsSectorSizeInformation = 11 +} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; + +typedef struct _FILE_FS_VOLUME_INFORMATION { + LARGE_INTEGER VolumeCreationTime; + ULONG VolumeSerialNumber; + ULONG VolumeLabelLength; + BOOLEAN SupportsObjects; + WCHAR VolumeLabel[1]; +} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION; + +typedef struct _FILE_FS_LABEL_INFORMATION { + ULONG VolumeLabelLength; + WCHAR VolumeLabel[1]; +} FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION; + +typedef struct _FILE_FS_SIZE_INFORMATION { + LARGE_INTEGER TotalAllocationUnits; + LARGE_INTEGER AvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION; + +typedef struct _FILE_FS_DEVICE_INFORMATION { + DEVICE_TYPE DeviceType; + ULONG Characteristics; +} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION; + +typedef struct _FILE_FS_ATTRIBUTE_INFORMATION { + ULONG FileSystemAttributes; + LONG MaximumComponentNameLength; + ULONG FileSystemNameLength; + WCHAR FileSystemName[1]; +} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION; + +typedef struct _FILE_FS_CONTROL_INFORMATION { + LARGE_INTEGER FreeSpaceStartFiltering; + LARGE_INTEGER FreeSpaceThreshold; + LARGE_INTEGER FreeSpaceStopFiltering; + LARGE_INTEGER DefaultQuotaThreshold; + LARGE_INTEGER DefaultQuotaLimit; + ULONG FileSystemControlFlags; +} FILE_FS_CONTROL_INFORMATION, *PFILE_FS_CONTROL_INFORMATION; + +typedef struct _FILE_FS_FULL_SIZE_INFORMATION { + LARGE_INTEGER TotalAllocationUnits; + LARGE_INTEGER CallerAvailableAllocationUnits; + LARGE_INTEGER ActualAvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION; + +typedef struct _FILE_FS_OBJECTID_INFORMATION { + UCHAR ObjectId[16]; + UCHAR ExtendedInfo[48]; +} FILE_FS_OBJECTID_INFORMATION, *PFILE_FS_OBJECTID_INFORMATION; + +typedef struct _FILE_FS_DRIVER_PATH_INFORMATION { + BOOLEAN DriverInPath; + ULONG DriverNameLength; + WCHAR DriverName[1]; +} FILE_FS_DRIVER_PATH_INFORMATION, *PFILE_FS_DRIVER_PATH_INFORMATION; + +typedef struct _FILE_FS_VOLUME_FLAGS_INFORMATION { + ULONG Flags; +} FILE_FS_VOLUME_FLAGS_INFORMATION, *PFILE_FS_VOLUME_FLAGS_INFORMATION; + +typedef struct _FILE_FS_SECTOR_SIZE_INFORMATION { + ULONG LogicalBytesPerSector; + ULONG PhysicalBytesPerSectorForAtomicity; + ULONG PhysicalBytesPerSectorForPerformance; + ULONG FileSystemEffectivePhysicalBytesPerSectorForAtomicity; + ULONG Flags; + ULONG ByteOffsetForSectorAlignment; + ULONG ByteOffsetForPartitionAlignment; +} FILE_FS_SECTOR_SIZE_INFORMATION, *PFILE_FS_SECTOR_SIZE_INFORMATION; + +typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; + LARGE_INTEGER InterruptTime; + ULONG InterruptCount; +} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; + +#ifndef SystemProcessorPerformanceInformation +# define SystemProcessorPerformanceInformation 8 +#endif + +#ifndef FILE_DEVICE_FILE_SYSTEM +# define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#endif + +#ifndef FILE_DEVICE_NETWORK +# define FILE_DEVICE_NETWORK 0x00000012 +#endif + +#ifndef METHOD_BUFFERED +# define METHOD_BUFFERED 0 +#endif + +#ifndef METHOD_IN_DIRECT +# define METHOD_IN_DIRECT 1 +#endif + +#ifndef METHOD_OUT_DIRECT +# define METHOD_OUT_DIRECT 2 +#endif + +#ifndef METHOD_NEITHER +#define METHOD_NEITHER 3 +#endif + +#ifndef METHOD_DIRECT_TO_HARDWARE +# define METHOD_DIRECT_TO_HARDWARE METHOD_IN_DIRECT +#endif + +#ifndef METHOD_DIRECT_FROM_HARDWARE +# define METHOD_DIRECT_FROM_HARDWARE METHOD_OUT_DIRECT +#endif + +#ifndef FILE_ANY_ACCESS +# define FILE_ANY_ACCESS 0 +#endif + +#ifndef FILE_SPECIAL_ACCESS +# define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) +#endif + +#ifndef FILE_READ_ACCESS +# define FILE_READ_ACCESS 0x0001 +#endif + +#ifndef FILE_WRITE_ACCESS +# define FILE_WRITE_ACCESS 0x0002 +#endif + +#ifndef CTL_CODE +# define CTL_CODE(device_type, function, method, access) \ + (((device_type) << 16) | ((access) << 14) | ((function) << 2) | (method)) +#endif + +#ifndef FSCTL_SET_REPARSE_POINT +# define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \ + 41, \ + METHOD_BUFFERED, \ + FILE_SPECIAL_ACCESS) +#endif + +#ifndef FSCTL_GET_REPARSE_POINT +# define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \ + 42, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) +#endif + +#ifndef FSCTL_DELETE_REPARSE_POINT +# define FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \ + 43, \ + METHOD_BUFFERED, \ + FILE_SPECIAL_ACCESS) +#endif + +#ifndef IO_REPARSE_TAG_SYMLINK +# define IO_REPARSE_TAG_SYMLINK (0xA000000CL) +#endif + +typedef VOID (NTAPI *PIO_APC_ROUTINE) + (PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG Reserved); + +typedef ULONG (NTAPI *sRtlNtStatusToDosError) + (NTSTATUS Status); + +typedef NTSTATUS (NTAPI *sNtDeviceIoControlFile) + (HANDLE FileHandle, + HANDLE Event, + PIO_APC_ROUTINE ApcRoutine, + PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG IoControlCode, + PVOID InputBuffer, + ULONG InputBufferLength, + PVOID OutputBuffer, + ULONG OutputBufferLength); + +typedef NTSTATUS (NTAPI *sNtQueryInformationFile) + (HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass); + +typedef NTSTATUS (NTAPI *sNtSetInformationFile) + (HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass); + +typedef NTSTATUS (NTAPI *sNtQueryVolumeInformationFile) + (HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FsInformation, + ULONG Length, + FS_INFORMATION_CLASS FsInformationClass); + +typedef NTSTATUS (NTAPI *sNtQuerySystemInformation) + (UINT SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength); + +typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile) + (HANDLE FileHandle, + HANDLE Event, + PIO_APC_ROUTINE ApcRoutine, + PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass, + BOOLEAN ReturnSingleEntry, + PUNICODE_STRING FileName, + BOOLEAN RestartScan + ); + +/* + * Kernel32 headers + */ +#ifndef FILE_SKIP_COMPLETION_PORT_ON_SUCCESS +# define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1 +#endif + +#ifndef FILE_SKIP_SET_EVENT_ON_HANDLE +# define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2 +#endif + +#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY +# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 +#endif + +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) + typedef struct _OVERLAPPED_ENTRY { + ULONG_PTR lpCompletionKey; + LPOVERLAPPED lpOverlapped; + ULONG_PTR Internal; + DWORD dwNumberOfBytesTransferred; + } OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY; +#endif + +/* from wincon.h */ +#ifndef ENABLE_INSERT_MODE +# define ENABLE_INSERT_MODE 0x20 +#endif + +#ifndef ENABLE_QUICK_EDIT_MODE +# define ENABLE_QUICK_EDIT_MODE 0x40 +#endif + +#ifndef ENABLE_EXTENDED_FLAGS +# define ENABLE_EXTENDED_FLAGS 0x80 +#endif + +/* from winerror.h */ +#ifndef ERROR_SYMLINK_NOT_SUPPORTED +# define ERROR_SYMLINK_NOT_SUPPORTED 1464 +#endif + +#ifndef ERROR_MUI_FILE_NOT_FOUND +# define ERROR_MUI_FILE_NOT_FOUND 15100 +#endif + +#ifndef ERROR_MUI_INVALID_FILE +# define ERROR_MUI_INVALID_FILE 15101 +#endif + +#ifndef ERROR_MUI_INVALID_RC_CONFIG +# define ERROR_MUI_INVALID_RC_CONFIG 15102 +#endif + +#ifndef ERROR_MUI_INVALID_LOCALE_NAME +# define ERROR_MUI_INVALID_LOCALE_NAME 15103 +#endif + +#ifndef ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME +# define ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME 15104 +#endif + +#ifndef ERROR_MUI_FILE_NOT_LOADED +# define ERROR_MUI_FILE_NOT_LOADED 15105 +#endif + +typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx) + (HANDLE CompletionPort, + LPOVERLAPPED_ENTRY lpCompletionPortEntries, + ULONG ulCount, + PULONG ulNumEntriesRemoved, + DWORD dwMilliseconds, + BOOL fAlertable); + +typedef BOOL (WINAPI* sSetFileCompletionNotificationModes) + (HANDLE FileHandle, + UCHAR Flags); + +typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW) + (LPCWSTR lpSymlinkFileName, + LPCWSTR lpTargetFileName, + DWORD dwFlags); + +typedef BOOL (WINAPI* sCancelIoEx) + (HANDLE hFile, + LPOVERLAPPED lpOverlapped); + +typedef VOID (WINAPI* sInitializeConditionVariable) + (PCONDITION_VARIABLE ConditionVariable); + +typedef BOOL (WINAPI* sSleepConditionVariableCS) + (PCONDITION_VARIABLE ConditionVariable, + PCRITICAL_SECTION CriticalSection, + DWORD dwMilliseconds); + +typedef BOOL (WINAPI* sSleepConditionVariableSRW) + (PCONDITION_VARIABLE ConditionVariable, + PSRWLOCK SRWLock, + DWORD dwMilliseconds, + ULONG Flags); + +typedef VOID (WINAPI* sWakeAllConditionVariable) + (PCONDITION_VARIABLE ConditionVariable); + +typedef VOID (WINAPI* sWakeConditionVariable) + (PCONDITION_VARIABLE ConditionVariable); + +typedef BOOL (WINAPI* sCancelSynchronousIo) + (HANDLE hThread); + +typedef DWORD (WINAPI* sGetFinalPathNameByHandleW) + (HANDLE hFile, + LPWSTR lpszFilePath, + DWORD cchFilePath, + DWORD dwFlags); + +/* from powerbase.h */ +#ifndef DEVICE_NOTIFY_CALLBACK +# define DEVICE_NOTIFY_CALLBACK 2 +#endif + +#ifndef PBT_APMRESUMEAUTOMATIC +# define PBT_APMRESUMEAUTOMATIC 18 +#endif + +#ifndef PBT_APMRESUMESUSPEND +# define PBT_APMRESUMESUSPEND 7 +#endif + +typedef ULONG CALLBACK _DEVICE_NOTIFY_CALLBACK_ROUTINE( + PVOID Context, + ULONG Type, + PVOID Setting +); +typedef _DEVICE_NOTIFY_CALLBACK_ROUTINE* _PDEVICE_NOTIFY_CALLBACK_ROUTINE; + +typedef struct _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS { + _PDEVICE_NOTIFY_CALLBACK_ROUTINE Callback; + PVOID Context; +} _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, *_PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS; + +typedef PVOID _HPOWERNOTIFY; +typedef _HPOWERNOTIFY *_PHPOWERNOTIFY; + +typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification) + (DWORD Flags, + HANDLE Recipient, + _PHPOWERNOTIFY RegistrationHandle); + + +/* Ntdll function pointers */ +extern sRtlNtStatusToDosError pRtlNtStatusToDosError; +extern sNtDeviceIoControlFile pNtDeviceIoControlFile; +extern sNtQueryInformationFile pNtQueryInformationFile; +extern sNtSetInformationFile pNtSetInformationFile; +extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile; +extern sNtQueryDirectoryFile pNtQueryDirectoryFile; +extern sNtQuerySystemInformation pNtQuerySystemInformation; + + +/* Kernel32 function pointers */ +extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; +extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; +extern sCreateSymbolicLinkW pCreateSymbolicLinkW; +extern sCancelIoEx pCancelIoEx; +extern sInitializeConditionVariable pInitializeConditionVariable; +extern sSleepConditionVariableCS pSleepConditionVariableCS; +extern sSleepConditionVariableSRW pSleepConditionVariableSRW; +extern sWakeAllConditionVariable pWakeAllConditionVariable; +extern sWakeConditionVariable pWakeConditionVariable; +extern sCancelSynchronousIo pCancelSynchronousIo; +extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; + + +/* Powrprof.dll function pointer */ +extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; + +#endif /* UV_WIN_WINAPI_H_ */ diff --git a/src/win/winsock.c b/src/win/winsock.c new file mode 100644 index 0000000..d2e667e --- /dev/null +++ b/src/win/winsock.c @@ -0,0 +1,561 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" + + +/* Whether there are any non-IFS LSPs stacked on TCP */ +int uv_tcp_non_ifs_lsp_ipv4; +int uv_tcp_non_ifs_lsp_ipv6; + +/* Ip address used to bind to any port at any interface */ +struct sockaddr_in uv_addr_ip4_any_; +struct sockaddr_in6 uv_addr_ip6_any_; + + +/* + * Retrieves the pointer to a winsock extension function. + */ +static BOOL uv_get_extension_function(SOCKET socket, GUID guid, + void **target) { + int result; + DWORD bytes; + + result = WSAIoctl(socket, + SIO_GET_EXTENSION_FUNCTION_POINTER, + &guid, + sizeof(guid), + (void*)target, + sizeof(*target), + &bytes, + NULL, + NULL); + + if (result == SOCKET_ERROR) { + *target = NULL; + return FALSE; + } else { + return TRUE; + } +} + + +BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) { + const GUID wsaid_acceptex = WSAID_ACCEPTEX; + return uv_get_extension_function(socket, wsaid_acceptex, (void**)target); +} + + +BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) { + const GUID wsaid_connectex = WSAID_CONNECTEX; + return uv_get_extension_function(socket, wsaid_connectex, (void**)target); +} + + +static int error_means_no_support(DWORD error) { + return error == WSAEPROTONOSUPPORT || error == WSAESOCKTNOSUPPORT || + error == WSAEPFNOSUPPORT || error == WSAEAFNOSUPPORT; +} + + +void uv_winsock_init() { + WSADATA wsa_data; + int errorno; + SOCKET dummy; + WSAPROTOCOL_INFOW protocol_info; + int opt_len; + + /* Initialize winsock */ + errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data); + if (errorno != 0) { + uv_fatal_error(errorno, "WSAStartup"); + } + + /* Set implicit binding address used by connectEx */ + if (uv_ip4_addr("0.0.0.0", 0, &uv_addr_ip4_any_)) { + abort(); + } + + if (uv_ip6_addr("::", 0, &uv_addr_ip6_any_)) { + abort(); + } + + /* Detect non-IFS LSPs */ + dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + + if (dummy != INVALID_SOCKET) { + opt_len = (int) sizeof protocol_info; + if (getsockopt(dummy, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &opt_len) == SOCKET_ERROR) + uv_fatal_error(WSAGetLastError(), "getsockopt"); + + if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)) + uv_tcp_non_ifs_lsp_ipv4 = 1; + + if (closesocket(dummy) == SOCKET_ERROR) + uv_fatal_error(WSAGetLastError(), "closesocket"); + + } else if (!error_means_no_support(WSAGetLastError())) { + /* Any error other than "socket type not supported" is fatal. */ + uv_fatal_error(WSAGetLastError(), "socket"); + } + + /* Detect IPV6 support and non-IFS LSPs */ + dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP); + + if (dummy != INVALID_SOCKET) { + opt_len = (int) sizeof protocol_info; + if (getsockopt(dummy, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &opt_len) == SOCKET_ERROR) + uv_fatal_error(WSAGetLastError(), "getsockopt"); + + if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)) + uv_tcp_non_ifs_lsp_ipv6 = 1; + + if (closesocket(dummy) == SOCKET_ERROR) + uv_fatal_error(WSAGetLastError(), "closesocket"); + + } else if (!error_means_no_support(WSAGetLastError())) { + /* Any error other than "socket type not supported" is fatal. */ + uv_fatal_error(WSAGetLastError(), "socket"); + } +} + + +int uv_ntstatus_to_winsock_error(NTSTATUS status) { + switch (status) { + case STATUS_SUCCESS: + return ERROR_SUCCESS; + + case STATUS_PENDING: + return ERROR_IO_PENDING; + + case STATUS_INVALID_HANDLE: + case STATUS_OBJECT_TYPE_MISMATCH: + return WSAENOTSOCK; + + case STATUS_INSUFFICIENT_RESOURCES: + case STATUS_PAGEFILE_QUOTA: + case STATUS_COMMITMENT_LIMIT: + case STATUS_WORKING_SET_QUOTA: + case STATUS_NO_MEMORY: + case STATUS_QUOTA_EXCEEDED: + case STATUS_TOO_MANY_PAGING_FILES: + case STATUS_REMOTE_RESOURCES: + return WSAENOBUFS; + + case STATUS_TOO_MANY_ADDRESSES: + case STATUS_SHARING_VIOLATION: + case STATUS_ADDRESS_ALREADY_EXISTS: + return WSAEADDRINUSE; + + case STATUS_LINK_TIMEOUT: + case STATUS_IO_TIMEOUT: + case STATUS_TIMEOUT: + return WSAETIMEDOUT; + + case STATUS_GRACEFUL_DISCONNECT: + return WSAEDISCON; + + case STATUS_REMOTE_DISCONNECT: + case STATUS_CONNECTION_RESET: + case STATUS_LINK_FAILED: + case STATUS_CONNECTION_DISCONNECTED: + case STATUS_PORT_UNREACHABLE: + case STATUS_HOPLIMIT_EXCEEDED: + return WSAECONNRESET; + + case STATUS_LOCAL_DISCONNECT: + case STATUS_TRANSACTION_ABORTED: + case STATUS_CONNECTION_ABORTED: + return WSAECONNABORTED; + + case STATUS_BAD_NETWORK_PATH: + case STATUS_NETWORK_UNREACHABLE: + case STATUS_PROTOCOL_UNREACHABLE: + return WSAENETUNREACH; + + case STATUS_HOST_UNREACHABLE: + return WSAEHOSTUNREACH; + + case STATUS_CANCELLED: + case STATUS_REQUEST_ABORTED: + return WSAEINTR; + + case STATUS_BUFFER_OVERFLOW: + case STATUS_INVALID_BUFFER_SIZE: + return WSAEMSGSIZE; + + case STATUS_BUFFER_TOO_SMALL: + case STATUS_ACCESS_VIOLATION: + return WSAEFAULT; + + case STATUS_DEVICE_NOT_READY: + case STATUS_REQUEST_NOT_ACCEPTED: + return WSAEWOULDBLOCK; + + case STATUS_INVALID_NETWORK_RESPONSE: + case STATUS_NETWORK_BUSY: + case STATUS_NO_SUCH_DEVICE: + case STATUS_NO_SUCH_FILE: + case STATUS_OBJECT_PATH_NOT_FOUND: + case STATUS_OBJECT_NAME_NOT_FOUND: + case STATUS_UNEXPECTED_NETWORK_ERROR: + return WSAENETDOWN; + + case STATUS_INVALID_CONNECTION: + return WSAENOTCONN; + + case STATUS_REMOTE_NOT_LISTENING: + case STATUS_CONNECTION_REFUSED: + return WSAECONNREFUSED; + + case STATUS_PIPE_DISCONNECTED: + return WSAESHUTDOWN; + + case STATUS_CONFLICTING_ADDRESSES: + case STATUS_INVALID_ADDRESS: + case STATUS_INVALID_ADDRESS_COMPONENT: + return WSAEADDRNOTAVAIL; + + case STATUS_NOT_SUPPORTED: + case STATUS_NOT_IMPLEMENTED: + return WSAEOPNOTSUPP; + + case STATUS_ACCESS_DENIED: + return WSAEACCES; + + default: + if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) && + (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) { + /* It's a windows error that has been previously mapped to an */ + /* ntstatus code. */ + return (DWORD) (status & 0xffff); + } else { + /* The default fallback for unmappable ntstatus codes. */ + return WSAEINVAL; + } + } +} + + +/* + * This function provides a workaround for a bug in the winsock implementation + * of WSARecv. The problem is that when SetFileCompletionNotificationModes is + * used to avoid IOCP notifications of completed reads, WSARecv does not + * reliably indicate whether we can expect a completion package to be posted + * when the receive buffer is smaller than the received datagram. + * + * However it is desirable to use SetFileCompletionNotificationModes because + * it yields a massive performance increase. + * + * This function provides a workaround for that bug, but it only works for the + * specific case that we need it for. E.g. it assumes that the "avoid iocp" + * bit has been set, and supports only overlapped operation. It also requires + * the user to use the default msafd driver, doesn't work when other LSPs are + * stacked on top of it. + */ +int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers, + DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) { + NTSTATUS status; + void* apc_context; + IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal; + AFD_RECV_INFO info; + DWORD error; + + if (overlapped == NULL || completion_routine != NULL) { + WSASetLastError(WSAEINVAL); + return SOCKET_ERROR; + } + + info.BufferArray = buffers; + info.BufferCount = buffer_count; + info.AfdFlags = AFD_OVERLAPPED; + info.TdiFlags = TDI_RECEIVE_NORMAL; + + if (*flags & MSG_PEEK) { + info.TdiFlags |= TDI_RECEIVE_PEEK; + } + + if (*flags & MSG_PARTIAL) { + info.TdiFlags |= TDI_RECEIVE_PARTIAL; + } + + if (!((intptr_t) overlapped->hEvent & 1)) { + apc_context = (void*) overlapped; + } else { + apc_context = NULL; + } + + iosb->Status = STATUS_PENDING; + iosb->Pointer = 0; + + status = pNtDeviceIoControlFile((HANDLE) socket, + overlapped->hEvent, + NULL, + apc_context, + iosb, + IOCTL_AFD_RECEIVE, + &info, + sizeof(info), + NULL, + 0); + + *flags = 0; + *bytes = (DWORD) iosb->Information; + + switch (status) { + case STATUS_SUCCESS: + error = ERROR_SUCCESS; + break; + + case STATUS_PENDING: + error = WSA_IO_PENDING; + break; + + case STATUS_BUFFER_OVERFLOW: + error = WSAEMSGSIZE; + break; + + case STATUS_RECEIVE_EXPEDITED: + error = ERROR_SUCCESS; + *flags = MSG_OOB; + break; + + case STATUS_RECEIVE_PARTIAL_EXPEDITED: + error = ERROR_SUCCESS; + *flags = MSG_PARTIAL | MSG_OOB; + break; + + case STATUS_RECEIVE_PARTIAL: + error = ERROR_SUCCESS; + *flags = MSG_PARTIAL; + break; + + default: + error = uv_ntstatus_to_winsock_error(status); + break; + } + + WSASetLastError(error); + + if (error == ERROR_SUCCESS) { + return 0; + } else { + return SOCKET_ERROR; + } +} + + +/* See description of uv_wsarecv_workaround. */ +int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, + DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr, + int* addr_len, WSAOVERLAPPED *overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) { + NTSTATUS status; + void* apc_context; + IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal; + AFD_RECV_DATAGRAM_INFO info; + DWORD error; + + if (overlapped == NULL || addr == NULL || addr_len == NULL || + completion_routine != NULL) { + WSASetLastError(WSAEINVAL); + return SOCKET_ERROR; + } + + info.BufferArray = buffers; + info.BufferCount = buffer_count; + info.AfdFlags = AFD_OVERLAPPED; + info.TdiFlags = TDI_RECEIVE_NORMAL; + info.Address = addr; + info.AddressLength = addr_len; + + if (*flags & MSG_PEEK) { + info.TdiFlags |= TDI_RECEIVE_PEEK; + } + + if (*flags & MSG_PARTIAL) { + info.TdiFlags |= TDI_RECEIVE_PARTIAL; + } + + if (!((intptr_t) overlapped->hEvent & 1)) { + apc_context = (void*) overlapped; + } else { + apc_context = NULL; + } + + iosb->Status = STATUS_PENDING; + iosb->Pointer = 0; + + status = pNtDeviceIoControlFile((HANDLE) socket, + overlapped->hEvent, + NULL, + apc_context, + iosb, + IOCTL_AFD_RECEIVE_DATAGRAM, + &info, + sizeof(info), + NULL, + 0); + + *flags = 0; + *bytes = (DWORD) iosb->Information; + + switch (status) { + case STATUS_SUCCESS: + error = ERROR_SUCCESS; + break; + + case STATUS_PENDING: + error = WSA_IO_PENDING; + break; + + case STATUS_BUFFER_OVERFLOW: + error = WSAEMSGSIZE; + break; + + case STATUS_RECEIVE_EXPEDITED: + error = ERROR_SUCCESS; + *flags = MSG_OOB; + break; + + case STATUS_RECEIVE_PARTIAL_EXPEDITED: + error = ERROR_SUCCESS; + *flags = MSG_PARTIAL | MSG_OOB; + break; + + case STATUS_RECEIVE_PARTIAL: + error = ERROR_SUCCESS; + *flags = MSG_PARTIAL; + break; + + default: + error = uv_ntstatus_to_winsock_error(status); + break; + } + + WSASetLastError(error); + + if (error == ERROR_SUCCESS) { + return 0; + } else { + return SOCKET_ERROR; + } +} + + +int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, + AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) { + IO_STATUS_BLOCK iosb; + IO_STATUS_BLOCK* iosb_ptr; + HANDLE event = NULL; + void* apc_context; + NTSTATUS status; + DWORD error; + + if (overlapped != NULL) { + /* Overlapped operation. */ + iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal; + event = overlapped->hEvent; + + /* Do not report iocp completion if hEvent is tagged. */ + if ((uintptr_t) event & 1) { + event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1); + apc_context = NULL; + } else { + apc_context = overlapped; + } + + } else { + /* Blocking operation. */ + iosb_ptr = &iosb; + event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (event == NULL) { + return SOCKET_ERROR; + } + apc_context = NULL; + } + + iosb_ptr->Status = STATUS_PENDING; + status = pNtDeviceIoControlFile((HANDLE) socket, + event, + NULL, + apc_context, + iosb_ptr, + IOCTL_AFD_POLL, + info_in, + sizeof *info_in, + info_out, + sizeof *info_out); + + if (overlapped == NULL) { + /* If this is a blocking operation, wait for the event to become */ + /* signaled, and then grab the real status from the io status block. */ + if (status == STATUS_PENDING) { + DWORD r = WaitForSingleObject(event, INFINITE); + + if (r == WAIT_FAILED) { + DWORD saved_error = GetLastError(); + CloseHandle(event); + WSASetLastError(saved_error); + return SOCKET_ERROR; + } + + status = iosb.Status; + } + + CloseHandle(event); + } + + switch (status) { + case STATUS_SUCCESS: + error = ERROR_SUCCESS; + break; + + case STATUS_PENDING: + error = WSA_IO_PENDING; + break; + + default: + error = uv_ntstatus_to_winsock_error(status); + break; + } + + WSASetLastError(error); + + if (error == ERROR_SUCCESS) { + return 0; + } else { + return SOCKET_ERROR; + } +} diff --git a/src/win/winsock.h b/src/win/winsock.h new file mode 100644 index 0000000..7c007ab --- /dev/null +++ b/src/win/winsock.h @@ -0,0 +1,190 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_WIN_WINSOCK_H_ +#define UV_WIN_WINSOCK_H_ + +#include +#include +#include +#include +#include + +#include "winapi.h" + + +/* + * MinGW is missing these too + */ +#ifndef SO_UPDATE_CONNECT_CONTEXT +# define SO_UPDATE_CONNECT_CONTEXT 0x7010 +#endif + +#ifndef TCP_KEEPALIVE +# define TCP_KEEPALIVE 3 +#endif + +#ifndef IPV6_V6ONLY +# define IPV6_V6ONLY 27 +#endif + +#ifndef IPV6_HOPLIMIT +# define IPV6_HOPLIMIT 21 +#endif + +#ifndef SIO_BASE_HANDLE +# define SIO_BASE_HANDLE 0x48000022 +#endif + +/* + * TDI defines that are only in the DDK. + * We only need receive flags so far. + */ +#ifndef TDI_RECEIVE_NORMAL + #define TDI_RECEIVE_BROADCAST 0x00000004 + #define TDI_RECEIVE_MULTICAST 0x00000008 + #define TDI_RECEIVE_PARTIAL 0x00000010 + #define TDI_RECEIVE_NORMAL 0x00000020 + #define TDI_RECEIVE_EXPEDITED 0x00000040 + #define TDI_RECEIVE_PEEK 0x00000080 + #define TDI_RECEIVE_NO_RESPONSE_EXP 0x00000100 + #define TDI_RECEIVE_COPY_LOOKAHEAD 0x00000200 + #define TDI_RECEIVE_ENTIRE_MESSAGE 0x00000400 + #define TDI_RECEIVE_AT_DISPATCH_LEVEL 0x00000800 + #define TDI_RECEIVE_CONTROL_INFO 0x00001000 + #define TDI_RECEIVE_FORCE_INDICATION 0x00002000 + #define TDI_RECEIVE_NO_PUSH 0x00004000 +#endif + +/* + * The "Auxiliary Function Driver" is the windows kernel-mode driver that does + * TCP, UDP etc. Winsock is just a layer that dispatches requests to it. + * Having these definitions allows us to bypass winsock and make an AFD kernel + * call directly, avoiding a bug in winsock's recvfrom implementation. + */ + +#define AFD_NO_FAST_IO 0x00000001 +#define AFD_OVERLAPPED 0x00000002 +#define AFD_IMMEDIATE 0x00000004 + +#define AFD_POLL_RECEIVE_BIT 0 +#define AFD_POLL_RECEIVE (1 << AFD_POLL_RECEIVE_BIT) +#define AFD_POLL_RECEIVE_EXPEDITED_BIT 1 +#define AFD_POLL_RECEIVE_EXPEDITED (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT) +#define AFD_POLL_SEND_BIT 2 +#define AFD_POLL_SEND (1 << AFD_POLL_SEND_BIT) +#define AFD_POLL_DISCONNECT_BIT 3 +#define AFD_POLL_DISCONNECT (1 << AFD_POLL_DISCONNECT_BIT) +#define AFD_POLL_ABORT_BIT 4 +#define AFD_POLL_ABORT (1 << AFD_POLL_ABORT_BIT) +#define AFD_POLL_LOCAL_CLOSE_BIT 5 +#define AFD_POLL_LOCAL_CLOSE (1 << AFD_POLL_LOCAL_CLOSE_BIT) +#define AFD_POLL_CONNECT_BIT 6 +#define AFD_POLL_CONNECT (1 << AFD_POLL_CONNECT_BIT) +#define AFD_POLL_ACCEPT_BIT 7 +#define AFD_POLL_ACCEPT (1 << AFD_POLL_ACCEPT_BIT) +#define AFD_POLL_CONNECT_FAIL_BIT 8 +#define AFD_POLL_CONNECT_FAIL (1 << AFD_POLL_CONNECT_FAIL_BIT) +#define AFD_POLL_QOS_BIT 9 +#define AFD_POLL_QOS (1 << AFD_POLL_QOS_BIT) +#define AFD_POLL_GROUP_QOS_BIT 10 +#define AFD_POLL_GROUP_QOS (1 << AFD_POLL_GROUP_QOS_BIT) + +#define AFD_NUM_POLL_EVENTS 11 +#define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1) + +typedef struct _AFD_RECV_DATAGRAM_INFO { + LPWSABUF BufferArray; + ULONG BufferCount; + ULONG AfdFlags; + ULONG TdiFlags; + struct sockaddr* Address; + int* AddressLength; +} AFD_RECV_DATAGRAM_INFO, *PAFD_RECV_DATAGRAM_INFO; + +typedef struct _AFD_RECV_INFO { + LPWSABUF BufferArray; + ULONG BufferCount; + ULONG AfdFlags; + ULONG TdiFlags; +} AFD_RECV_INFO, *PAFD_RECV_INFO; + + +#define _AFD_CONTROL_CODE(operation, method) \ + ((FSCTL_AFD_BASE) << 12 | (operation << 2) | method) + +#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK + +#define AFD_RECEIVE 5 +#define AFD_RECEIVE_DATAGRAM 6 +#define AFD_POLL 9 + +#define IOCTL_AFD_RECEIVE \ + _AFD_CONTROL_CODE(AFD_RECEIVE, METHOD_NEITHER) + +#define IOCTL_AFD_RECEIVE_DATAGRAM \ + _AFD_CONTROL_CODE(AFD_RECEIVE_DATAGRAM, METHOD_NEITHER) + +#define IOCTL_AFD_POLL \ + _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED) + +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP { + /* FIXME: __C89_NAMELESS was removed */ + /* __C89_NAMELESS */ union { + ULONGLONG Alignment; + /* __C89_NAMELESS */ struct { + ULONG Length; + DWORD Flags; + }; + }; + struct _IP_ADAPTER_UNICAST_ADDRESS_XP *Next; + SOCKET_ADDRESS Address; + IP_PREFIX_ORIGIN PrefixOrigin; + IP_SUFFIX_ORIGIN SuffixOrigin; + IP_DAD_STATE DadState; + ULONG ValidLifetime; + ULONG PreferredLifetime; + ULONG LeaseLifetime; +} IP_ADAPTER_UNICAST_ADDRESS_XP,*PIP_ADAPTER_UNICAST_ADDRESS_XP; + +typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH { + union { + ULONGLONG Alignment; + struct { + ULONG Length; + DWORD Flags; + }; + }; + struct _IP_ADAPTER_UNICAST_ADDRESS_LH *Next; + SOCKET_ADDRESS Address; + IP_PREFIX_ORIGIN PrefixOrigin; + IP_SUFFIX_ORIGIN SuffixOrigin; + IP_DAD_STATE DadState; + ULONG ValidLifetime; + ULONG PreferredLifetime; + ULONG LeaseLifetime; + UINT8 OnLinkPrefixLength; +} IP_ADAPTER_UNICAST_ADDRESS_LH,*PIP_ADAPTER_UNICAST_ADDRESS_LH; + +#endif + +#endif /* UV_WIN_WINSOCK_H_ */ https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0cb012e03cd6ad6b12adf3b0547eb91fadbe7292 commit 0cb012e03cd6ad6b12adf3b0547eb91fadbe7292 Author: Brad King AuthorDate: Tue Aug 16 16:19:43 2016 -0400 Commit: Brad King CommitDate: Thu Aug 25 13:50:51 2016 -0400 Add script to update libuv from upstream diff --git a/Utilities/Scripts/update-libuv.bash b/Utilities/Scripts/update-libuv.bash new file mode 100755 index 0000000..d7a7d1f --- /dev/null +++ b/Utilities/Scripts/update-libuv.bash @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -e +set -x +shopt -s dotglob + +readonly name="libuv" +readonly ownership="libuv upstream " +readonly subtree="Utilities/cmlibuv" +readonly repo="https://github.com/libuv/libuv.git" +readonly tag="v1.x" +readonly shortlog=false +readonly paths=" + LICENSE + include + src +" + +extract_source () { + git_archive + pushd "${extractdir}/${name}-reduced" + echo "* -whitespace" > .gitattributes + popd +} + +. "${BASH_SOURCE%/*}/update-third-party.bash" ----------------------------------------------------------------------- Summary of changes: CMakeLists.txt | 43 +- Source/CMakeLists.txt | 1 + Source/Modules/FindLibUV.cmake | 131 + Source/cmConfigure.cmake.h.in | 1 + Source/cmakemain.cxx | 7 + Tests/CMakeLists.txt | 4 + Tests/FindLibUV/CMakeLists.txt | 10 + Tests/FindLibUV/Test/CMakeLists.txt | 17 + Tests/FindLibUV/Test/main.c | 7 + Utilities/Scripts/update-libuv.bash | 26 + Utilities/cmThirdParty.h.in | 1 + Utilities/cm_uv.h | 23 + Utilities/{cmcurl => cmlibuv}/.gitattributes | 0 Utilities/cmlibuv/CMakeLists.txt | 227 ++ Utilities/cmlibuv/LICENSE | 70 + Utilities/cmlibuv/include/android-ifaddrs.h | 54 + Utilities/cmlibuv/include/pthread-barrier.h | 66 + Utilities/cmlibuv/include/stdint-msvc2008.h | 247 ++ Utilities/cmlibuv/include/tree.h | 768 ++++ Utilities/cmlibuv/include/uv-aix.h | 32 + Utilities/cmlibuv/include/uv-bsd.h | 34 + Utilities/cmlibuv/include/uv-darwin.h | 61 + Utilities/cmlibuv/include/uv-errno.h | 419 +++ Utilities/cmlibuv/include/uv-linux.h | 34 + Utilities/cmlibuv/include/uv-os390.h | 27 + Utilities/cmlibuv/include/uv-sunos.h | 44 + Utilities/cmlibuv/include/uv-threadpool.h | 37 + Utilities/cmlibuv/include/uv-unix.h | 371 ++ Utilities/cmlibuv/include/uv-version.h | 43 + Utilities/cmlibuv/include/uv-win.h | 660 ++++ Utilities/cmlibuv/include/uv.h | 1499 ++++++++ Utilities/cmlibuv/src/fs-poll.c | 256 ++ Utilities/cmlibuv/src/heap-inl.h | 245 ++ Utilities/cmlibuv/src/inet.c | 309 ++ Utilities/cmlibuv/src/queue.h | 108 + Utilities/cmlibuv/src/threadpool.c | 303 ++ Utilities/cmlibuv/src/unix/aix.c | 1154 ++++++ Utilities/cmlibuv/src/unix/android-ifaddrs.c | 703 ++++ Utilities/cmlibuv/src/unix/async.c | 290 ++ Utilities/cmlibuv/src/unix/atomic-ops.h | 88 + Utilities/cmlibuv/src/unix/core.c | 1238 +++++++ Utilities/cmlibuv/src/unix/darwin-proctitle.c | 206 ++ Utilities/cmlibuv/src/unix/darwin.c | 335 ++ Utilities/cmlibuv/src/unix/dl.c | 80 + Utilities/cmlibuv/src/unix/freebsd.c | 460 +++ Utilities/cmlibuv/src/unix/fs.c | 1355 +++++++ Utilities/cmlibuv/src/unix/fsevents.c | 904 +++++ Utilities/cmlibuv/src/unix/getaddrinfo.c | 202 ++ Utilities/cmlibuv/src/unix/getnameinfo.c | 120 + Utilities/cmlibuv/src/unix/internal.h | 322 ++ Utilities/cmlibuv/src/unix/kqueue.c | 463 +++ Utilities/cmlibuv/src/unix/linux-core.c | 985 +++++ Utilities/cmlibuv/src/unix/linux-inotify.c | 285 ++ Utilities/cmlibuv/src/unix/linux-syscalls.c | 471 +++ Utilities/cmlibuv/src/unix/linux-syscalls.h | 151 + Utilities/cmlibuv/src/unix/loop-watcher.c | 68 + Utilities/cmlibuv/src/unix/loop.c | 159 + Utilities/cmlibuv/src/unix/netbsd.c | 380 ++ Utilities/cmlibuv/src/unix/openbsd.c | 396 ++ Utilities/cmlibuv/src/unix/os390.c | 42 + Utilities/cmlibuv/src/unix/pipe.c | 298 ++ Utilities/cmlibuv/src/unix/poll.c | 130 + Utilities/cmlibuv/src/unix/process.c | 563 +++ Utilities/cmlibuv/src/unix/proctitle.c | 105 + Utilities/cmlibuv/src/unix/pthread-barrier.c | 120 + Utilities/cmlibuv/src/unix/pthread-fixes.c | 56 + Utilities/cmlibuv/src/unix/signal.c | 467 +++ Utilities/cmlibuv/src/unix/spinlock.h | 53 + Utilities/cmlibuv/src/unix/stream.c | 1638 +++++++++ Utilities/cmlibuv/src/unix/sunos.c | 821 +++++ Utilities/cmlibuv/src/unix/tcp.c | 395 ++ Utilities/cmlibuv/src/unix/thread.c | 605 ++++ Utilities/cmlibuv/src/unix/timer.c | 172 + Utilities/cmlibuv/src/unix/tty.c | 336 ++ Utilities/cmlibuv/src/unix/udp.c | 895 +++++ Utilities/cmlibuv/src/uv-common.c | 652 ++++ Utilities/cmlibuv/src/uv-common.h | 227 ++ Utilities/cmlibuv/src/version.c | 45 + Utilities/cmlibuv/src/win/async.c | 99 + Utilities/cmlibuv/src/win/atomicops-inl.h | 56 + Utilities/cmlibuv/src/win/core.c | 602 ++++ Utilities/cmlibuv/src/win/detect-wakeup.c | 35 + Utilities/cmlibuv/src/win/dl.c | 118 + Utilities/cmlibuv/src/win/error.c | 170 + Utilities/cmlibuv/src/win/fs-event.c | 545 +++ Utilities/cmlibuv/src/win/fs.c | 2491 +++++++++++++ Utilities/cmlibuv/src/win/getaddrinfo.c | 385 ++ Utilities/cmlibuv/src/win/getnameinfo.c | 150 + Utilities/cmlibuv/src/win/handle-inl.h | 179 + Utilities/cmlibuv/src/win/handle.c | 154 + Utilities/cmlibuv/src/win/internal.h | 398 +++ Utilities/cmlibuv/src/win/loop-watcher.c | 122 + Utilities/cmlibuv/src/win/pipe.c | 2130 +++++++++++ Utilities/cmlibuv/src/win/poll.c | 646 ++++ Utilities/cmlibuv/src/win/process-stdio.c | 510 +++ Utilities/cmlibuv/src/win/process.c | 1247 +++++++ Utilities/cmlibuv/src/win/req-inl.h | 224 ++ Utilities/cmlibuv/src/win/req.c | 25 + Utilities/cmlibuv/src/win/signal.c | 356 ++ Utilities/cmlibuv/src/win/snprintf.c | 42 + Utilities/cmlibuv/src/win/stream-inl.h | 56 + Utilities/cmlibuv/src/win/stream.c | 249 ++ Utilities/cmlibuv/src/win/tcp.c | 1510 ++++++++ Utilities/cmlibuv/src/win/thread.c | 697 ++++ Utilities/cmlibuv/src/win/timer.c | 195 + Utilities/cmlibuv/src/win/tty.c | 2175 +++++++++++ Utilities/cmlibuv/src/win/udp.c | 928 +++++ Utilities/cmlibuv/src/win/util.c | 1380 +++++++ Utilities/cmlibuv/src/win/winapi.c | 159 + Utilities/cmlibuv/src/win/winapi.h | 4757 +++++++++++++++++++++++++ Utilities/cmlibuv/src/win/winsock.c | 561 +++ Utilities/cmlibuv/src/win/winsock.h | 191 + 112 files changed, 48161 insertions(+), 1 deletion(-) create mode 100644 Source/Modules/FindLibUV.cmake create mode 100644 Tests/FindLibUV/CMakeLists.txt create mode 100644 Tests/FindLibUV/Test/CMakeLists.txt create mode 100644 Tests/FindLibUV/Test/main.c create mode 100755 Utilities/Scripts/update-libuv.bash create mode 100644 Utilities/cm_uv.h copy Utilities/{cmcurl => cmlibuv}/.gitattributes (100%) create mode 100644 Utilities/cmlibuv/CMakeLists.txt create mode 100644 Utilities/cmlibuv/LICENSE create mode 100644 Utilities/cmlibuv/include/android-ifaddrs.h create mode 100644 Utilities/cmlibuv/include/pthread-barrier.h create mode 100644 Utilities/cmlibuv/include/stdint-msvc2008.h create mode 100644 Utilities/cmlibuv/include/tree.h create mode 100644 Utilities/cmlibuv/include/uv-aix.h create mode 100644 Utilities/cmlibuv/include/uv-bsd.h create mode 100644 Utilities/cmlibuv/include/uv-darwin.h create mode 100644 Utilities/cmlibuv/include/uv-errno.h create mode 100644 Utilities/cmlibuv/include/uv-linux.h create mode 100644 Utilities/cmlibuv/include/uv-os390.h create mode 100644 Utilities/cmlibuv/include/uv-sunos.h create mode 100644 Utilities/cmlibuv/include/uv-threadpool.h create mode 100644 Utilities/cmlibuv/include/uv-unix.h create mode 100644 Utilities/cmlibuv/include/uv-version.h create mode 100644 Utilities/cmlibuv/include/uv-win.h create mode 100644 Utilities/cmlibuv/include/uv.h create mode 100644 Utilities/cmlibuv/src/fs-poll.c create mode 100644 Utilities/cmlibuv/src/heap-inl.h create mode 100644 Utilities/cmlibuv/src/inet.c create mode 100644 Utilities/cmlibuv/src/queue.h create mode 100644 Utilities/cmlibuv/src/threadpool.c create mode 100644 Utilities/cmlibuv/src/unix/aix.c create mode 100644 Utilities/cmlibuv/src/unix/android-ifaddrs.c create mode 100644 Utilities/cmlibuv/src/unix/async.c create mode 100644 Utilities/cmlibuv/src/unix/atomic-ops.h create mode 100644 Utilities/cmlibuv/src/unix/core.c create mode 100644 Utilities/cmlibuv/src/unix/darwin-proctitle.c create mode 100644 Utilities/cmlibuv/src/unix/darwin.c create mode 100644 Utilities/cmlibuv/src/unix/dl.c create mode 100644 Utilities/cmlibuv/src/unix/freebsd.c create mode 100644 Utilities/cmlibuv/src/unix/fs.c create mode 100644 Utilities/cmlibuv/src/unix/fsevents.c create mode 100644 Utilities/cmlibuv/src/unix/getaddrinfo.c create mode 100644 Utilities/cmlibuv/src/unix/getnameinfo.c create mode 100644 Utilities/cmlibuv/src/unix/internal.h create mode 100644 Utilities/cmlibuv/src/unix/kqueue.c create mode 100644 Utilities/cmlibuv/src/unix/linux-core.c create mode 100644 Utilities/cmlibuv/src/unix/linux-inotify.c create mode 100644 Utilities/cmlibuv/src/unix/linux-syscalls.c create mode 100644 Utilities/cmlibuv/src/unix/linux-syscalls.h create mode 100644 Utilities/cmlibuv/src/unix/loop-watcher.c create mode 100644 Utilities/cmlibuv/src/unix/loop.c create mode 100644 Utilities/cmlibuv/src/unix/netbsd.c create mode 100644 Utilities/cmlibuv/src/unix/openbsd.c create mode 100644 Utilities/cmlibuv/src/unix/os390.c create mode 100644 Utilities/cmlibuv/src/unix/pipe.c create mode 100644 Utilities/cmlibuv/src/unix/poll.c create mode 100644 Utilities/cmlibuv/src/unix/process.c create mode 100644 Utilities/cmlibuv/src/unix/proctitle.c create mode 100644 Utilities/cmlibuv/src/unix/pthread-barrier.c create mode 100644 Utilities/cmlibuv/src/unix/pthread-fixes.c create mode 100644 Utilities/cmlibuv/src/unix/signal.c create mode 100644 Utilities/cmlibuv/src/unix/spinlock.h create mode 100644 Utilities/cmlibuv/src/unix/stream.c create mode 100644 Utilities/cmlibuv/src/unix/sunos.c create mode 100644 Utilities/cmlibuv/src/unix/tcp.c create mode 100644 Utilities/cmlibuv/src/unix/thread.c create mode 100644 Utilities/cmlibuv/src/unix/timer.c create mode 100644 Utilities/cmlibuv/src/unix/tty.c create mode 100644 Utilities/cmlibuv/src/unix/udp.c create mode 100644 Utilities/cmlibuv/src/uv-common.c create mode 100644 Utilities/cmlibuv/src/uv-common.h create mode 100644 Utilities/cmlibuv/src/version.c create mode 100644 Utilities/cmlibuv/src/win/async.c create mode 100644 Utilities/cmlibuv/src/win/atomicops-inl.h create mode 100644 Utilities/cmlibuv/src/win/core.c create mode 100644 Utilities/cmlibuv/src/win/detect-wakeup.c create mode 100644 Utilities/cmlibuv/src/win/dl.c create mode 100644 Utilities/cmlibuv/src/win/error.c create mode 100644 Utilities/cmlibuv/src/win/fs-event.c create mode 100644 Utilities/cmlibuv/src/win/fs.c create mode 100644 Utilities/cmlibuv/src/win/getaddrinfo.c create mode 100644 Utilities/cmlibuv/src/win/getnameinfo.c create mode 100644 Utilities/cmlibuv/src/win/handle-inl.h create mode 100644 Utilities/cmlibuv/src/win/handle.c create mode 100644 Utilities/cmlibuv/src/win/internal.h create mode 100644 Utilities/cmlibuv/src/win/loop-watcher.c create mode 100644 Utilities/cmlibuv/src/win/pipe.c create mode 100644 Utilities/cmlibuv/src/win/poll.c create mode 100644 Utilities/cmlibuv/src/win/process-stdio.c create mode 100644 Utilities/cmlibuv/src/win/process.c create mode 100644 Utilities/cmlibuv/src/win/req-inl.h create mode 100644 Utilities/cmlibuv/src/win/req.c create mode 100644 Utilities/cmlibuv/src/win/signal.c create mode 100644 Utilities/cmlibuv/src/win/snprintf.c create mode 100644 Utilities/cmlibuv/src/win/stream-inl.h create mode 100644 Utilities/cmlibuv/src/win/stream.c create mode 100644 Utilities/cmlibuv/src/win/tcp.c create mode 100644 Utilities/cmlibuv/src/win/thread.c create mode 100644 Utilities/cmlibuv/src/win/timer.c create mode 100644 Utilities/cmlibuv/src/win/tty.c create mode 100644 Utilities/cmlibuv/src/win/udp.c create mode 100644 Utilities/cmlibuv/src/win/util.c create mode 100644 Utilities/cmlibuv/src/win/winapi.c create mode 100644 Utilities/cmlibuv/src/win/winapi.h create mode 100644 Utilities/cmlibuv/src/win/winsock.c create mode 100644 Utilities/cmlibuv/src/win/winsock.h hooks/post-receive -- CMake From domen.vrankar at gmail.com Thu Aug 25 16:21:15 2016 From: domen.vrankar at gmail.com (Domen Vrankar) Date: Thu, 25 Aug 2016 16:21:15 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1471-g81bb94a Message-ID: <20160825202115.9CF53F57AC@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 81bb94aff906c89cd7bc0cf070df1c34c0a4086b (commit) via 11ad59ca59a7d1372588f14f681211a2ab3ea71f (commit) from 33ab8bdd0aad3e44e8d85a730daca64c26ad71b1 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=81bb94aff906c89cd7bc0cf070df1c34c0a4086b commit 81bb94aff906c89cd7bc0cf070df1c34c0a4086b Merge: 33ab8bd 11ad59c Author: Domen Vrankar AuthorDate: Thu Aug 25 16:21:14 2016 -0400 Commit: CMake Topic Stage CommitDate: Thu Aug 25 16:21:14 2016 -0400 Merge topic 'cpack-rpm-debuginfo-pkg' into next 11ad59ca fixup! cpack-rpm-debuginfo https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=11ad59ca59a7d1372588f14f681211a2ab3ea71f commit 11ad59ca59a7d1372588f14f681211a2ab3ea71f Author: Domen Vrankar AuthorDate: Thu Aug 25 22:20:51 2016 +0200 Commit: Domen Vrankar CommitDate: Thu Aug 25 22:20:51 2016 +0200 fixup! cpack-rpm-debuginfo diff --git a/Help/release/dev/cpack-rpm-debuginfo-pkg.rst b/Help/release/dev/cpack-rpm-debuginfo-pkg.rst index f02a162..8b37fe4 100644 --- a/Help/release/dev/cpack-rpm-debuginfo-pkg.rst +++ b/Help/release/dev/cpack-rpm-debuginfo-pkg.rst @@ -1,5 +1,5 @@ cpack-rpm-debuginfo-pkg ------------------- +----------------------- * The :module:`CPackRPM` module learned to generate debuginfo packages on demand. See :variable:`CPACK_RPM_DEBUGINFO_PACKAGE` ----------------------------------------------------------------------- Summary of changes: Help/release/dev/cpack-rpm-debuginfo-pkg.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From kwrobot at kitware.com Fri Aug 26 00:01:07 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Fri, 26 Aug 2016 00:01:07 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-734-gff88df4 Message-ID: <20160826040107.6371BF5C38@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via ff88df48e8a693f213a44aee3ad2474f500857b5 (commit) from 98caa14cc84cc659c2c5b51f84c6547b57c89c30 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ff88df48e8a693f213a44aee3ad2474f500857b5 commit ff88df48e8a693f213a44aee3ad2474f500857b5 Author: Kitware Robot AuthorDate: Fri Aug 26 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Fri Aug 26 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index d26debc..e8a4d2c 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160825) +set(CMake_VERSION_PATCH 20160826) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From gjasny at googlemail.com Fri Aug 26 02:54:05 2016 From: gjasny at googlemail.com (Gregor Jasny) Date: Fri, 26 Aug 2016 02:54:05 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1474-g031a9c4 Message-ID: <20160826065405.CACF3F5412@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 031a9c4558879f4f5b5b4f5122623a78066e4638 (commit) via 4a5c14a5a15bc82e8ea045fe1c8522682b17cbdd (commit) via ff88df48e8a693f213a44aee3ad2474f500857b5 (commit) from 81bb94aff906c89cd7bc0cf070df1c34c0a4086b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=031a9c4558879f4f5b5b4f5122623a78066e4638 commit 031a9c4558879f4f5b5b4f5122623a78066e4638 Merge: 81bb94a 4a5c14a Author: Gregor Jasny AuthorDate: Fri Aug 26 02:54:03 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 26 02:54:03 2016 -0400 Merge topic '16101-xcode-fix-directory-exclude-from-all' into next 4a5c14a5 Xcode: Add targets marked as EXCLUDE_FROM_ALL to project (#16101) ff88df48 CMake Nightly Date Stamp https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4a5c14a5a15bc82e8ea045fe1c8522682b17cbdd commit 4a5c14a5a15bc82e8ea045fe1c8522682b17cbdd Author: Gregor Jasny AuthorDate: Fri Aug 19 21:50:48 2016 +0200 Commit: Gregor Jasny CommitDate: Fri Aug 26 08:53:39 2016 +0200 Xcode: Add targets marked as EXCLUDE_FROM_ALL to project (#16101) diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 780ca90..b4bc084 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -2635,13 +2635,10 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) } bool cmGlobalXCodeGenerator::CreateGroups( - cmLocalGenerator* root, std::vector& generators) + std::vector& generators) { for (std::vector::iterator i = generators.begin(); i != generators.end(); ++i) { - if (this->IsExcluded(root, *i)) { - continue; - } cmMakefile* mf = (*i)->GetMakefile(); std::vector sourceGroups = mf->GetSourceGroups(); std::vector tgts = (*i)->GetGeneratorTargets(); @@ -2873,7 +2870,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( this->MainGroupChildren->AddObject(resourcesGroup); // now create the cmake groups - if (!this->CreateGroups(root, generators)) { + if (!this->CreateGroups(generators)) { return false; } @@ -3041,10 +3038,8 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( std::vector targets; for (std::vector::iterator i = generators.begin(); i != generators.end(); ++i) { - if (!this->IsExcluded(root, *i)) { - if (!this->CreateXCodeTargets(*i, targets)) { - return false; - } + if (!this->CreateXCodeTargets(*i, targets)) { + return false; } } // loop over all targets and add link and depend info diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 0485d4f..303dfa0 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -92,8 +92,7 @@ private: cmXCodeObject* CreateOrGetPBXGroup(cmGeneratorTarget* gtgt, cmSourceGroup* sg); cmXCodeObject* CreatePBXGroup(cmXCodeObject* parent, std::string name); - bool CreateGroups(cmLocalGenerator* root, - std::vector& generators); + bool CreateGroups(std::vector& generators); std::string XCodeEscapePath(const std::string& p); std::string RelativeToSource(const char* p); std::string RelativeToBinary(const char* p); diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake b/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake new file mode 100644 index 0000000..f686005 --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake @@ -0,0 +1,6 @@ +enable_language(CXX) + +add_subdirectory(ExcludeFromAll EXCLUDE_FROM_ALL) + +add_executable(main main.cpp) +target_link_libraries(main PRIVATE foo) diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt new file mode 100644 index 0000000..b1df6b0 --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(bar STATIC bar.cpp) + +add_library(foo STATIC foo.cpp) +target_include_directories(foo PUBLIC .) diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp new file mode 100644 index 0000000..7a828bd --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp @@ -0,0 +1 @@ +#error This should be excluded from all target diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp new file mode 100644 index 0000000..2789e61 --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp @@ -0,0 +1,3 @@ +#include "foo.h" + +int foo() { return 42; } diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.h b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.h new file mode 100644 index 0000000..5d5f8f0 --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.h @@ -0,0 +1 @@ +int foo(); diff --git a/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake index 9d514e1..6d9418b 100644 --- a/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake +++ b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake @@ -3,3 +3,15 @@ include(RunCMake) run_cmake(DoesNotExist) run_cmake(Missing) run_cmake(Function) + +set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ExcludeFromAll) +set(RunCMake_TEST_NO_CLEAN 1) + +file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") +file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + +run_cmake(ExcludeFromAll) +run_cmake_command(ExcludeFromAll-build ${CMAKE_COMMAND} --build .) + +unset(RunCMake_TEST_BINARY_DIR) +unset(RunCMake_TEST_NO_CLEAN) diff --git a/Tests/RunCMake/add_subdirectory/main.cpp b/Tests/RunCMake/add_subdirectory/main.cpp new file mode 100644 index 0000000..8e69c08 --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/main.cpp @@ -0,0 +1,6 @@ +#include "foo.h" + +int main(int, char**) +{ + return foo(); +} ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- Source/cmGlobalXCodeGenerator.cxx | 13 ++++--------- Source/cmGlobalXCodeGenerator.h | 3 +-- Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake | 6 ++++++ .../add_subdirectory/ExcludeFromAll/CMakeLists.txt | 4 ++++ Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp | 1 + Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp | 3 +++ .../{Framework => add_subdirectory/ExcludeFromAll}/foo.h | 0 Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake | 12 ++++++++++++ Tests/RunCMake/add_subdirectory/main.cpp | 6 ++++++ 10 files changed, 38 insertions(+), 12 deletions(-) create mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake create mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt create mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp create mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp copy Tests/RunCMake/{Framework => add_subdirectory/ExcludeFromAll}/foo.h (100%) create mode 100644 Tests/RunCMake/add_subdirectory/main.cpp hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 08:34:08 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 08:34:08 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1476-g9a42912 Message-ID: <20160826123408.15E16F5B26@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 9a429125465a38a75d23b85f6e1f55a9cb5e83fb (commit) via 8c94b5b004606dc021e153e0a4a824a3d9db6750 (commit) from 031a9c4558879f4f5b5b4f5122623a78066e4638 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9a429125465a38a75d23b85f6e1f55a9cb5e83fb commit 9a429125465a38a75d23b85f6e1f55a9cb5e83fb Merge: 031a9c4 8c94b5b Author: Brad King AuthorDate: Fri Aug 26 08:34:06 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 26 08:34:06 2016 -0400 Merge topic 'import-libuv' into next 8c94b5b0 Do not build libuv on Cygwin https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8c94b5b004606dc021e153e0a4a824a3d9db6750 commit 8c94b5b004606dc021e153e0a4a824a3d9db6750 Author: Brad King AuthorDate: Fri Aug 26 08:17:42 2016 -0400 Commit: Brad King CommitDate: Fri Aug 26 08:17:42 2016 -0400 Do not build libuv on Cygwin Currently libuv does not support Cygwin: https://github.com/libuv/libuv/issues/832 in part due to lack of pthread APIs: https://cygwin.com/cygwin-api/std-notimpl.html diff --git a/CMakeLists.txt b/CMakeLists.txt index b62f6a5..9176049 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -481,6 +481,9 @@ int main(void) { return 0; } if(NOT HAVE_CoreServices_OS_X_10_5) set(CMAKE_USE_LIBUV 0) endif() + elseif(CYGWIN) + # libuv does not support Cygwin + set(CMAKE_USE_LIBUV 0) endif() endif() if(CMAKE_USE_LIBUV) ----------------------------------------------------------------------- Summary of changes: CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 08:34:10 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 08:34:10 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1478-g7159a29 Message-ID: <20160826123410.C1813F5B2D@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 7159a29e50c3ce63b70994e6bbc915f38bb09851 (commit) via 24e7ccb7ef486191ebb9fca916c70e367c41b2fb (commit) from 9a429125465a38a75d23b85f6e1f55a9cb5e83fb (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7159a29e50c3ce63b70994e6bbc915f38bb09851 commit 7159a29e50c3ce63b70994e6bbc915f38bb09851 Merge: 9a42912 24e7ccb Author: Brad King AuthorDate: Fri Aug 26 08:34:08 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 26 08:34:08 2016 -0400 Merge topic 'update-curl-script' into next 24e7ccb7 curl: Update script to get curl from new repository https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=24e7ccb7ef486191ebb9fca916c70e367c41b2fb commit 24e7ccb7ef486191ebb9fca916c70e367c41b2fb Author: Brad King AuthorDate: Fri Aug 26 08:32:23 2016 -0400 Commit: Brad King CommitDate: Fri Aug 26 08:32:45 2016 -0400 curl: Update script to get curl from new repository Curl is now hosted at https://github.com/curl/curl.git diff --git a/Utilities/Scripts/update-curl.bash b/Utilities/Scripts/update-curl.bash index 0e466cf..590bd44 100755 --- a/Utilities/Scripts/update-curl.bash +++ b/Utilities/Scripts/update-curl.bash @@ -7,7 +7,7 @@ shopt -s dotglob readonly name="curl" readonly ownership="Curl Upstream " readonly subtree="Utilities/cmcurl" -readonly repo="https://github.com/bagder/curl.git" +readonly repo="https://github.com/curl/curl.git" readonly tag="curl-7_50_1" readonly shortlog=false readonly paths=" ----------------------------------------------------------------------- Summary of changes: Utilities/Scripts/update-curl.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 08:59:57 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 08:59:57 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1480-g7a7da5c Message-ID: <20160826125957.B2B1BF5C5F@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 7a7da5c4909f2836bbc52d86b02ac14a4c8719fa (commit) via a9d5f76bc76295966223211ca15d07e3b91a3387 (commit) from 7159a29e50c3ce63b70994e6bbc915f38bb09851 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7a7da5c4909f2836bbc52d86b02ac14a4c8719fa commit 7a7da5c4909f2836bbc52d86b02ac14a4c8719fa Merge: 7159a29 a9d5f76 Author: Brad King AuthorDate: Fri Aug 26 08:59:56 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 26 08:59:56 2016 -0400 Merge topic 'import-libuv' into next a9d5f76b Do not build libuv on SPARC https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a9d5f76bc76295966223211ca15d07e3b91a3387 commit a9d5f76bc76295966223211ca15d07e3b91a3387 Author: Brad King AuthorDate: Fri Aug 26 08:57:40 2016 -0400 Commit: Brad King CommitDate: Fri Aug 26 08:57:40 2016 -0400 Do not build libuv on SPARC Some work may be needed to port to SPARC with Solaris and Linux. diff --git a/CMakeLists.txt b/CMakeLists.txt index 9176049..65876d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -484,6 +484,9 @@ int main(void) { return 0; } elseif(CYGWIN) # libuv does not support Cygwin set(CMAKE_USE_LIBUV 0) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "sparc") + # Disable until it can be ported. + set(CMAKE_USE_LIBUV 0) endif() endif() if(CMAKE_USE_LIBUV) ----------------------------------------------------------------------- Summary of changes: CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 09:04:22 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 09:04:22 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1482-g26b134e Message-ID: <20160826130422.1D0CFF5CFE@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 26b134edb36b913f45a63896a2e4c06993cc0779 (commit) via f0a0e4559c17020101e3e0be18bac54e27a263cb (commit) from 7a7da5c4909f2836bbc52d86b02ac14a4c8719fa (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=26b134edb36b913f45a63896a2e4c06993cc0779 commit 26b134edb36b913f45a63896a2e4c06993cc0779 Merge: 7a7da5c f0a0e45 Author: Brad King AuthorDate: Fri Aug 26 09:04:21 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 26 09:04:21 2016 -0400 Merge topic 'import-libuv' into next f0a0e455 Do not build libuv on HP-UX https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f0a0e4559c17020101e3e0be18bac54e27a263cb commit f0a0e4559c17020101e3e0be18bac54e27a263cb Author: Brad King AuthorDate: Fri Aug 26 09:02:46 2016 -0400 Commit: Brad King CommitDate: Fri Aug 26 09:03:02 2016 -0400 Do not build libuv on HP-UX Currently libuv does not support HP-UX. diff --git a/CMakeLists.txt b/CMakeLists.txt index 65876d5..aab8416 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -484,6 +484,9 @@ int main(void) { return 0; } elseif(CYGWIN) # libuv does not support Cygwin set(CMAKE_USE_LIBUV 0) + elseif(CMAKE_SYSTEM_NAME STREQUAL "HP-UX") + # libuv does not support HP-UX + set(CMAKE_USE_LIBUV 0) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "sparc") # Disable until it can be ported. set(CMAKE_USE_LIBUV 0) ----------------------------------------------------------------------- Summary of changes: CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 09:15:40 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 09:15:40 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1484-g795c417 Message-ID: <20160826131540.39A4BF479B@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 795c4172d8c78c66cf56e1728543967d0f81226c (commit) via 86255f8911796de904245682e3b0de2adfa571dc (commit) from 26b134edb36b913f45a63896a2e4c06993cc0779 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=795c4172d8c78c66cf56e1728543967d0f81226c commit 795c4172d8c78c66cf56e1728543967d0f81226c Merge: 26b134e 86255f8 Author: Brad King AuthorDate: Fri Aug 26 09:15:39 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 26 09:15:39 2016 -0400 Merge topic 'ninja-add_custom_command-depfile' into next 86255f89 fixup! add_custom_command: Add DEPFILE option for Ninja https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=86255f8911796de904245682e3b0de2adfa571dc commit 86255f8911796de904245682e3b0de2adfa571dc Author: Brad King AuthorDate: Fri Aug 26 09:15:16 2016 -0400 Commit: Brad King CommitDate: Fri Aug 26 09:15:16 2016 -0400 fixup! add_custom_command: Add DEPFILE option for Ninja diff --git a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt index 733c950..74d62a4 100644 --- a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt +++ b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt @@ -1,2 +1,5 @@ ^CMake Error at CustomCommandDepfile-ERROR.cmake:1 \(add_custom_command\): - add_custom_command Option DEPFILE not supported by Unix Makefiles + add_custom_command Option DEPFILE not supported by [^ +]+ +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ ----------------------------------------------------------------------- Summary of changes: Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 09:21:12 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 09:21:12 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1487-gc3bcd01 Message-ID: <20160826132112.7BA42F53B8@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via c3bcd014a7452256dcbf738d753944a8d7ed3d78 (commit) via 87ff791424b715b1edd31c45b834fddf92a38646 (commit) via fd22d5bb476eac37896bfc43cdd4bfa4bdd4fae5 (commit) from 795c4172d8c78c66cf56e1728543967d0f81226c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c3bcd014a7452256dcbf738d753944a8d7ed3d78 commit c3bcd014a7452256dcbf738d753944a8d7ed3d78 Merge: 795c417 87ff791 Author: Brad King AuthorDate: Fri Aug 26 09:21:11 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 26 09:21:11 2016 -0400 Merge topic 'import-libuv' into next 87ff7914 fixup! libuv: Disable warnings to avoid changing 3rd party code fd22d5bb libuv: Fix unused variable warning in uv_loop_close https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=87ff791424b715b1edd31c45b834fddf92a38646 commit 87ff791424b715b1edd31c45b834fddf92a38646 Author: Brad King AuthorDate: Fri Aug 26 09:19:38 2016 -0400 Commit: Brad King CommitDate: Fri Aug 26 09:19:38 2016 -0400 fixup! libuv: Disable warnings to avoid changing 3rd party code diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt index 599f3f7..e25ac82 100644 --- a/Utilities/cmlibuv/CMakeLists.txt +++ b/Utilities/cmlibuv/CMakeLists.txt @@ -1,11 +1,11 @@ project(libuv C) # Disable warnings to avoid changing 3rd party code. -if(CMAKE_CXX_COMPILER_ID MATCHES +if(CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w") -elseif(CMAKE_CXX_COMPILER_ID STREQUAL "PathScale") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -woffall") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w") +elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall") endif() find_package(Threads) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=fd22d5bb476eac37896bfc43cdd4bfa4bdd4fae5 commit fd22d5bb476eac37896bfc43cdd4bfa4bdd4fae5 Author: Brad King AuthorDate: Fri Aug 26 09:16:45 2016 -0400 Commit: Brad King CommitDate: Fri Aug 26 09:16:45 2016 -0400 libuv: Fix unused variable warning in uv_loop_close diff --git a/Utilities/cmlibuv/src/uv-common.c b/Utilities/cmlibuv/src/uv-common.c index 434a502..46d9546 100644 --- a/Utilities/cmlibuv/src/uv-common.c +++ b/Utilities/cmlibuv/src/uv-common.c @@ -613,7 +613,9 @@ uv_loop_t* uv_loop_new(void) { int uv_loop_close(uv_loop_t* loop) { QUEUE* q; uv_handle_t* h; +#ifndef NDEBUG void* saved_data; +#endif if (!QUEUE_EMPTY(&(loop)->active_reqs)) return UV_EBUSY; ----------------------------------------------------------------------- Summary of changes: Utilities/cmlibuv/CMakeLists.txt | 8 ++++---- Utilities/cmlibuv/src/uv-common.c | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 09:42:11 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 09:42:11 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1489-g82e6501 Message-ID: <20160826134211.5D57DF3AEC@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 82e65010ed8cbc807604fc618baa7fc176613a8b (commit) via 426f97d35300555fc5360698b6a6f0da2ba18169 (commit) from c3bcd014a7452256dcbf738d753944a8d7ed3d78 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=82e65010ed8cbc807604fc618baa7fc176613a8b commit 82e65010ed8cbc807604fc618baa7fc176613a8b Merge: c3bcd01 426f97d Author: Brad King AuthorDate: Fri Aug 26 09:42:10 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 26 09:42:10 2016 -0400 Merge topic 'cpack-rpm-debuginfo-pkg' into next 426f97d3 CPack/RPM: Add test for debuginfo package generation https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=426f97d35300555fc5360698b6a6f0da2ba18169 commit 426f97d35300555fc5360698b6a6f0da2ba18169 Author: Domen Vrankar AuthorDate: Thu Aug 25 18:35:42 2016 +0200 Commit: Brad King CommitDate: Fri Aug 26 09:40:37 2016 -0400 CPack/RPM: Add test for debuginfo package generation diff --git a/Help/release/dev/cpack-rpm-debuginfo-pkg.rst b/Help/release/dev/cpack-rpm-debuginfo-pkg.rst new file mode 100644 index 0000000..8b37fe4 --- /dev/null +++ b/Help/release/dev/cpack-rpm-debuginfo-pkg.rst @@ -0,0 +1,6 @@ +cpack-rpm-debuginfo-pkg +----------------------- + +* The :module:`CPackRPM` module learned to generate debuginfo + packages on demand. See :variable:`CPACK_RPM_DEBUGINFO_PACKAGE` + and its per component version. diff --git a/Tests/RunCMake/CPack/DEBUGINFO.cmake b/Tests/RunCMake/CPack/DEBUGINFO.cmake new file mode 100644 index 0000000..2a65b7f --- /dev/null +++ b/Tests/RunCMake/CPack/DEBUGINFO.cmake @@ -0,0 +1,26 @@ +set(CMAKE_BUILD_WITH_INSTALL_RPATH 1) + +set(CPACK_RPM_COMPONENT_INSTALL "ON") + +set(CMAKE_BUILD_TYPE Debug) + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.hpp" + "int test_lib();\n") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp" + "#include \"test_lib.hpp\"\nint test_lib() {return 0;}\n") +add_library(test_lib SHARED "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp") + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp" + "#include \"test_lib.hpp\"\nint main() {return test_lib();}\n") +add_executable(test_prog "${CMAKE_CURRENT_BINARY_DIR}/main.cpp") +target_link_libraries(test_prog test_lib) + +install(TARGETS test_prog DESTINATION foo COMPONENT applications) +install(FILES CMakeLists.txt DESTINATION bar COMPONENT headers) +install(TARGETS test_lib DESTINATION bas COMPONENT libs) + +set(CPACK_RPM_APPLICATIONS_FILE_NAME "RPM-DEFAULT") +set(CPACK_RPM_APPLICATIONS_DEBUGINFO_PACKAGE ON) +set(CPACK_RPM_LIBS_DEBUGINFO_PACKAGE ON) + +set(CPACK_PACKAGE_NAME "debuginfo") diff --git a/Tests/RunCMake/CPack/RPM/DEBUGINFO-ExpectedFiles.cmake b/Tests/RunCMake/CPack/RPM/DEBUGINFO-ExpectedFiles.cmake new file mode 100644 index 0000000..265ca92 --- /dev/null +++ b/Tests/RunCMake/CPack/RPM/DEBUGINFO-ExpectedFiles.cmake @@ -0,0 +1,14 @@ +set(whitespaces_ "[\t\n\r ]*") + +set(EXPECTED_FILES_COUNT "5") +set(EXPECTED_FILE_1 "debuginfo-applications-0*.rpm") +set(EXPECTED_FILE_CONTENT_1 "^/usr/foo${whitespaces_}/usr/foo/test_prog$") +set(EXPECTED_FILE_2 "debuginfo*-headers.rpm") +set(EXPECTED_FILE_CONTENT_2 "^/usr/bar${whitespaces_}/usr/bar/CMakeLists.txt$") +set(EXPECTED_FILE_3 "debuginfo*-libs.rpm") +set(EXPECTED_FILE_CONTENT_3 "^/usr/bas${whitespaces_}/usr/bas/libtest_lib.so$") + +set(EXPECTED_FILE_4 "debuginfo-applications-debuginfo*.rpm") +set(EXPECTED_FILE_CONTENT_4 ".*") +set(EXPECTED_FILE_5 "debuginfo-libs-debuginfo*.rpm") +set(EXPECTED_FILE_CONTENT_5 ".*") diff --git a/Tests/RunCMake/CPack/RPM/DEBUGINFO-stderr.txt b/Tests/RunCMake/CPack/RPM/DEBUGINFO-stderr.txt new file mode 100644 index 0000000..557ef3d --- /dev/null +++ b/Tests/RunCMake/CPack/RPM/DEBUGINFO-stderr.txt @@ -0,0 +1,3 @@ +^CPackRPM: Will use GENERATED spec file: .*/Tests/RunCMake/RPM/CPack/DEBUGINFO-build/_CPack_Packages/.*/RPM/SPECS/debuginfo-applications.spec +CPackRPM: Will use GENERATED spec file: .*/Tests/RunCMake/RPM/CPack/DEBUGINFO-build/_CPack_Packages/.*/RPM/SPECS/debuginfo-headers.spec +CPackRPM: Will use GENERATED spec file: .*/Tests/RunCMake/RPM/CPack/DEBUGINFO-build/_CPack_Packages/.*/RPM/SPECS/debuginfo-libs.spec$ diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake index 59c52f8..44586d7 100644 --- a/Tests/RunCMake/CPack/RunCMakeTest.cmake +++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake @@ -16,3 +16,4 @@ run_cpack_test(RPM_DIST "RPM" false) run_cpack_test(INSTALL_SCRIPTS "RPM" false) run_cpack_test(DEB_GENERATE_SHLIBS "DEB" true) run_cpack_test(DEB_GENERATE_SHLIBS_LDCONFIG "DEB" true) +run_cpack_test(DEBUGINFO "RPM" true) ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 09:45:30 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 09:45:30 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-736-gda7111e Message-ID: <20160826134530.A8FF8F4951@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via da7111e1a34bd8b85a98ed1ebc14f65c499748be (commit) via f325ae186d5d235cb90f4fb002a8df56abc050f8 (commit) from ff88df48e8a693f213a44aee3ad2474f500857b5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=da7111e1a34bd8b85a98ed1ebc14f65c499748be commit da7111e1a34bd8b85a98ed1ebc14f65c499748be Merge: ff88df4 f325ae1 Author: Brad King AuthorDate: Fri Aug 26 09:45:28 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 26 09:45:28 2016 -0400 Merge topic 'vs-resource-pri-dir' f325ae18 VS: Use target-specific directory for `resources.pri` ----------------------------------------------------------------------- Summary of changes: Source/cmVisualStudio10TargetGenerator.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 09:45:33 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 09:45:33 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-738-gd65584f Message-ID: <20160826134533.56311F4972@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via d65584f7a3074ff9887a4e540cfdbd48a4628c22 (commit) via cd344e3a62e3a6728e5b749cb923104c2c09949c (commit) from da7111e1a34bd8b85a98ed1ebc14f65c499748be (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d65584f7a3074ff9887a4e540cfdbd48a4628c22 commit d65584f7a3074ff9887a4e540cfdbd48a4628c22 Merge: da7111e cd344e3 Author: Brad King AuthorDate: Fri Aug 26 09:45:31 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 26 09:45:31 2016 -0400 Merge topic 'test-driver-clang-tidy' cd344e3a create_test_sourcelist: Use safer strncpy instead of strcpy ----------------------------------------------------------------------- Summary of changes: Templates/TestDriver.cxx.in | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 09:45:36 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 09:45:36 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-741-g135c785 Message-ID: <20160826134536.06C2DF4972@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 135c78554944250e9a15efe2bc60e9f8197ff2a1 (commit) via 20d7da5276704864569fb08259278a08c5f9e725 (commit) via 4ef8a205edf66b652418aa5491436d26fd806175 (commit) from d65584f7a3074ff9887a4e540cfdbd48a4628c22 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=135c78554944250e9a15efe2bc60e9f8197ff2a1 commit 135c78554944250e9a15efe2bc60e9f8197ff2a1 Merge: d65584f 20d7da5 Author: Brad King AuthorDate: Fri Aug 26 09:45:34 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 26 09:45:34 2016 -0400 Merge topic 'FindwxWidgets-library-path' 20d7da52 FindwxWidgets: Add VS-versioned library directory prefixes 4ef8a205 FindwxWidgets: Add version 3.1.0 ----------------------------------------------------------------------- Summary of changes: Modules/FindwxWidgets.cmake | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 09:45:39 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 09:45:39 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-744-g41f03f5 Message-ID: <20160826134539.2D1CBF4A0A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 41f03f5fa794e05745ff2975b7d8854e3a4a7792 (commit) via 426f97d35300555fc5360698b6a6f0da2ba18169 (commit) via bc8c0add7f799ad5775e4f229256832e17156b68 (commit) from 135c78554944250e9a15efe2bc60e9f8197ff2a1 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=41f03f5fa794e05745ff2975b7d8854e3a4a7792 commit 41f03f5fa794e05745ff2975b7d8854e3a4a7792 Merge: 135c785 426f97d Author: Brad King AuthorDate: Fri Aug 26 09:45:36 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 26 09:45:36 2016 -0400 Merge topic 'cpack-rpm-debuginfo-pkg' 426f97d3 CPack/RPM: Add test for debuginfo package generation bc8c0add CPack RPM debuginfo packages generation ----------------------------------------------------------------------- Summary of changes: Help/release/dev/cpack-rpm-debuginfo-pkg.rst | 6 ++ Modules/CPackRPM.cmake | 65 +++++++++++++++++++- .../CPack/{DEPENDENCIES.cmake => DEBUGINFO.cmake} | 12 +++- .../CPack/RPM/DEBUGINFO-ExpectedFiles.cmake | 14 +++++ Tests/RunCMake/CPack/RPM/DEBUGINFO-stderr.txt | 3 + Tests/RunCMake/CPack/RunCMakeTest.cmake | 1 + 6 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 Help/release/dev/cpack-rpm-debuginfo-pkg.rst copy Tests/RunCMake/CPack/{DEPENDENCIES.cmake => DEBUGINFO.cmake} (74%) create mode 100644 Tests/RunCMake/CPack/RPM/DEBUGINFO-ExpectedFiles.cmake create mode 100644 Tests/RunCMake/CPack/RPM/DEBUGINFO-stderr.txt hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 09:45:41 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 09:45:41 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-746-g21c946e Message-ID: <20160826134543.1B895F4889@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 21c946eef4e11e6161cc46b265fbeb128ea1baf7 (commit) via 24e7ccb7ef486191ebb9fca916c70e367c41b2fb (commit) from 41f03f5fa794e05745ff2975b7d8854e3a4a7792 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=21c946eef4e11e6161cc46b265fbeb128ea1baf7 commit 21c946eef4e11e6161cc46b265fbeb128ea1baf7 Merge: 41f03f5 24e7ccb Author: Brad King AuthorDate: Fri Aug 26 09:45:39 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 26 09:45:39 2016 -0400 Merge topic 'update-curl-script' 24e7ccb7 curl: Update script to get curl from new repository ----------------------------------------------------------------------- Summary of changes: Utilities/Scripts/update-curl.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 09:47:07 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 09:47:07 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1495-g7184f48 Message-ID: <20160826134707.E66D4F4D2A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 7184f486f54f39fd1584a876ca67c27da07e97b2 (commit) via 21c946eef4e11e6161cc46b265fbeb128ea1baf7 (commit) via 41f03f5fa794e05745ff2975b7d8854e3a4a7792 (commit) via 135c78554944250e9a15efe2bc60e9f8197ff2a1 (commit) via d65584f7a3074ff9887a4e540cfdbd48a4628c22 (commit) via da7111e1a34bd8b85a98ed1ebc14f65c499748be (commit) from 82e65010ed8cbc807604fc618baa7fc176613a8b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7184f486f54f39fd1584a876ca67c27da07e97b2 commit 7184f486f54f39fd1584a876ca67c27da07e97b2 Merge: 82e6501 21c946e Author: Brad King AuthorDate: Fri Aug 26 09:46:59 2016 -0400 Commit: Brad King CommitDate: Fri Aug 26 09:46:59 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 09:56:19 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 09:56:19 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1497-g037fa07 Message-ID: <20160826135619.C0593F59A9@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 037fa07721e5c990f30e8116d987916d87fddd56 (commit) via 38995d19b806e8cc1d43fab0422beefd4c23431f (commit) from 7184f486f54f39fd1584a876ca67c27da07e97b2 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=037fa07721e5c990f30e8116d987916d87fddd56 commit 037fa07721e5c990f30e8116d987916d87fddd56 Merge: 7184f48 38995d1 Author: Brad King AuthorDate: Fri Aug 26 09:56:19 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 26 09:56:19 2016 -0400 Merge topic 'code-blocks-include-order' into next 38995d19 CodeBlocks: List C++ includes first https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=38995d19b806e8cc1d43fab0422beefd4c23431f commit 38995d19b806e8cc1d43fab0422beefd4c23431f Author: Kevin Ottens AuthorDate: Wed Aug 17 22:45:06 2016 +0200 Commit: Brad King CommitDate: Fri Aug 26 09:55:30 2016 -0400 CodeBlocks: List C++ includes first When using the Clang Code Model in QtCreator, it turned out that having the C system include dirs can make it report false positives for most uses of the STL. This is due to the order the Clang Code Model looks at the include directories and some C includes in /usr/include could be incompatible with the used STL if found first. diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index 559974e..6eae26b 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -593,7 +593,7 @@ void cmExtraCodeBlocksGenerator::AppendTarget( includes.end()); std::string systemIncludeDirs = makefile->GetSafeDefinition( - "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS"); + "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS"); if (!systemIncludeDirs.empty()) { std::vector dirs; cmSystemTools::ExpandListArgument(systemIncludeDirs, dirs); @@ -601,7 +601,7 @@ void cmExtraCodeBlocksGenerator::AppendTarget( } systemIncludeDirs = makefile->GetSafeDefinition( - "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS"); + "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS"); if (!systemIncludeDirs.empty()) { std::vector dirs; cmSystemTools::ExpandListArgument(systemIncludeDirs, dirs); ----------------------------------------------------------------------- Summary of changes: Source/cmExtraCodeBlocksGenerator.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 10:04:21 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 10:04:21 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1499-gc583e88 Message-ID: <20160826140421.4C5F7F5B7E@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via c583e887954417fd07e64061039da5184d35ee69 (commit) via 1f4aeb1739fb632ab5162a977764b51736728edc (commit) from 037fa07721e5c990f30e8116d987916d87fddd56 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c583e887954417fd07e64061039da5184d35ee69 commit c583e887954417fd07e64061039da5184d35ee69 Merge: 037fa07 1f4aeb1 Author: Brad King AuthorDate: Fri Aug 26 10:04:20 2016 -0400 Commit: CMake Topic Stage CommitDate: Fri Aug 26 10:04:20 2016 -0400 Merge topic 'vs-NsightTegra-empty-version' into next 1f4aeb17 VS: Fix out-of-bounds write on empty Nsight Tegra version https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1f4aeb1739fb632ab5162a977764b51736728edc commit 1f4aeb1739fb632ab5162a977764b51736728edc Author: Fujii Hironori AuthorDate: Fri Aug 26 15:28:48 2016 +0900 Commit: Brad King CommitDate: Fri Aug 26 10:01:39 2016 -0400 VS: Fix out-of-bounds write on empty Nsight Tegra version In cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator, wrote 0 to this->NsightTegraVersion[-1] if sscanf returns -1 which is the case of GetNsightTegraVersion is empty. diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index fb05976..009f9a2 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -183,13 +183,12 @@ cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator( this->GUID = this->GlobalGenerator->GetGUID(this->Name.c_str()); this->Platform = gg->GetPlatformName(); this->NsightTegra = gg->IsNsightTegra(); - for (int i = - sscanf(gg->GetNsightTegraVersion().c_str(), "%u.%u.%u.%u", - &this->NsightTegraVersion[0], &this->NsightTegraVersion[1], - &this->NsightTegraVersion[2], &this->NsightTegraVersion[3]); - i < 4; ++i) { + for (int i = 0; i < 4; ++i) { this->NsightTegraVersion[i] = 0; } + sscanf(gg->GetNsightTegraVersion().c_str(), "%u.%u.%u.%u", + &this->NsightTegraVersion[0], &this->NsightTegraVersion[1], + &this->NsightTegraVersion[2], &this->NsightTegraVersion[3]); this->MSTools = !this->NsightTegra; this->TargetCompileAsWinRT = false; this->BuildFileStream = 0; ----------------------------------------------------------------------- Summary of changes: Source/cmVisualStudio10TargetGenerator.cxx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 10:05:10 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 10:05:10 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-748-ga749ab8 Message-ID: <20160826140510.CB922F5B95@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via a749ab8f3ddaf2eab470d1d567be69acab359f63 (commit) via 83fd4a7039f46e458186274feb3ba397a4f58bb8 (commit) from 21c946eef4e11e6161cc46b265fbeb128ea1baf7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 10:05:11 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 10:05:11 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1502-g61cdf5d Message-ID: <20160826140511.9158FF5B94@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 61cdf5d4af56e5e5f7d30448828cc7a35a8ae4a7 (commit) via a749ab8f3ddaf2eab470d1d567be69acab359f63 (commit) via 83fd4a7039f46e458186274feb3ba397a4f58bb8 (commit) from c583e887954417fd07e64061039da5184d35ee69 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=61cdf5d4af56e5e5f7d30448828cc7a35a8ae4a7 commit 61cdf5d4af56e5e5f7d30448828cc7a35a8ae4a7 Merge: c583e88 a749ab8 Author: Brad King AuthorDate: Fri Aug 26 10:04:58 2016 -0400 Commit: Brad King CommitDate: Fri Aug 26 10:04:58 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Fri Aug 26 10:05:11 2016 From: brad.king at kitware.com (Brad King) Date: Fri, 26 Aug 2016 10:05:11 -0400 (EDT) Subject: [Cmake-commits] CMake branch, release, updated. v3.6.1-24-g83fd4a7 Message-ID: <20160826140511.E276EF5B9A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, release has been updated via 83fd4a7039f46e458186274feb3ba397a4f58bb8 (commit) via f699323ade84bb672ed0998de73c6f0333981bc1 (commit) from fc552ce1c70e702d26508261090a07ebe1c426a1 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- ----------------------------------------------------------------------- Summary of changes: Source/cmDependsFortran.cxx | 6 ++++++ 1 file changed, 6 insertions(+) hooks/post-receive -- CMake From kwrobot at kitware.com Sat Aug 27 00:01:07 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Sat, 27 Aug 2016 00:01:07 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-749-g8973460 Message-ID: <20160827040107.9ECBDF5861@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 897346032b33ebd033cda9bcb5d094f1c112f37d (commit) from a749ab8f3ddaf2eab470d1d567be69acab359f63 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=897346032b33ebd033cda9bcb5d094f1c112f37d commit 897346032b33ebd033cda9bcb5d094f1c112f37d Author: Kitware Robot AuthorDate: Sat Aug 27 00:01:05 2016 -0400 Commit: Kitware Robot CommitDate: Sat Aug 27 00:01:05 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index e8a4d2c..770b6bd 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160826) +set(CMake_VERSION_PATCH 20160827) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From steveire at gmail.com Sat Aug 27 07:45:33 2016 From: steveire at gmail.com (Stephen Kelly) Date: Sat, 27 Aug 2016 07:45:33 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1531-g738e3e9 Message-ID: <20160827114533.BDE6FF3CC2@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 738e3e9d9af191e7f118e182bb3ba3690430e2af (commit) via 6ad153786f119e994662c2ec05059cdf46d9dbad (commit) via a11a408a6edcb956fe9ba7a141cfbfd8e94078d6 (commit) via bfa30fa10056b0ee07a58b7d09bc87617fbb7cd2 (commit) via 12520e0f723916bb803946d6ba6f5f929bba0120 (commit) via f9d90d054510548490d0a7555b186201ae9f1a45 (commit) via f57933cac8dfd8d4c64d970b1991c263154b0a82 (commit) via bed34f1bd81edd04d55a46cf43658b8339aac1de (commit) via 861e2da31d76947b8358930c9f43eed0aa15b642 (commit) via bb1985c5408ac6c130c3f94197fcd987b7e7edc2 (commit) via 8c020fc541e6a00736c9897f791e1a3ea76ef0d6 (commit) via e3da80d92561e8a5fdc65fb0a5db18e09cf9ef1e (commit) via fe916d26c37622ee0c6198385dcf86ea7fb545dc (commit) via e7c62e41461995c3ad73be65cb7a9f63e77081b9 (commit) via fcb3a56802c4bf8757424375baf3c4fe053aafbd (commit) via 9a296bc30b860e3360fbc4b7adaa1113461a1c89 (commit) via e99e08cc167535daf324d81d510ca8f818ce924c (commit) via ca4bddc08179c8c9c1585f1949bbc840869c1d9f (commit) via 064724040af65c7edc985877b637560620136565 (commit) via be096139cf7380f89d8aaad3ea283559b27b2614 (commit) via cd351ef2c427284eea0ab494eba5d4f24bc0e050 (commit) via fbd83948675f4b1cb487d59390cfe1689f801fc0 (commit) via c341f4679ad00cb65c7660b474ddabd13d0ef498 (commit) via 6960516b6b053816313d2ff5ee4e9375a84829cb (commit) via e0fd2d0446101847dd40cfe4cc451667d04ddcd9 (commit) via ad70a236f4368c21c08bcd4ea4d28425176c4e17 (commit) via e3ca17e13b8d2aecc6d97ac800d65c6c35378a98 (commit) via 0bbdbd95c9515a4714ef1d57a17c7271bc4d1774 (commit) via 9440d5776bf48778d452e2d3a48d4e93d7b6f7a7 (commit) from 61cdf5d4af56e5e5f7d30448828cc7a35a8ae4a7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=738e3e9d9af191e7f118e182bb3ba3690430e2af commit 738e3e9d9af191e7f118e182bb3ba3690430e2af Merge: 61cdf5d 6ad1537 Author: Stephen Kelly AuthorDate: Sat Aug 27 07:45:30 2016 -0400 Commit: CMake Topic Stage CommitDate: Sat Aug 27 07:45:30 2016 -0400 Merge topic 'cleanup-Convert' into next 6ad15378 Convert: Make variables a bit more clear a11a408a Convert: Remove UNCHANGED enum value bfa30fa1 Convert: Remove 'FULL' conversion 12520e0f Convert: Replace Convert(FULL) with equivalent f9d90d05 Ninja: Replace ternary with if() f57933ca Convert: Replace trivial conversion with new method bed34f1b Convert: Replace UNCHANGED conversions with new API call 861e2da3 Convert: Extract ConvertToRelativePath from Convert() bb1985c5 Convert: Replace FULL conversions with equivalent 8c020fc5 VS: Replace FULL/UNCHANGED conversion with equivalent e3da80d9 Convert: Remove NONE conversion fe916d26 Convert: Replace uses of Convert(NONE) e7c62e41 VS: Replace variable with an if() fcb3a568 Makefiles: Replace ternaries with if()s 9a296bc3 Makefiles: Inline MakeLauncher into only caller e99e08cc Makefiles: Simplify MakeLauncher return value ... https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6ad153786f119e994662c2ec05059cdf46d9dbad commit 6ad153786f119e994662c2ec05059cdf46d9dbad Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:58 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:58 2016 +0200 Convert: Make variables a bit more clear diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index f056a1b..630da42 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -49,26 +49,26 @@ std::string cmOutputConverter::ConvertToOutputForExisting( std::string cmOutputConverter::ConvertToRelativePath( const std::string& source, RelativeRoot relative) const { - std::string result = source; + std::string result; switch (relative) { case HOME: result = this->ConvertToRelativePath( - this->GetState()->GetSourceDirectoryComponents(), result); + this->GetState()->GetSourceDirectoryComponents(), source); break; case START: result = this->ConvertToRelativePath( this->StateSnapshot.GetDirectory().GetCurrentSourceComponents(), - result); + source); break; case HOME_OUTPUT: result = this->ConvertToRelativePath( - this->GetState()->GetBinaryDirectoryComponents(), result); + this->GetState()->GetBinaryDirectoryComponents(), source); break; case START_OUTPUT: result = this->ConvertToRelativePath( this->StateSnapshot.GetDirectory().GetCurrentBinaryComponents(), - result); + source); break; } return result; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a11a408a6edcb956fe9ba7a141cfbfd8e94078d6 commit a11a408a6edcb956fe9ba7a141cfbfd8e94078d6 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:57 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:57 2016 +0200 Convert: Remove UNCHANGED enum value It is no longer used. diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index d3f9d64..b433c18 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -57,9 +57,9 @@ protected: // The windows module definition source file (.def), if any. cmSourceFile const* ModuleDefinitionFile; - std::string Convert( - std::string const& source, cmOutputConverter::RelativeRoot relative, - cmOutputConverter::OutputFormat output = cmOutputConverter::UNCHANGED); + std::string Convert(std::string const& source, + cmOutputConverter::RelativeRoot relative, + cmOutputConverter::OutputFormat output); void AppendFortranFormatFlags(std::string& flags, cmSourceFile const& source); diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index c2403db..9af9659 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -45,7 +45,6 @@ public: }; enum OutputFormat { - UNCHANGED, MAKERULE, SHELL, WATCOMQUOTE, @@ -54,7 +53,7 @@ public: std::string ConvertToOutputFormat(const std::string& source, OutputFormat output) const; std::string Convert(const std::string& remote, RelativeRoot local, - OutputFormat output = UNCHANGED) const; + OutputFormat output) const; std::string ConvertToRelativePath(const std::string& remote, RelativeRoot local) const; std::string ConvertDirectorySeparatorsForShell( https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bfa30fa10056b0ee07a58b7d09bc87617fbb7cd2 commit bfa30fa10056b0ee07a58b7d09bc87617fbb7cd2 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:57 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:57 2016 +0200 Convert: Remove 'FULL' conversion It is no longer used. diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 176c9a0..f056a1b 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -70,9 +70,6 @@ std::string cmOutputConverter::ConvertToRelativePath( this->StateSnapshot.GetDirectory().GetCurrentBinaryComponents(), result); break; - case FULL: - result = cmSystemTools::CollapseFullPath(result); - break; } return result; } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 71bb086..c2403db 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -38,7 +38,6 @@ public: */ enum RelativeRoot { - FULL, HOME, START, HOME_OUTPUT, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=12520e0f723916bb803946d6ba6f5f929bba0120 commit 12520e0f723916bb803946d6ba6f5f929bba0120 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:57 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:57 2016 +0200 Convert: Replace Convert(FULL) with equivalent This is more explicit than funnelling everything through the Convert method. diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index bbc794d..77fbbe9 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -723,8 +723,9 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # in target - progCmd << lg->Convert(progress.Dir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << lg->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progress.Dir), + cmOutputConverter::SHELL); // std::set emitted; progCmd << " " << this->CountProgressMarksInTarget(gtarget, emitted); @@ -736,8 +737,9 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0 - progCmd << lg->Convert(progress.Dir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << lg->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progress.Dir), + cmOutputConverter::SHELL); progCmd << " 0"; commands.push_back(progCmd.str()); } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 2fa3f86..de9e1e5 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -688,7 +688,9 @@ std::string cmLocalGenerator::ExpandRuleVariable( } } if (variable == "CMAKE_COMMAND") { - return this->Convert(cmSystemTools::GetCMakeCommand(), FULL, SHELL); + return this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()), + SHELL); } std::vector enabledLanguages = this->GetState()->GetEnabledLanguages(); @@ -1183,7 +1185,8 @@ void cmLocalGenerator::GetTargetFlags( if (sf->GetExtension() == "def") { linkFlags += this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG"); - linkFlags += this->Convert(sf->GetFullPath(), FULL, SHELL); + linkFlags += this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(sf->GetFullPath()), SHELL); linkFlags += " "; } } diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index bbec634..d07bfaa 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -133,7 +133,8 @@ std::string cmLocalNinjaGenerator::ConvertToIncludeReference( bool forceFullPaths) { if (forceFullPaths) { - return this->Convert(path, cmOutputConverter::FULL, format); + return this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(path), + format); } return this->Convert(path, cmOutputConverter::HOME_OUTPUT, format); } diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index efccb4a..81251f9 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -640,9 +640,9 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( std::string cmakeShellCommand = this->MaybeConvertWacomShellCommand(cmSystemTools::GetCMakeCommand()); if (cmakeShellCommand.empty()) { - cmakeShellCommand = - this->Convert(cmSystemTools::GetCMakeCommand(), cmOutputConverter::FULL, - cmOutputConverter::SHELL); + cmakeShellCommand = this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()), + cmOutputConverter::SHELL); } /* clang-format off */ @@ -665,16 +665,14 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( makefileStream << "# The top-level source directory on which CMake was run.\n" << "CMAKE_SOURCE_DIR = " - << this->Convert(this->GetSourceDirectory(), - cmOutputConverter::FULL, + << this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(this->GetSourceDirectory()), cmOutputConverter::SHELL) << "\n" << "\n"; makefileStream << "# The top-level build directory on which CMake was run.\n" << "CMAKE_BINARY_DIR = " - << this->Convert(this->GetBinaryDirectory(), - cmOutputConverter::FULL, + << this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(this->GetBinaryDirectory()), cmOutputConverter::SHELL) << "\n" << "\n"; @@ -1153,8 +1151,9 @@ void cmLocalUnixMakefileGenerator3::AppendEcho( cmd += color_name; if (progress) { cmd += "--progress-dir="; - cmd += this->Convert(progress->Dir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + cmd += this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progress->Dir), + cmOutputConverter::SHELL); cmd += " "; cmd += "--progress-num="; cmd += progress->Arg; @@ -1602,15 +1601,16 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; - progCmd << this->Convert(progressDir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL); std::string progressFile = cmake::GetCMakeFilesDirectory(); progressFile += "/progress.marks"; std::string progressFileNameFull = this->ConvertToFullPath(progressFile); progCmd << " " - << this->Convert(progressFileNameFull, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progressFileNameFull), + cmOutputConverter::SHELL); commands.push_back(progCmd.str()); } std::string mf2Dir = cmake::GetCMakeFilesDirectoryPostSlash(); @@ -1622,8 +1622,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0 - progCmd << this->Convert(progressDir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL); progCmd << " 0"; commands.push_back(progCmd.str()); } diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 1beaa87..70fe819 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -269,8 +269,8 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() args += this->GetBinaryDirectory(); commandLine.push_back(args); commandLine.push_back("--check-stamp-file"); - std::string stampFilename = this->Convert( - stampName.c_str(), cmOutputConverter::FULL, cmOutputConverter::SHELL); + std::string stampFilename = this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(stampName), cmOutputConverter::SHELL); commandLine.push_back(stampFilename.c_str()); std::vector const& listFiles = this->Makefile->GetListFiles(); diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index d1cefe3..b492962 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -155,7 +155,8 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( script += newline; newline = newline_text; script += "cd "; - script += this->Convert(workingDirectory, FULL, SHELL); + script += this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(workingDirectory), SHELL); script += check_error; // Change the working drive. diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index b34cd6e..165f96c 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1000,9 +1000,10 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() // paths. Make sure PWD is set to the original name of the home // output directory to help cmSystemTools to create the same // translation table for the dependency scanning process. - depCmd << "cd " << (this->LocalGenerator->Convert( - this->LocalGenerator->GetBinaryDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL)) + depCmd << "cd " << (this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetBinaryDirectory()), + cmOutputConverter::SHELL)) << " && "; #endif // Generate a call this signature: @@ -1016,20 +1017,29 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() // the state of our local generator sufficiently for its needs. depCmd << "$(CMAKE_COMMAND) -E cmake_depends \"" << this->GlobalGenerator->GetName() << "\" " - << this->Convert(this->LocalGenerator->GetSourceDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetSourceDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->LocalGenerator->GetCurrentSourceDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetCurrentSourceDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->LocalGenerator->GetBinaryDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetBinaryDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->LocalGenerator->GetCurrentBinaryDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetCurrentBinaryDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->InfoFileNameFull, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(this->InfoFileNameFull), + cmOutputConverter::SHELL); if (this->LocalGenerator->GetColorMakefile()) { depCmd << " --color=$(COLOR)"; } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f9d90d054510548490d0a7555b186201ae9f1a45 commit f9d90d054510548490d0a7555b186201ae9f1a45 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:57 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:57 2016 +0200 Ninja: Replace ternary with if() On principle of segregating the interface. diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 9e2c920..bbec634 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -132,9 +132,10 @@ std::string cmLocalNinjaGenerator::ConvertToIncludeReference( std::string const& path, cmOutputConverter::OutputFormat format, bool forceFullPaths) { - return this->Convert(path, forceFullPaths ? cmOutputConverter::FULL - : cmOutputConverter::HOME_OUTPUT, - format); + if (forceFullPaths) { + return this->Convert(path, cmOutputConverter::FULL, format); + } + return this->Convert(path, cmOutputConverter::HOME_OUTPUT, format); } // Private methods. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f57933cac8dfd8d4c64d970b1991c263154b0a82 commit f57933cac8dfd8d4c64d970b1991c263154b0a82 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:56 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:56 2016 +0200 Convert: Replace trivial conversion with new method diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index 18e123e..928f7ec 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -238,8 +238,8 @@ bool cmDependsC::WriteDependencies(const std::set& sources, // written by the original local generator for this directory // convert the dependencies to paths relative to the home output // directory. We must do the same here. - std::string obj_i = - this->LocalGenerator->Convert(obj, cmOutputConverter::HOME_OUTPUT); + std::string obj_i = this->LocalGenerator->ConvertToRelativePath( + obj, cmOutputConverter::HOME_OUTPUT); std::string obj_m = this->LocalGenerator->ConvertToOutputFormat( obj_i, cmOutputConverter::MAKERULE); internalDepends << obj_i << std::endl; diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index c57b558..8c0acce 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -193,15 +193,15 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends, stamp += ".mod.stamp"; fcStream << "\n"; fcStream << " \"" - << this->LocalGenerator->Convert( + << this->LocalGenerator->ConvertToRelativePath( mod_lower, cmOutputConverter::START_OUTPUT) << "\"\n"; fcStream << " \"" - << this->LocalGenerator->Convert( + << this->LocalGenerator->ConvertToRelativePath( mod_upper, cmOutputConverter::START_OUTPUT) << "\"\n"; fcStream << " \"" - << this->LocalGenerator->Convert( + << this->LocalGenerator->ConvertToRelativePath( stamp, cmOutputConverter::START_OUTPUT) << "\"\n"; } @@ -317,8 +317,8 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, const char* src = info.Source.c_str(); // Write the include dependencies to the output stream. - std::string obj_i = - this->LocalGenerator->Convert(obj, cmOutputConverter::HOME_OUTPUT); + std::string obj_i = this->LocalGenerator->ConvertToRelativePath( + obj, cmOutputConverter::HOME_OUTPUT); std::string obj_m = this->LocalGenerator->ConvertToOutputFormat( obj_i, cmOutputConverter::MAKERULE); internalDepends << obj_i << std::endl; diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index e617b08..945ee40 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -904,8 +904,8 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const it != this->GlobalGenerator->GetLocalGenerators().end(); ++it) { const std::vector targets = (*it)->GetGeneratorTargets(); - std::string subdir = (*it)->Convert((*it)->GetCurrentBinaryDirectory(), - cmOutputConverter::HOME_OUTPUT); + std::string subdir = (*it)->ConvertToRelativePath( + (*it)->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT); if (subdir == ".") { subdir = ""; } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 295f65b..50c5a42 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -2547,8 +2547,8 @@ void cmGlobalGenerator::AddRuleHash(const std::vector& outputs, // Shorten the output name (in expected use case). cmOutputConverter converter(this->GetMakefiles()[0]->GetStateSnapshot()); - std::string fname = - converter.Convert(outputs[0], cmOutputConverter::HOME_OUTPUT); + std::string fname = converter.ConvertToRelativePath( + outputs[0], cmOutputConverter::HOME_OUTPUT); // Associate the hash with this output. this->RuleHashes[fname] = hash; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 2b83479..939c5ad 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -747,7 +747,8 @@ std::string cmGlobalNinjaGenerator::ConvertToNinjaPath(const std::string& path) { cmLocalNinjaGenerator* ng = static_cast(this->LocalGenerators[0]); - std::string convPath = ng->Convert(path, cmOutputConverter::HOME_OUTPUT); + std::string convPath = + ng->ConvertToRelativePath(path, cmOutputConverter::HOME_OUTPUT); convPath = this->NinjaOutputPath(convPath); #ifdef _WIN32 std::replace(convPath.begin(), convPath.end(), '/', '\\'); @@ -760,7 +761,8 @@ std::string cmGlobalNinjaGenerator::ConvertToNinjaFolderRule( { cmLocalNinjaGenerator* ng = static_cast(this->LocalGenerators[0]); - std::string convPath = ng->Convert(path + "/all", cmOutputConverter::HOME); + std::string convPath = + ng->ConvertToRelativePath(path + "/all", cmOutputConverter::HOME); convPath = this->NinjaOutputPath(convPath); #ifdef _WIN32 std::replace(convPath.begin(), convPath.end(), '/', '\\'); diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index f115ecb..bbc794d 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -311,11 +311,14 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() cmakefileStream << "# The top level Makefile was generated from the following files:\n" << "set(CMAKE_MAKEFILE_DEPENDS\n" - << " \"" << lg->Convert(cache, cmOutputConverter::START_OUTPUT) << "\"\n"; + << " \"" + << lg->ConvertToRelativePath(cache, cmOutputConverter::START_OUTPUT) + << "\"\n"; for (std::vector::const_iterator i = lfiles.begin(); i != lfiles.end(); ++i) { cmakefileStream << " \"" - << lg->Convert(*i, cmOutputConverter::START_OUTPUT) + << lg->ConvertToRelativePath( + *i, cmOutputConverter::START_OUTPUT) << "\"\n"; } cmakefileStream << " )\n\n"; @@ -329,10 +332,12 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() cmakefileStream << "# The corresponding makefile is:\n" << "set(CMAKE_MAKEFILE_OUTPUTS\n" << " \"" - << lg->Convert(makefileName, cmOutputConverter::START_OUTPUT) + << lg->ConvertToRelativePath(makefileName, + cmOutputConverter::START_OUTPUT) << "\"\n" << " \"" - << lg->Convert(check, cmOutputConverter::START_OUTPUT) + << lg->ConvertToRelativePath(check, + cmOutputConverter::START_OUTPUT) << "\"\n"; cmakefileStream << " )\n\n"; @@ -345,7 +350,8 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() for (std::vector::const_iterator k = outfiles.begin(); k != outfiles.end(); ++k) { cmakefileStream << " \"" - << lg->Convert(*k, cmOutputConverter::HOME_OUTPUT) + << lg->ConvertToRelativePath( + *k, cmOutputConverter::HOME_OUTPUT) << "\"\n"; } @@ -358,7 +364,8 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() tmpStr += cmake::GetCMakeFilesDirectory(); tmpStr += "/CMakeDirectoryInformation.cmake"; cmakefileStream << " \"" - << lg->Convert(tmpStr, cmOutputConverter::HOME_OUTPUT) + << lg->ConvertToRelativePath( + tmpStr, cmOutputConverter::HOME_OUTPUT) << "\"\n"; } cmakefileStream << " )\n\n"; @@ -519,7 +526,7 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( tname += "/fast"; } cmOutputConverter conv(mf->GetStateSnapshot()); - tname = conv.Convert(tname, cmOutputConverter::HOME_OUTPUT); + tname = conv.ConvertToRelativePath(tname, cmOutputConverter::HOME_OUTPUT); cmSystemTools::ConvertToOutputSlashes(tname); makeCommand.push_back(tname); if (this->Makefiles.empty()) { diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 0a83b3a..67ac230 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -385,7 +385,8 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( if (vcprojName) { cmLocalGenerator* lg = target->GetLocalGenerator(); std::string dir = lg->GetCurrentBinaryDirectory(); - dir = root->Convert(dir.c_str(), cmOutputConverter::START_OUTPUT); + dir = root->ConvertToRelativePath(dir.c_str(), + cmOutputConverter::START_OUTPUT); if (dir == ".") { dir = ""; // msbuild cannot handle ".\" prefix } diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 39d9e97..3c5e333 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -402,7 +402,8 @@ void cmListFileBacktrace::PrintTitle(std::ostream& out) const cmOutputConverter converter(this->Bottom); cmListFileContext lfc = *this->Cur; if (!this->Bottom.GetState()->GetIsInTryCompile()) { - lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME); + lfc.FilePath = + converter.ConvertToRelativePath(lfc.FilePath, cmOutputConverter::HOME); } out << (lfc.Line ? " at " : " in ") << lfc; } @@ -427,7 +428,8 @@ void cmListFileBacktrace::PrintCallStack(std::ostream& out) const } cmListFileContext lfc = *i; if (!this->Bottom.GetState()->GetIsInTryCompile()) { - lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME); + lfc.FilePath = + converter.ConvertToRelativePath(lfc.FilePath, cmOutputConverter::HOME); } out << " " << lfc << "\n"; } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 20a1e21..2fa3f86 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -176,7 +176,7 @@ void cmLocalGenerator::GenerateTestFiles() // TODO: Use add_subdirectory instead? fout << "subdirs("; std::string outP = children[i].GetDirectory().GetCurrentBinary(); - fout << this->Convert(outP, START_OUTPUT); + fout << this->ConvertToRelativePath(outP, START_OUTPUT); fout << ")" << std::endl; } } @@ -2237,7 +2237,8 @@ std::string cmLocalGenerator::ConstructComment( for (std::vector::const_iterator o = ccg.GetOutputs().begin(); o != ccg.GetOutputs().end(); ++o) { comment += sep; - comment += this->Convert(*o, cmOutputConverter::START_OUTPUT); + comment += + this->ConvertToRelativePath(*o, cmOutputConverter::START_OUTPUT); sep = ", "; } return comment; @@ -2505,13 +2506,14 @@ std::string cmLocalGenerator::GetObjectFileNameWithoutTarget( const char* fullPath = source.GetFullPath().c_str(); // Try referencing the source relative to the source tree. - std::string relFromSource = this->Convert(fullPath, START); + std::string relFromSource = this->ConvertToRelativePath(fullPath, START); assert(!relFromSource.empty()); bool relSource = !cmSystemTools::FileIsFullPath(relFromSource.c_str()); bool subSource = relSource && relFromSource[0] != '.'; // Try referencing the source relative to the binary tree. - std::string relFromBinary = this->Convert(fullPath, START_OUTPUT); + std::string relFromBinary = + this->ConvertToRelativePath(fullPath, START_OUTPUT); assert(!relFromBinary.empty()); bool relBinary = !cmSystemTools::FileIsFullPath(relFromBinary.c_str()); bool subBinary = relBinary && relFromBinary[0] != '.'; diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 8c092e7..9e2c920 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -41,7 +41,7 @@ void cmLocalNinjaGenerator::Generate() { // Compute the path to use when referencing the current output // directory from the top output directory. - this->HomeRelativeOutputPath = this->Convert( + this->HomeRelativeOutputPath = this->ConvertToRelativePath( this->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT); if (this->HomeRelativeOutputPath == ".") { this->HomeRelativeOutputPath = ""; diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index a50b1b6..efccb4a 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -140,7 +140,7 @@ void cmLocalUnixMakefileGenerator3::ComputeHomeRelativeOutputPath() { // Compute the path to use when referencing the current output // directory from the top output directory. - this->HomeRelativeOutputPath = this->Convert( + this->HomeRelativeOutputPath = this->ConvertToRelativePath( this->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT); if (this->HomeRelativeOutputPath == ".") { this->HomeRelativeOutputPath = ""; @@ -966,7 +966,8 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( // working directory will be the start-output directory. bool had_slash = cmd.find('/') != cmd.npos; if (workingDir.empty()) { - cmd = this->Convert(cmd, cmOutputConverter::START_OUTPUT); + cmd = + this->ConvertToRelativePath(cmd, cmOutputConverter::START_OUTPUT); } bool has_slash = cmd.find('/') != cmd.npos; if (had_slash && !has_slash) { @@ -1850,7 +1851,8 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( for (std::vector::iterator i = includes.begin(); i != includes.end(); ++i) { cmakefileStream << " \"" - << this->Convert(*i, cmOutputConverter::HOME_OUTPUT) + << this->ConvertToRelativePath( + *i, cmOutputConverter::HOME_OUTPUT) << "\"\n"; } cmakefileStream << " )\n"; @@ -1914,7 +1916,8 @@ std::string cmLocalUnixMakefileGenerator3::GetRecursiveMakeCall( // Add the target. if (!tgt.empty()) { // The make target is always relative to the top of the build tree. - std::string tgt2 = this->Convert(tgt, cmOutputConverter::HOME_OUTPUT); + std::string tgt2 = + this->ConvertToRelativePath(tgt, cmOutputConverter::HOME_OUTPUT); // The target may have been written with windows paths. cmSystemTools::ConvertToOutputSlashes(tgt2); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 2d53669..b34cd6e 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -312,8 +312,10 @@ void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()( output += "/"; output += cmSystemTools::GetFilenameName(input); this->Generator->CleanFiles.push_back( - this->Generator->Convert(output, cmOutputConverter::START_OUTPUT)); - output = this->Generator->Convert(output, cmOutputConverter::HOME_OUTPUT); + this->Generator->LocalGenerator->ConvertToRelativePath( + output, cmOutputConverter::START_OUTPUT)); + output = this->Generator->LocalGenerator->ConvertToRelativePath( + output, cmOutputConverter::HOME_OUTPUT); // Create a rule to copy the content into the bundle. std::vector depends; @@ -1171,7 +1173,8 @@ void cmMakefileTargetGenerator::WriteObjectsVariable( for (std::vector::const_iterator i = this->ExternalObjects.begin(); i != this->ExternalObjects.end(); ++i) { - object = this->Convert(*i, cmOutputConverter::START_OUTPUT); + object = this->LocalGenerator->ConvertToRelativePath( + *i, cmOutputConverter::START_OUTPUT); *this->BuildFileStream << " " << lineContinue << "\n" << this->Makefile->GetSafeDefinition( "CMAKE_OBJECT_NAME"); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index ed04d2f..d5274cd 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -602,7 +602,8 @@ void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const it != this->TLLCommands.end(); ++it) { if (it->first == sig) { cmListFileContext lfc = it->second; - lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME); + lfc.FilePath = + converter.ConvertToRelativePath(lfc.FilePath, cmOutputConverter::HOME); s << " * " << lfc << std::endl; } } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bed34f1bd81edd04d55a46cf43658b8339aac1de commit bed34f1bd81edd04d55a46cf43658b8339aac1de Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:56 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:56 2016 +0200 Convert: Replace UNCHANGED conversions with new API call diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 242493d..a50b1b6 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1075,8 +1075,8 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand( fout << "file(REMOVE_RECURSE\n"; for (std::vector::const_iterator f = files.begin(); f != files.end(); ++f) { - std::string fc = this->Convert(*f, cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + std::string fc = + this->ConvertToRelativePath(*f, cmOutputConverter::START_OUTPUT); fout << " " << cmOutputConverter::EscapeForCMake(fc) << "\n"; } fout << ")\n"; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 497defb..1beaa87 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -788,8 +788,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( target->GetProperty("Fortran_MODULE_DIRECTORY"); std::string modDir; if (target_mod_dir) { - modDir = this->Convert(target_mod_dir, cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + modDir = this->ConvertToRelativePath(target_mod_dir, + cmOutputConverter::START_OUTPUT); } else { modDir = "."; } @@ -1300,9 +1300,8 @@ void cmLocalVisualStudio7GeneratorInternals::OutputLibraries( cmLocalVisualStudio7Generator* lg = this->LocalGenerator; for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) { if (l->IsPath) { - std::string rel = - lg->Convert(l->Value.c_str(), cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + std::string rel = lg->ConvertToRelativePath( + l->Value.c_str(), cmOutputConverter::START_OUTPUT); fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " "; } else if (!l->Target || l->Target->GetType() != cmState::INTERFACE_LIBRARY) { @@ -1322,8 +1321,8 @@ void cmLocalVisualStudio7GeneratorInternals::OutputObjects( const char* sep = isep ? isep : ""; for (std::vector::const_iterator oi = objs.begin(); oi != objs.end(); ++oi) { - std::string rel = lg->Convert(oi->c_str(), cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + std::string rel = + lg->ConvertToRelativePath(oi->c_str(), cmOutputConverter::START_OUTPUT); fout << sep << lg->ConvertToXMLOutputPath(rel.c_str()); sep = " "; } @@ -1346,9 +1345,8 @@ void cmLocalVisualStudio7Generator::OutputLibraryDirectories( // Switch to a relative path specification if it is shorter. if (cmSystemTools::FileIsFullPath(dir.c_str())) { - std::string rel = - this->Convert(dir.c_str(), cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + std::string rel = this->ConvertToRelativePath( + dir.c_str(), cmOutputConverter::START_OUTPUT); if (rel.size() < dir.size()) { dir = rel; } diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index a14df79..66e1ca2 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -218,40 +218,34 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Construct a list of files associated with this executable that // may need to be cleaned. std::vector exeCleanFiles; - exeCleanFiles.push_back(this->Convert(targetFullPath, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPath, cmOutputConverter::START_OUTPUT)); #ifdef _WIN32 // There may be a manifest file for this target. Add it to the // clean set just in case. - exeCleanFiles.push_back(this->Convert((targetFullPath + ".manifest").c_str(), - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + (targetFullPath + ".manifest").c_str(), cmOutputConverter::START_OUTPUT)); #endif if (targetNameReal != targetName) { - exeCleanFiles.push_back(this->Convert(targetFullPathReal, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathReal, cmOutputConverter::START_OUTPUT)); } if (!targetNameImport.empty()) { - exeCleanFiles.push_back(this->Convert(targetFullPathImport, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathImport, cmOutputConverter::START_OUTPUT)); std::string implib; if (this->GeneratorTarget->GetImplibGNUtoMS(targetFullPathImport, implib)) { - exeCleanFiles.push_back(this->Convert(implib, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + implib, cmOutputConverter::START_OUTPUT)); } } // List the PDB for cleaning only when the whole target is // cleaned. We do not want to delete the .pdb file just before // linking the target. - this->CleanFiles.push_back(this->Convert(targetFullPathPDB, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + this->CleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathPDB, cmOutputConverter::START_OUTPUT)); // Add the pre-build and pre-link rules building but not when relinking. if (!relink) { diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index c8ee05f..b85243e 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -367,46 +367,40 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // Clean files associated with this library. std::vector libCleanFiles; - libCleanFiles.push_back(this->Convert(targetFullPath, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPath, cmOutputConverter::START_OUTPUT)); if (targetNameReal != targetName) { - libCleanFiles.push_back(this->Convert(targetFullPathReal, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathReal, cmOutputConverter::START_OUTPUT)); } if (targetNameSO != targetName && targetNameSO != targetNameReal) { - libCleanFiles.push_back(this->Convert(targetFullPathSO, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathSO, cmOutputConverter::START_OUTPUT)); } if (!targetNameImport.empty()) { - libCleanFiles.push_back(this->Convert(targetFullPathImport, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathImport, cmOutputConverter::START_OUTPUT)); std::string implib; if (this->GeneratorTarget->GetImplibGNUtoMS(targetFullPathImport, implib)) { - libCleanFiles.push_back(this->Convert(implib, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + implib, cmOutputConverter::START_OUTPUT)); } } // List the PDB for cleaning only when the whole target is // cleaned. We do not want to delete the .pdb file just before // linking the target. - this->CleanFiles.push_back(this->Convert(targetFullPathPDB, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + this->CleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathPDB, cmOutputConverter::START_OUTPUT)); #ifdef _WIN32 // There may be a manifest file for this target. Add it to the // clean set just in case. if (this->GeneratorTarget->GetType() != cmState::STATIC_LIBRARY) { - libCleanFiles.push_back(this->Convert( - (targetFullPath + ".manifest").c_str(), cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back( + this->ConvertToRelativePath((targetFullPath + ".manifest").c_str(), + cmOutputConverter::START_OUTPUT)); } #endif diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index dd4333d..2d53669 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -172,8 +172,8 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() const std::vector& outputs = ccg.GetOutputs(); for (std::vector::const_iterator o = outputs.begin(); o != outputs.end(); ++o) { - this->CleanFiles.push_back(this->Convert( - *o, cmOutputConverter::START_OUTPUT, cmOutputConverter::UNCHANGED)); + this->CleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + *o, cmOutputConverter::START_OUTPUT)); } } } @@ -1258,9 +1258,8 @@ void cmMakefileTargetGenerator::WriteTargetDriverRule( this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget); std::string buildTargetRuleName = dir; buildTargetRuleName += relink ? "/preinstall" : "/build"; - buildTargetRuleName = - this->Convert(buildTargetRuleName, cmOutputConverter::HOME_OUTPUT, - cmOutputConverter::UNCHANGED); + buildTargetRuleName = this->LocalGenerator->ConvertToRelativePath( + buildTargetRuleName, cmOutputConverter::HOME_OUTPUT); // Build the list of target outputs to drive. std::vector depends; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 1b1d04b..216de03 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2416,9 +2416,8 @@ void cmVisualStudio10TargetGenerator::AddLibraries( ItemVector libs = cli.GetItems(); for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) { if (l->IsPath) { - std::string path = this->LocalGenerator->Convert( - l->Value.c_str(), cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + std::string path = this->LocalGenerator->ConvertToRelativePath( + l->Value.c_str(), cmOutputConverter::START_OUTPUT); this->ConvertToWindowsSlash(path); libVec.push_back(path); } else if (!l->Target || https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=861e2da31d76947b8358930c9f43eed0aa15b642 commit 861e2da31d76947b8358930c9f43eed0aa15b642 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:56 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:56 2016 +0200 Convert: Extract ConvertToRelativePath from Convert() Convert() does some kind of relative conversion, followed by a conversion to 'output format'. Make it possible to do the former without the latter. diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 80fa4bf..176c9a0 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -46,11 +46,9 @@ std::string cmOutputConverter::ConvertToOutputForExisting( return this->ConvertToOutputFormat(remote, format); } -std::string cmOutputConverter::Convert(const std::string& source, - RelativeRoot relative, - OutputFormat output) const +std::string cmOutputConverter::ConvertToRelativePath( + const std::string& source, RelativeRoot relative) const { - // Convert the path to a relative path. std::string result = source; switch (relative) { @@ -76,6 +74,15 @@ std::string cmOutputConverter::Convert(const std::string& source, result = cmSystemTools::CollapseFullPath(result); break; } + return result; +} + +std::string cmOutputConverter::Convert(const std::string& source, + RelativeRoot relative, + OutputFormat output) const +{ + // Convert the path to a relative path. + std::string result = this->ConvertToRelativePath(source, relative); return this->ConvertToOutputFormat(result, output); } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 0f4884e..71bb086 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -56,6 +56,8 @@ public: OutputFormat output) const; std::string Convert(const std::string& remote, RelativeRoot local, OutputFormat output = UNCHANGED) const; + std::string ConvertToRelativePath(const std::string& remote, + RelativeRoot local) const; std::string ConvertDirectorySeparatorsForShell( const std::string& source) const; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bb1985c5408ac6c130c3f94197fcd987b7e7edc2 commit bb1985c5408ac6c130c3f94197fcd987b7e7edc2 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:55 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:55 2016 +0200 Convert: Replace FULL conversions with equivalent diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 594357f..242493d 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1066,8 +1066,7 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand( cleanfile += filename; } cleanfile += ".cmake"; - std::string cleanfilePath = - this->Convert(cleanfile, cmOutputConverter::FULL); + std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile); cmsys::ofstream fout(cleanfilePath.c_str()); if (!fout) { cmSystemTools::Error("Could not create ", cleanfilePath.c_str()); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 7747aa7..dd4333d 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -393,9 +393,9 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( std::string objFullPath = this->LocalGenerator->GetCurrentBinaryDirectory(); objFullPath += "/"; objFullPath += obj; - objFullPath = this->Convert(objFullPath, cmOutputConverter::FULL); + objFullPath = cmSystemTools::CollapseFullPath(objFullPath); std::string srcFullPath = - this->Convert(source.GetFullPath(), cmOutputConverter::FULL); + cmSystemTools::CollapseFullPath(source.GetFullPath()); this->LocalGenerator->AddImplicitDepends( this->GeneratorTarget, lang, objFullPath.c_str(), srcFullPath.c_str()); } @@ -584,9 +584,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( lang_can_export_cmds && compileCommands.size() == 1) { std::string compileCommand = compileCommands[0]; this->LocalGenerator->ExpandRuleVariables(compileCommand, vars); - std::string workingDirectory = this->LocalGenerator->Convert( - this->LocalGenerator->GetCurrentBinaryDirectory(), - cmOutputConverter::FULL); + std::string workingDirectory = cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetCurrentBinaryDirectory()); compileCommand.replace(compileCommand.find(langFlags), langFlags.size(), this->GetFlags(lang)); std::string langDefines = std::string("$(") + lang + "_DEFINES)"; @@ -1115,10 +1114,8 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile( for (cmCustomCommand::ImplicitDependsList::const_iterator idi = ccg.GetCC().GetImplicitDepends().begin(); idi != ccg.GetCC().GetImplicitDepends().end(); ++idi) { - std::string objFullPath = - this->Convert(outputs[0], cmOutputConverter::FULL); - std::string srcFullPath = - this->Convert(idi->second, cmOutputConverter::FULL); + std::string objFullPath = cmSystemTools::CollapseFullPath(outputs[0]); + std::string srcFullPath = cmSystemTools::CollapseFullPath(idi->second); this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, idi->first, objFullPath.c_str(), srcFullPath.c_str()); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8c020fc541e6a00736c9897f791e1a3ea76ef0d6 commit 8c020fc541e6a00736c9897f791e1a3ea76ef0d6 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:55 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:55 2016 +0200 VS: Replace FULL/UNCHANGED conversion with equivalent diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index e72abe9..497defb 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -278,8 +278,8 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() cmCustomCommandLines commandLines; commandLines.push_back(commandLine); const char* no_working_directory = 0; - std::string fullpathStampName = this->Convert( - stampName.c_str(), cmOutputConverter::FULL, cmOutputConverter::UNCHANGED); + std::string fullpathStampName = + cmSystemTools::CollapseFullPath(stampName.c_str()); this->Makefile->AddCustomCommandToOutput( fullpathStampName.c_str(), listFiles, makefileIn.c_str(), commandLines, comment.c_str(), no_working_directory, true); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e3da80d92561e8a5fdc65fb0a5db18e09cf9ef1e commit e3da80d92561e8a5fdc65fb0a5db18e09cf9ef1e Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:55 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:55 2016 +0200 Convert: Remove NONE conversion It is no longer used. diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 98872d6..80fa4bf 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -75,8 +75,6 @@ std::string cmOutputConverter::Convert(const std::string& source, case FULL: result = cmSystemTools::CollapseFullPath(result); break; - case NONE: - break; } return this->ConvertToOutputFormat(result, output); } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index ff06ab6..0f4884e 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -38,7 +38,6 @@ public: */ enum RelativeRoot { - NONE, FULL, HOME, START, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=fe916d26c37622ee0c6198385dcf86ea7fb545dc commit fe916d26c37622ee0c6198385dcf86ea7fb545dc Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:55 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:55 2016 +0200 Convert: Replace uses of Convert(NONE) These are equivalent to ConvertToOutputFormat. diff --git a/Source/cmLocalCommonGenerator.cxx b/Source/cmLocalCommonGenerator.cxx index 5502296..1383421 100644 --- a/Source/cmLocalCommonGenerator.cxx +++ b/Source/cmLocalCommonGenerator.cxx @@ -74,8 +74,7 @@ std::string cmLocalCommonGenerator::GetTargetFortranFlags( for (std::vector::const_iterator idi = includes.begin(); idi != includes.end(); ++idi) { std::string flg = modpath_flag; - flg += - this->Convert(*idi, cmOutputConverter::NONE, cmOutputConverter::SHELL); + flg += this->ConvertToOutputFormat(*idi, cmOutputConverter::SHELL); this->AppendFlags(flags, flg); } } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index d8f6bdf..20a1e21 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1393,7 +1393,7 @@ std::string cmLocalGenerator::ConvertToLinkReference(std::string const& lib, sp += lib.substr(pos); // Convert to an output path. - return this->Convert(sp.c_str(), NONE, format); + return this->ConvertToOutputFormat(sp.c_str(), format); } } } @@ -1489,7 +1489,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, for (std::vector::const_iterator fdi = fwDirs.begin(); fdi != fwDirs.end(); ++fdi) { frameworkPath += fwSearchFlag; - frameworkPath += this->Convert(*fdi, NONE, shellFormat); + frameworkPath += this->ConvertToOutputFormat(*fdi, shellFormat); frameworkPath += " "; } } @@ -1535,7 +1535,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, for (std::vector::iterator ri = runtimeDirs.begin(); ri != runtimeDirs.end(); ++ri) { rpath += cli.GetRuntimeFlag(); - rpath += this->Convert(*ri, NONE, shellFormat); + rpath += this->ConvertToOutputFormat(*ri, shellFormat); rpath += " "; } fout << rpath; @@ -1605,7 +1605,7 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags, flags += " "; flags += sysrootFlag; flags += " "; - flags += this->Convert(sysroot, NONE, SHELL); + flags += this->ConvertToOutputFormat(sysroot, SHELL); } if (deploymentTargetFlag && *deploymentTargetFlag && deploymentTarget && diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 58c336d..8c092e7 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -490,8 +490,8 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher( output = this->Convert(outputs[0], cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); } else { - output = this->Convert(outputs[0], cmOutputConverter::NONE, - cmOutputConverter::SHELL); + output = + this->ConvertToOutputFormat(outputs[0], cmOutputConverter::SHELL); } } vars.Output = output.c_str(); diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 820ad19..594357f 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -602,8 +602,7 @@ std::string cmLocalUnixMakefileGenerator3::MaybeConvertWacomShellCommand( // lines with shell redirection operators. std::string scmd; if (cmSystemTools::GetShortPath(cmd, scmd)) { - return this->Convert(scmd, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + return this->ConvertToOutputFormat(scmd, cmOutputConverter::SHELL); } } return std::string(); @@ -790,8 +789,8 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom( std::string runRule = "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; runRule += " --check-build-system "; - runRule += this->Convert(cmakefileName, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + runRule += + this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); runRule += " 0"; std::vector no_depends; @@ -995,8 +994,8 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( cmOutputConverter::SHELL); } else { - output = this->Convert(outputs[0], cmOutputConverter::NONE, - cmOutputConverter::SHELL); + output = this->ConvertToOutputFormat(outputs[0], + cmOutputConverter::SHELL); } } vars.Output = output.c_str(); @@ -1680,8 +1679,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( std::string runRule = "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; runRule += " --check-build-system "; - runRule += this->Convert(cmakefileName, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + runRule += + this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); runRule += " 1"; commands.push_back(runRule); this->CreateCDCommand(commands, this->GetBinaryDirectory(), @@ -1894,8 +1893,7 @@ std::string cmLocalUnixMakefileGenerator3::GetRecursiveMakeCall( // Call make on the given file. std::string cmd; cmd += "$(MAKE) -f "; - cmd += - this->Convert(makefile, cmOutputConverter::NONE, cmOutputConverter::SHELL); + cmd += this->ConvertToOutputFormat(makefile, cmOutputConverter::SHELL); cmd += " "; cmGlobalUnixMakefileGenerator3* gg = diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index ca006b7..d1cefe3 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -205,7 +205,7 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( if (workingDirectory.empty()) { script += this->Convert(cmd.c_str(), START_OUTPUT, SHELL); } else { - script += this->Convert(cmd.c_str(), NONE, SHELL); + script += this->ConvertToOutputFormat(cmd.c_str(), SHELL); } ccg.AppendArguments(c, script); diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 74bfedc..a14df79 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -135,8 +135,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) std::string targetFullPathReal = outpath + targetNameReal; std::string targetFullPathPDB = pdbOutputPath + targetNamePDB; std::string targetFullPathImport = outpathImp + targetNameImport; - std::string targetOutPathPDB = this->Convert( - targetFullPathPDB, cmOutputConverter::NONE, cmOutputConverter::SHELL); + std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( + targetFullPathPDB, cmOutputConverter::SHELL); // Convert to the output path to use in constructing commands. std::string targetOutPath = this->Convert( targetFullPath, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); @@ -357,9 +357,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) vars.Manifests = manifests.c_str(); if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE")) { - std::string cmakeCommand = - this->Convert(cmSystemTools::GetCMakeCommand(), cmLocalGenerator::NONE, - cmLocalGenerator::SHELL); + std::string cmakeCommand = this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); cmakeCommand += " -E __run_iwyu --lwyu="; cmakeCommand += targetOutPathReal; real_link_commands.push_back(cmakeCommand); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 6727bd0..c8ee05f 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -310,8 +310,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // Construct the output path version of the names for use in command // arguments. - std::string targetOutPathPDB = this->Convert( - targetFullPathPDB, cmOutputConverter::NONE, cmOutputConverter::SHELL); + std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( + targetFullPathPDB, cmOutputConverter::SHELL); std::string targetOutPath = this->Convert( targetFullPath, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); std::string targetOutPathSO = @@ -572,8 +572,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( vars.TargetInstallNameDir = ""; } else { // Convert to a path for the native build tool. - install_name_dir = this->LocalGenerator->Convert( - install_name_dir, cmOutputConverter::NONE, cmOutputConverter::SHELL); + install_name_dir = this->LocalGenerator->ConvertToOutputFormat( + install_name_dir, cmOutputConverter::SHELL); vars.TargetInstallNameDir = install_name_dir.c_str(); } } @@ -640,9 +640,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( cmSystemTools::ExpandListArgument(linkRule, real_link_commands); if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE") && (this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY)) { - std::string cmakeCommand = - this->Convert(cmSystemTools::GetCMakeCommand(), - cmLocalGenerator::NONE, cmLocalGenerator::SHELL); + std::string cmakeCommand = this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); cmakeCommand += " -E __run_iwyu --lwyu="; cmakeCommand += targetOutPathReal; real_link_commands.push_back(cmakeCommand); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 5bba29c..7747aa7 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -324,11 +324,11 @@ void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()( this->Generator->LocalGenerator->AppendEcho( commands, copyEcho, cmLocalUnixMakefileGenerator3::EchoBuild); std::string copyCommand = "$(CMAKE_COMMAND) -E copy "; - copyCommand += this->Generator->Convert(input, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + copyCommand += this->Generator->LocalGenerator->ConvertToOutputFormat( + input, cmOutputConverter::SHELL); copyCommand += " "; - copyCommand += this->Generator->Convert(output, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + copyCommand += this->Generator->LocalGenerator->ConvertToOutputFormat( + output, cmOutputConverter::SHELL); commands.push_back(copyCommand); this->Generator->LocalGenerator->WriteMakeRule( *this->Generator->BuildFileStream, CM_NULLPTR, output, depends, commands, @@ -464,8 +464,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( } // Get the output paths for source and object files. - std::string sourceFile = this->Convert( - source.GetFullPath(), cmOutputConverter::NONE, cmOutputConverter::SHELL); + std::string sourceFile = this->LocalGenerator->ConvertToOutputFormat( + source.GetFullPath(), cmOutputConverter::SHELL); // Construct the build message. std::vector no_commands; @@ -516,8 +516,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( targetOutPathReal = this->Convert(targetFullPathReal, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); - targetOutPathPDB = this->Convert( - targetFullPathPDB, cmOutputConverter::NONE, cmOutputConverter::SHELL); + targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( + targetFullPathPDB, cmOutputConverter::SHELL); targetOutPathCompilePDB = this->Convert(targetFullPathCompilePDB, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); @@ -539,7 +539,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( vars.TargetCompilePDB = targetOutPathCompilePDB.c_str(); vars.Source = sourceFile.c_str(); std::string shellObj = - this->Convert(obj, cmOutputConverter::NONE, cmOutputConverter::SHELL); + this->LocalGenerator->ConvertToOutputFormat(obj, cmOutputConverter::SHELL); vars.Object = shellObj.c_str(); std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); objectDir = this->Convert(objectDir, cmOutputConverter::START_OUTPUT, @@ -699,8 +699,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( std::vector preprocessCommands; cmSystemTools::ExpandListArgument(preprocessRule, preprocessCommands); - std::string shellObjI = this->Convert(objI, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + std::string shellObjI = this->LocalGenerator->ConvertToOutputFormat( + objI, cmOutputConverter::SHELL); vars.PreprocessedSource = shellObjI.c_str(); // Expand placeholders in the commands. @@ -746,8 +746,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( std::vector assemblyCommands; cmSystemTools::ExpandListArgument(assemblyRule, assemblyCommands); - std::string shellObjS = this->Convert(objS, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + std::string shellObjS = this->LocalGenerator->ConvertToOutputFormat( + objS, cmOutputConverter::SHELL); vars.AssemblySource = shellObjS.c_str(); // Expand placeholders in the commands. @@ -1576,8 +1576,8 @@ void cmMakefileTargetGenerator::CreateLinkLibs( // Reference the response file. linkLibs = responseFlag; - linkLibs += this->Convert(link_rsp, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + linkLibs += this->LocalGenerator->ConvertToOutputFormat( + link_rsp, cmOutputConverter::SHELL); } } @@ -1625,8 +1625,8 @@ void cmMakefileTargetGenerator::CreateObjectLists( // Reference the response file. buildObjs += responseFlag; - buildObjs += this->Convert(objects_rsp, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + buildObjs += this->LocalGenerator->ConvertToOutputFormat( + objects_rsp, cmOutputConverter::SHELL); } } else if (useLinkScript) { if (!useArchiveRules) { @@ -1683,8 +1683,8 @@ void cmMakefileTargetGenerator::GenDefFile( name_of_def_file += std::string("/") + this->GeneratorTarget->GetName(); name_of_def_file += ".def"; std::string cmd = cmSystemTools::GetCMakeCommand(); - cmd = - this->Convert(cmd, cmOutputConverter::NONE, cmOutputConverter::SHELL); + cmd = this->LocalGenerator->ConvertToOutputFormat( + cmd, cmOutputConverter::SHELL); cmd += " -E __create_def "; cmd += this->Convert(name_of_def_file, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index d0db133..335b552 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -543,8 +543,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() std::string install_dir = this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName); if (!install_dir.empty()) { - vars["INSTALLNAME_DIR"] = localGen.Convert( - install_dir, cmOutputConverter::NONE, cmOutputConverter::SHELL); + vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat( + install_dir, cmOutputConverter::SHELL); } } } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e7c62e41461995c3ad73be65cb7a9f63e77081b9 commit e7c62e41461995c3ad73be65cb7a9f63e77081b9 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:54 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:54 2016 +0200 VS: Replace variable with an if() diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index bdb1c2b..ca006b7 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -127,7 +127,6 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( { bool useLocal = this->CustomCommandUseLocal(); std::string workingDirectory = ccg.GetWorkingDirectory(); - RelativeRoot relativeRoot = workingDirectory.empty() ? START_OUTPUT : NONE; // Avoid leading or trailing newlines. std::string newline = ""; @@ -203,7 +202,11 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( } } - script += this->Convert(cmd.c_str(), relativeRoot, SHELL); + if (workingDirectory.empty()) { + script += this->Convert(cmd.c_str(), START_OUTPUT, SHELL); + } else { + script += this->Convert(cmd.c_str(), NONE, SHELL); + } ccg.AppendArguments(c, script); // After each custom command, check for an error result. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=fcb3a56802c4bf8757424375baf3c4fe053aafbd commit fcb3a56802c4bf8757424375baf3c4fe053aafbd Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:54 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:54 2016 +0200 Makefiles: Replace ternaries with if()s diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 46d7e18..58c336d 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -486,12 +486,13 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher( std::string output; const std::vector& outputs = ccg.GetOutputs(); if (!outputs.empty()) { - cmOutputConverter::RelativeRoot relative_root = - ccg.GetWorkingDirectory().empty() ? cmOutputConverter::START_OUTPUT - : cmOutputConverter::NONE; - - output = - this->Convert(outputs[0], relative_root, cmOutputConverter::SHELL); + if (ccg.GetWorkingDirectory().empty()) { + output = this->Convert(outputs[0], cmOutputConverter::START_OUTPUT, + cmOutputConverter::SHELL); + } else { + output = this->Convert(outputs[0], cmOutputConverter::NONE, + cmOutputConverter::SHELL); + } } vars.Output = output.c_str(); diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index d7f6b66..820ad19 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -990,10 +990,14 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( std::string output; const std::vector& outputs = ccg.GetOutputs(); if (!outputs.empty()) { - output = this->Convert(outputs[0], workingDir.empty() - ? cmOutputConverter::START_OUTPUT - : cmOutputConverter::NONE, - cmOutputConverter::SHELL); + if (workingDir.empty()) { + output = this->Convert(outputs[0], cmOutputConverter::START_OUTPUT, + cmOutputConverter::SHELL); + + } else { + output = this->Convert(outputs[0], cmOutputConverter::NONE, + cmOutputConverter::SHELL); + } } vars.Output = output.c_str(); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9a296bc30b860e3360fbc4b7adaa1113461a1c89 commit 9a296bc30b860e3360fbc4b7adaa1113461a1c89 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:54 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:54 2016 +0200 Makefiles: Inline MakeLauncher into only caller diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 1c66eb6..d7f6b66 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -976,9 +976,33 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( // without the current directory being in the search path. cmd = "./" + cmd; } - std::string launcher = this->MakeLauncher( - ccg, target, workingDir.empty() ? cmOutputConverter::START_OUTPUT - : cmOutputConverter::NONE); + + std::string launcher; + // Short-circuit if there is no launcher. + const char* prop = "RULE_LAUNCH_CUSTOM"; + const char* val = this->GetRuleLauncher(target, prop); + if (val && *val) { + // Expand rules in the empty string. It may insert the launcher and + // perform replacements. + RuleVariables vars; + vars.RuleLauncher = prop; + vars.CMTarget = target; + std::string output; + const std::vector& outputs = ccg.GetOutputs(); + if (!outputs.empty()) { + output = this->Convert(outputs[0], workingDir.empty() + ? cmOutputConverter::START_OUTPUT + : cmOutputConverter::NONE, + cmOutputConverter::SHELL); + } + vars.Output = output.c_str(); + + this->ExpandRuleVariables(launcher, vars); + if (!launcher.empty()) { + launcher += " "; + } + } + std::string shellCommand = this->MaybeConvertWacomShellCommand(cmd); if (shellCommand.empty()) { shellCommand = cmd; @@ -1026,35 +1050,6 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( commands.insert(commands.end(), commands1.begin(), commands1.end()); } -std::string cmLocalUnixMakefileGenerator3::MakeLauncher( - cmCustomCommandGenerator const& ccg, cmGeneratorTarget* target, - cmOutputConverter::RelativeRoot relative) -{ - std::string launcher; - // Short-circuit if there is no launcher. - const char* prop = "RULE_LAUNCH_CUSTOM"; - const char* val = this->GetRuleLauncher(target, prop); - if (val && *val) { - // Expand rules in the empty string. It may insert the launcher and - // perform replacements. - RuleVariables vars; - vars.RuleLauncher = prop; - vars.CMTarget = target; - std::string output; - const std::vector& outputs = ccg.GetOutputs(); - if (!outputs.empty()) { - output = this->Convert(outputs[0], relative, cmOutputConverter::SHELL); - } - vars.Output = output.c_str(); - - this->ExpandRuleVariables(launcher, vars); - if (!launcher.empty()) { - launcher += " "; - } - } - return launcher; -} - void cmLocalUnixMakefileGenerator3::AppendCleanCommand( std::vector& commands, const std::vector& files, cmGeneratorTarget* target, const char* filename) diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index 9541f65..bc7566e 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -251,9 +251,6 @@ protected: private: std::string MaybeConvertWacomShellCommand(std::string const& cmd); - std::string MakeLauncher(cmCustomCommandGenerator const& ccg, - cmGeneratorTarget* target, - cmOutputConverter::RelativeRoot relative); void ComputeObjectFilenames( std::map& mapping, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e99e08cc167535daf324d81d510ca8f818ce924c commit e99e08cc167535daf324d81d510ca8f818ce924c Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:54 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:54 2016 +0200 Makefiles: Simplify MakeLauncher return value Bonus NRVO. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 5190a95..1c66eb6 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1030,6 +1030,7 @@ std::string cmLocalUnixMakefileGenerator3::MakeLauncher( cmCustomCommandGenerator const& ccg, cmGeneratorTarget* target, cmOutputConverter::RelativeRoot relative) { + std::string launcher; // Short-circuit if there is no launcher. const char* prop = "RULE_LAUNCH_CUSTOM"; const char* val = this->GetRuleLauncher(target, prop); @@ -1046,14 +1047,12 @@ std::string cmLocalUnixMakefileGenerator3::MakeLauncher( } vars.Output = output.c_str(); - std::string launcher; this->ExpandRuleVariables(launcher, vars); if (!launcher.empty()) { launcher += " "; } - return launcher; } - return ""; + return launcher; } void cmLocalUnixMakefileGenerator3::AppendCleanCommand( https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ca4bddc08179c8c9c1585f1949bbc840869c1d9f commit ca4bddc08179c8c9c1585f1949bbc840869c1d9f Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:54 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:54 2016 +0200 Makefiles: Invert logic in MakeLauncher Make it easier to inline into the caller. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index b3d601a..5190a95 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1033,28 +1033,27 @@ std::string cmLocalUnixMakefileGenerator3::MakeLauncher( // Short-circuit if there is no launcher. const char* prop = "RULE_LAUNCH_CUSTOM"; const char* val = this->GetRuleLauncher(target, prop); - if (!(val && *val)) { - return ""; - } - - // Expand rules in the empty string. It may insert the launcher and - // perform replacements. - RuleVariables vars; - vars.RuleLauncher = prop; - vars.CMTarget = target; - std::string output; - const std::vector& outputs = ccg.GetOutputs(); - if (!outputs.empty()) { - output = this->Convert(outputs[0], relative, cmOutputConverter::SHELL); - } - vars.Output = output.c_str(); + if (val && *val) { + // Expand rules in the empty string. It may insert the launcher and + // perform replacements. + RuleVariables vars; + vars.RuleLauncher = prop; + vars.CMTarget = target; + std::string output; + const std::vector& outputs = ccg.GetOutputs(); + if (!outputs.empty()) { + output = this->Convert(outputs[0], relative, cmOutputConverter::SHELL); + } + vars.Output = output.c_str(); - std::string launcher; - this->ExpandRuleVariables(launcher, vars); - if (!launcher.empty()) { - launcher += " "; + std::string launcher; + this->ExpandRuleVariables(launcher, vars); + if (!launcher.empty()) { + launcher += " "; + } + return launcher; } - return launcher; + return ""; } void cmLocalUnixMakefileGenerator3::AppendCleanCommand( https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=064724040af65c7edc985877b637560620136565 commit 064724040af65c7edc985877b637560620136565 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:53 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:53 2016 +0200 Makefiles: Remove uselss uses of Convert Convert with NONE and UNCHANGED is a no-op. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index cb82d0a..b3d601a 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -835,8 +835,7 @@ std::string cmLocalUnixMakefileGenerator3::GetRelativeTargetDirectory( { std::string dir = this->HomeRelativeOutputPath; dir += this->GetTargetDirectory(target); - return this->Convert(dir, cmOutputConverter::NONE, - cmOutputConverter::UNCHANGED); + return dir; } void cmLocalUnixMakefileGenerator3::AppendFlags(std::string& flags, @@ -982,7 +981,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( : cmOutputConverter::NONE); std::string shellCommand = this->MaybeConvertWacomShellCommand(cmd); if (shellCommand.empty()) { - shellCommand = this->Convert(cmd, cmOutputConverter::NONE); + shellCommand = cmd; } cmd = launcher + shellCommand; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=be096139cf7380f89d8aaad3ea283559b27b2614 commit be096139cf7380f89d8aaad3ea283559b27b2614 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:53 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:53 2016 +0200 Makefiles: Replace method with Wacom specific API The existing method uses RelativeRoot NONE and FULL values. In principle, those should be segregated interfaces. Mixing NONE and FULL into the RelativeRoot enum is a case of http://thedailywtf.com/articles/What_Is_Truth_0x3f_ diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index f2ef5c8..cb82d0a 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -592,8 +592,8 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule( } } -std::string cmLocalUnixMakefileGenerator3::ConvertShellCommand( - std::string const& cmd, cmOutputConverter::RelativeRoot root) +std::string cmLocalUnixMakefileGenerator3::MaybeConvertWacomShellCommand( + std::string const& cmd) { if (this->IsWatcomWMake() && cmSystemTools::FileIsFullPath(cmd.c_str()) && cmd.find_first_of("( )") != cmd.npos) { @@ -606,7 +606,7 @@ std::string cmLocalUnixMakefileGenerator3::ConvertShellCommand( cmOutputConverter::SHELL); } } - return this->Convert(cmd, root, cmOutputConverter::SHELL); + return std::string(); } void cmLocalUnixMakefileGenerator3::WriteMakeVariables( @@ -638,8 +638,13 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( #endif } - std::string cmakeShellCommand = this->ConvertShellCommand( - cmSystemTools::GetCMakeCommand(), cmOutputConverter::FULL); + std::string cmakeShellCommand = + this->MaybeConvertWacomShellCommand(cmSystemTools::GetCMakeCommand()); + if (cmakeShellCommand.empty()) { + cmakeShellCommand = + this->Convert(cmSystemTools::GetCMakeCommand(), cmOutputConverter::FULL, + cmOutputConverter::SHELL); + } /* clang-format off */ makefileStream @@ -975,7 +980,11 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( std::string launcher = this->MakeLauncher( ccg, target, workingDir.empty() ? cmOutputConverter::START_OUTPUT : cmOutputConverter::NONE); - cmd = launcher + this->ConvertShellCommand(cmd, cmOutputConverter::NONE); + std::string shellCommand = this->MaybeConvertWacomShellCommand(cmd); + if (shellCommand.empty()) { + shellCommand = this->Convert(cmd, cmOutputConverter::NONE); + } + cmd = launcher + shellCommand; ccg.AppendArguments(c, cmd); if (content) { diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index 243cc3d..9541f65 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -250,8 +250,7 @@ protected: void CheckMultipleOutputs(bool verbose); private: - std::string ConvertShellCommand(std::string const& cmd, - cmOutputConverter::RelativeRoot root); + std::string MaybeConvertWacomShellCommand(std::string const& cmd); std::string MakeLauncher(cmCustomCommandGenerator const& ccg, cmGeneratorTarget* target, cmOutputConverter::RelativeRoot relative); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cd351ef2c427284eea0ab494eba5d4f24bc0e050 commit cd351ef2c427284eea0ab494eba5d4f24bc0e050 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:53 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:53 2016 +0200 Makefiles: Deduplicate variable diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 824d4b8..f2ef5c8 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -638,19 +638,20 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( #endif } + std::string cmakeShellCommand = this->ConvertShellCommand( + cmSystemTools::GetCMakeCommand(), cmOutputConverter::FULL); + /* clang-format off */ makefileStream << "# The CMake executable.\n" << "CMAKE_COMMAND = " - << this->ConvertShellCommand(cmSystemTools::GetCMakeCommand(), - cmOutputConverter::FULL) + << cmakeShellCommand << "\n" << "\n"; makefileStream << "# The command to remove a file.\n" << "RM = " - << this->ConvertShellCommand(cmSystemTools::GetCMakeCommand(), - cmOutputConverter::FULL) + << cmakeShellCommand << " -E remove -f\n" << "\n"; makefileStream https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=fbd83948675f4b1cb487d59390cfe1689f801fc0 commit fbd83948675f4b1cb487d59390cfe1689f801fc0 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:53 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:53 2016 +0200 Convert: Remove obsolete GetRelativeRootPath diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 5e1babc..98872d6 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -46,23 +46,6 @@ std::string cmOutputConverter::ConvertToOutputForExisting( return this->ConvertToOutputFormat(remote, format); } -const char* cmOutputConverter::GetRelativeRootPath(RelativeRoot relroot) const -{ - switch (relroot) { - case HOME: - return this->GetState()->GetSourceDirectory(); - case START: - return this->StateSnapshot.GetDirectory().GetCurrentSource(); - case HOME_OUTPUT: - return this->GetState()->GetBinaryDirectory(); - case START_OUTPUT: - return this->StateSnapshot.GetDirectory().GetCurrentBinary(); - default: - break; - } - return CM_NULLPTR; -} - std::string cmOutputConverter::Convert(const std::string& source, RelativeRoot relative, OutputFormat output) const diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 9eb1846..ff06ab6 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -60,11 +60,6 @@ public: std::string ConvertDirectorySeparatorsForShell( const std::string& source) const; - /** - * Get path for the specified relative root. - */ - const char* GetRelativeRootPath(RelativeRoot relroot) const; - ///! for existing files convert to output path and short path if spaces std::string ConvertToOutputForExisting(const std::string& remote, OutputFormat format = SHELL) const; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c341f4679ad00cb65c7660b474ddabd13d0ef498 commit c341f4679ad00cb65c7660b474ddabd13d0ef498 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:53 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:53 2016 +0200 Makefiles: Change AppendCustomCommand API to strings Avoid the RelativeRoot enum. Supply the HOME_OUTPUT string at each callsite to make the parameter non-defaulted. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index a2ac38a..824d4b8 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -900,7 +900,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomDepend( void cmLocalUnixMakefileGenerator3::AppendCustomCommands( std::vector& commands, const std::vector& ccs, - cmGeneratorTarget* target, cmOutputConverter::RelativeRoot relative) + cmGeneratorTarget* target, std::string const& relative) { for (std::vector::const_iterator i = ccs.begin(); i != ccs.end(); ++i) { @@ -911,8 +911,8 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommands( void cmLocalUnixMakefileGenerator3::AppendCustomCommand( std::vector& commands, cmCustomCommandGenerator const& ccg, - cmGeneratorTarget* target, cmOutputConverter::RelativeRoot relative, - bool echo_comment, std::ostream* content) + cmGeneratorTarget* target, std::string const& relative, bool echo_comment, + std::ostream* content) { // Optionally create a command to display the custom command's // comment text. This is used for pre-build, pre-link, and @@ -1011,8 +1011,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( } // Setup the proper working directory for the commands. - std::string relativeDir = this->GetRelativeRootPath(relative); - this->CreateCDCommand(commands1, dir.c_str(), relativeDir); + this->CreateCDCommand(commands1, dir.c_str(), relative); // push back the custom commands commands.insert(commands.end(), commands1.begin(), commands1.end()); @@ -1559,9 +1558,9 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( this->AppendCustomDepends(depends, gt->GetPreBuildCommands()); this->AppendCustomDepends(depends, gt->GetPostBuildCommands()); this->AppendCustomCommands(commands, gt->GetPreBuildCommands(), gt, - cmOutputConverter::START_OUTPUT); + this->GetCurrentBinaryDirectory()); this->AppendCustomCommands(commands, gt->GetPostBuildCommands(), gt, - cmOutputConverter::START_OUTPUT); + this->GetCurrentBinaryDirectory()); std::string targetName = gt->GetName(); this->WriteMakeRule(ruleFileStream, targetString.c_str(), targetName, depends, commands, true); diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index ed167b3..243cc3d 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -228,15 +228,16 @@ protected: const std::vector& ccs); void AppendCustomDepend(std::vector& depends, cmCustomCommandGenerator const& cc); - void AppendCustomCommands( - std::vector& commands, - const std::vector& ccs, cmGeneratorTarget* target, - cmOutputConverter::RelativeRoot relative = cmOutputConverter::HOME_OUTPUT); - void AppendCustomCommand( - std::vector& commands, cmCustomCommandGenerator const& ccg, - cmGeneratorTarget* target, - cmOutputConverter::RelativeRoot relative = cmOutputConverter::HOME_OUTPUT, - bool echo_comment = false, std::ostream* content = CM_NULLPTR); + void AppendCustomCommands(std::vector& commands, + const std::vector& ccs, + cmGeneratorTarget* target, + std::string const& relative); + void AppendCustomCommand(std::vector& commands, + cmCustomCommandGenerator const& ccg, + cmGeneratorTarget* target, + std::string const& relative, + bool echo_comment = false, + std::ostream* content = CM_NULLPTR); void AppendCleanCommand(std::vector& commands, const std::vector& files, cmGeneratorTarget* target, diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index daf1587..74bfedc 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -257,10 +257,10 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) if (!relink) { this->LocalGenerator->AppendCustomCommands( commands, this->GeneratorTarget->GetPreBuildCommands(), - this->GeneratorTarget); + this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory()); this->LocalGenerator->AppendCustomCommands( commands, this->GeneratorTarget->GetPreLinkCommands(), - this->GeneratorTarget); + this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory()); } // Determine whether a link script will be used. @@ -411,7 +411,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) if (!relink) { this->LocalGenerator->AppendCustomCommands( commands, this->GeneratorTarget->GetPostBuildCommands(), - this->GeneratorTarget); + this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory()); } // Write the build rule. diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index b3cd6a2..6727bd0 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -112,7 +112,7 @@ void cmMakefileLibraryTargetGenerator::WriteObjectLibraryRules() // Add post-build rules. this->LocalGenerator->AppendCustomCommands( commands, this->GeneratorTarget->GetPostBuildCommands(), - this->GeneratorTarget); + this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory()); // Depend on the object files. this->AppendObjectDepends(depends); @@ -427,10 +427,10 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( if (!relink) { this->LocalGenerator->AppendCustomCommands( commands, this->GeneratorTarget->GetPreBuildCommands(), - this->GeneratorTarget); + this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory()); this->LocalGenerator->AppendCustomCommands( commands, this->GeneratorTarget->GetPreLinkCommands(), - this->GeneratorTarget); + this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory()); } // Determine whether a link script will be used. @@ -698,7 +698,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( if (!relink) { this->LocalGenerator->AppendCustomCommands( commands, this->GeneratorTarget->GetPostBuildCommands(), - this->GeneratorTarget); + this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory()); } // Compute the list of outputs. diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 0c637a9..5bba29c 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1094,8 +1094,8 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile( // Now append the actual user-specified commands. std::ostringstream content; this->LocalGenerator->AppendCustomCommand( - commands, ccg, this->GeneratorTarget, cmOutputConverter::HOME_OUTPUT, - false, &content); + commands, ccg, this->GeneratorTarget, + this->LocalGenerator->GetBinaryDirectory(), false, &content); // Collect the dependencies. std::vector depends; diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx index dfad0c4..b709545 100644 --- a/Source/cmMakefileUtilityTargetGenerator.cxx +++ b/Source/cmMakefileUtilityTargetGenerator.cxx @@ -75,14 +75,14 @@ void cmMakefileUtilityTargetGenerator::WriteRuleFiles() this->LocalGenerator->AppendCustomCommands( commands, this->GeneratorTarget->GetPreBuildCommands(), - this->GeneratorTarget); + this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory()); // Depend on all custom command outputs for sources this->DriveCustomCommands(depends); this->LocalGenerator->AppendCustomCommands( commands, this->GeneratorTarget->GetPostBuildCommands(), - this->GeneratorTarget); + this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory()); // Add dependencies on targets that must be built first. this->AppendTargetDepends(depends); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6960516b6b053816313d2ff5ee4e9375a84829cb commit 6960516b6b053816313d2ff5ee4e9375a84829cb Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:52 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:52 2016 +0200 Makefiles: Change signature of AppendCustomCommand The RelativeRoot parameter will become non-default. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 0169b47..a2ac38a 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -905,14 +905,14 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommands( for (std::vector::const_iterator i = ccs.begin(); i != ccs.end(); ++i) { cmCustomCommandGenerator ccg(*i, this->ConfigName, this); - this->AppendCustomCommand(commands, ccg, target, true, relative); + this->AppendCustomCommand(commands, ccg, target, relative, true); } } void cmLocalUnixMakefileGenerator3::AppendCustomCommand( std::vector& commands, cmCustomCommandGenerator const& ccg, - cmGeneratorTarget* target, bool echo_comment, - cmOutputConverter::RelativeRoot relative, std::ostream* content) + cmGeneratorTarget* target, cmOutputConverter::RelativeRoot relative, + bool echo_comment, std::ostream* content) { // Optionally create a command to display the custom command's // comment text. This is used for pre-build, pre-link, and diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index 5e1b651..ed167b3 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -234,9 +234,9 @@ protected: cmOutputConverter::RelativeRoot relative = cmOutputConverter::HOME_OUTPUT); void AppendCustomCommand( std::vector& commands, cmCustomCommandGenerator const& ccg, - cmGeneratorTarget* target, bool echo_comment = false, + cmGeneratorTarget* target, cmOutputConverter::RelativeRoot relative = cmOutputConverter::HOME_OUTPUT, - std::ostream* content = CM_NULLPTR); + bool echo_comment = false, std::ostream* content = CM_NULLPTR); void AppendCleanCommand(std::vector& commands, const std::vector& files, cmGeneratorTarget* target, diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 8f14e8c..0c637a9 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1094,8 +1094,8 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile( // Now append the actual user-specified commands. std::ostringstream content; this->LocalGenerator->AppendCustomCommand( - commands, ccg, this->GeneratorTarget, false, - cmOutputConverter::HOME_OUTPUT, &content); + commands, ccg, this->GeneratorTarget, cmOutputConverter::HOME_OUTPUT, + false, &content); // Collect the dependencies. std::vector depends; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e0fd2d0446101847dd40cfe4cc451667d04ddcd9 commit e0fd2d0446101847dd40cfe4cc451667d04ddcd9 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:52 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:52 2016 +0200 Makefiles: Port CreateCDCommand to string-based API diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 22937e3..0169b47 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -358,7 +358,7 @@ void cmLocalUnixMakefileGenerator3::WriteObjectConvenienceRule( this->GetRecursiveMakeCall(tgtMakefileName.c_str(), targetName)); } this->CreateCDCommand(commands, this->GetBinaryDirectory(), - cmOutputConverter::START_OUTPUT); + this->GetCurrentBinaryDirectory()); // Write the rule to the makefile. std::vector no_depends; @@ -398,7 +398,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalMakefileTargets( commands.push_back( this->GetRecursiveMakeCall(makefile2.c_str(), localName)); this->CreateCDCommand(commands, this->GetBinaryDirectory(), - cmOutputConverter::START_OUTPUT); + this->GetCurrentBinaryDirectory()); this->WriteMakeRule(ruleFileStream, "Convenience name for target.", localName, depends, commands, true); @@ -423,7 +423,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalMakefileTargets( commands.push_back( this->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName)); this->CreateCDCommand(commands, this->GetBinaryDirectory(), - cmOutputConverter::START_OUTPUT); + this->GetCurrentBinaryDirectory()); this->WriteMakeRule(ruleFileStream, "fast build rule for target.", localName, depends, commands, true); @@ -439,7 +439,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalMakefileTargets( commands.push_back( this->GetRecursiveMakeCall(makefile2.c_str(), makeTargetName)); this->CreateCDCommand(commands, this->GetBinaryDirectory(), - cmOutputConverter::START_OUTPUT); + this->GetCurrentBinaryDirectory()); this->WriteMakeRule(ruleFileStream, "Manual pre-install relink rule for target.", localName, depends, commands, true); @@ -793,7 +793,7 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom( commands.push_back(runRule); if (!this->IsRootMakefile()) { this->CreateCDCommand(commands, this->GetBinaryDirectory(), - cmOutputConverter::START_OUTPUT); + this->GetCurrentBinaryDirectory()); } this->WriteMakeRule( makefileStream, "Special rule to run CMake to check the build system " @@ -1011,7 +1011,8 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( } // Setup the proper working directory for the commands. - this->CreateCDCommand(commands1, dir.c_str(), relative); + std::string relativeDir = this->GetRelativeRootPath(relative); + this->CreateCDCommand(commands1, dir.c_str(), relativeDir); // push back the custom commands commands.insert(commands.end(), commands1.begin(), commands1.end()); @@ -1613,7 +1614,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( commands.push_back( this->GetRecursiveMakeCall(mf2Dir.c_str(), recursiveTarget)); this->CreateCDCommand(commands, this->GetBinaryDirectory(), - cmOutputConverter::START_OUTPUT); + this->GetCurrentBinaryDirectory()); { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0 @@ -1633,7 +1634,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( commands.push_back( this->GetRecursiveMakeCall(mf2Dir.c_str(), recursiveTarget)); this->CreateCDCommand(commands, this->GetBinaryDirectory(), - cmOutputConverter::START_OUTPUT); + this->GetCurrentBinaryDirectory()); this->WriteMakeRule(ruleFileStream, "The main clean target", "clean", depends, commands, true); commands.clear(); @@ -1659,7 +1660,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( commands.push_back( this->GetRecursiveMakeCall(mf2Dir.c_str(), recursiveTarget)); this->CreateCDCommand(commands, this->GetBinaryDirectory(), - cmOutputConverter::START_OUTPUT); + this->GetCurrentBinaryDirectory()); this->WriteMakeRule(ruleFileStream, "Prepare targets for installation.", "preinstall", depends, commands, true); depends.clear(); @@ -1679,7 +1680,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( runRule += " 1"; commands.push_back(runRule); this->CreateCDCommand(commands, this->GetBinaryDirectory(), - cmOutputConverter::START_OUTPUT); + this->GetCurrentBinaryDirectory()); this->WriteMakeRule(ruleFileStream, "clear depends", "depend", depends, commands, true); } @@ -2046,12 +2047,10 @@ void cmLocalUnixMakefileGenerator3::AddImplicitDepends( void cmLocalUnixMakefileGenerator3::CreateCDCommand( std::vector& commands, const char* tgtDir, - cmOutputConverter::RelativeRoot relRetDir) + std::string const& relDir) { - const char* relDir = this->GetRelativeRootPath(relRetDir); - // do we need to cd? - if (!strcmp(tgtDir, relDir)) { + if (tgtDir == relDir) { return; } diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index 42d1d91..5e1b651 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -121,8 +121,7 @@ public: // create a command that cds to the start dir then runs the commands void CreateCDCommand(std::vector& commands, - const char* targetDir, - cmOutputConverter::RelativeRoot returnDir); + const char* targetDir, std::string const& relDir); static std::string ConvertToQuotedOutputPath(const char* p, bool useWatcomQuote); diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 6fadc8f..daf1587 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -389,7 +389,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) } this->LocalGenerator->CreateCDCommand( commands1, this->Makefile->GetCurrentBinaryDirectory(), - cmOutputConverter::HOME_OUTPUT); + this->LocalGenerator->GetBinaryDirectory()); commands.insert(commands.end(), commands1.begin(), commands1.end()); commands1.clear(); @@ -402,7 +402,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) commands1.push_back(symlink); this->LocalGenerator->CreateCDCommand( commands1, this->Makefile->GetCurrentBinaryDirectory(), - cmOutputConverter::HOME_OUTPUT); + this->LocalGenerator->GetBinaryDirectory()); commands.insert(commands.end(), commands1.begin(), commands1.end()); commands1.clear(); } diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 580343d..b3cd6a2 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -418,7 +418,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( this->GeneratorTarget, "target"); this->LocalGenerator->CreateCDCommand( commands1, this->Makefile->GetCurrentBinaryDirectory(), - cmOutputConverter::HOME_OUTPUT); + this->LocalGenerator->GetBinaryDirectory()); commands.insert(commands.end(), commands1.begin(), commands1.end()); commands1.clear(); } @@ -672,7 +672,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( } this->LocalGenerator->CreateCDCommand( commands1, this->Makefile->GetCurrentBinaryDirectory(), - cmOutputConverter::HOME_OUTPUT); + this->LocalGenerator->GetBinaryDirectory()); commands.insert(commands.end(), commands1.begin(), commands1.end()); commands1.clear(); @@ -689,7 +689,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( commands1.push_back(symlink); this->LocalGenerator->CreateCDCommand( commands1, this->Makefile->GetCurrentBinaryDirectory(), - cmOutputConverter::HOME_OUTPUT); + this->LocalGenerator->GetBinaryDirectory()); commands.insert(commands.end(), commands1.begin(), commands1.end()); commands1.clear(); } diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 84a15e0..8f14e8c 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -649,7 +649,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( // Change the command working directory to the local build tree. this->LocalGenerator->CreateCDCommand( compileCommands, this->LocalGenerator->GetCurrentBinaryDirectory(), - cmOutputConverter::HOME_OUTPUT); + this->LocalGenerator->GetBinaryDirectory()); commands.insert(commands.end(), compileCommands.begin(), compileCommands.end()); } @@ -712,7 +712,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( this->LocalGenerator->CreateCDCommand( preprocessCommands, this->LocalGenerator->GetCurrentBinaryDirectory(), - cmOutputConverter::HOME_OUTPUT); + this->LocalGenerator->GetBinaryDirectory()); commands.insert(commands.end(), preprocessCommands.begin(), preprocessCommands.end()); } else { @@ -758,7 +758,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( this->LocalGenerator->CreateCDCommand( assemblyCommands, this->LocalGenerator->GetCurrentBinaryDirectory(), - cmOutputConverter::HOME_OUTPUT); + this->LocalGenerator->GetBinaryDirectory()); commands.insert(commands.end(), assemblyCommands.begin(), assemblyCommands.end()); } else { @@ -849,7 +849,7 @@ void cmMakefileTargetGenerator::WriteTargetCleanRules() this->GeneratorTarget); this->LocalGenerator->CreateCDCommand( commands, this->LocalGenerator->GetCurrentBinaryDirectory(), - cmOutputConverter::HOME_OUTPUT); + this->LocalGenerator->GetBinaryDirectory()); // Write the rule. this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ad70a236f4368c21c08bcd4ea4d28425176c4e17 commit ad70a236f4368c21c08bcd4ea4d28425176c4e17 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:52 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:52 2016 +0200 Convert: Remove ConvertToOutputForExisting overload It is no longer used. diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 47c2928..5e1babc 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -46,19 +46,6 @@ std::string cmOutputConverter::ConvertToOutputForExisting( return this->ConvertToOutputFormat(remote, format); } -std::string cmOutputConverter::ConvertToOutputForExisting( - RelativeRoot remote, OutputFormat format) const -{ - // The relative root must have a path (i.e. not FULL or NONE) - assert(remote != FULL); - assert(remote != NONE); - - const char* remotePath = this->GetRelativeRootPath(remote); - assert(remotePath != CM_NULLPTR); - - return this->ConvertToOutputForExisting(remotePath, format); -} - const char* cmOutputConverter::GetRelativeRootPath(RelativeRoot relroot) const { switch (relroot) { diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index d3ded25..9eb1846 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -69,11 +69,6 @@ public: std::string ConvertToOutputForExisting(const std::string& remote, OutputFormat format = SHELL) const; - /** For existing path identified by RelativeRoot convert to output - path and short path if spaces. */ - std::string ConvertToOutputForExisting(RelativeRoot remote, - OutputFormat format = SHELL) const; - void SetLinkScriptShell(bool linkScriptShell); /** https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e3ca17e13b8d2aecc6d97ac800d65c6c35378a98 commit e3ca17e13b8d2aecc6d97ac800d65c6c35378a98 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:52 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:52 2016 +0200 Makefiles: Use string overload of ConvertToOutputForExisting The string is already determined so, no need to call the overload to determine it again. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 4ecd0b2..22937e3 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -2073,7 +2073,7 @@ void cmLocalUnixMakefileGenerator3::CreateCDCommand( // Change back to the starting directory. cmd = cd_cmd; - cmd += this->ConvertToOutputForExisting(relRetDir); + cmd += this->ConvertToOutputForExisting(relDir); commands.push_back(cmd); } else { // On UNIX we must construct a single shell command to change https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0bbdbd95c9515a4714ef1d57a17c7271bc4d1774 commit 0bbdbd95c9515a4714ef1d57a17c7271bc4d1774 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:52 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:52 2016 +0200 Makefiles: Rename local variable In this context, 'ret' means 'return', but I don't really know what that means. It is not consistent with types and other variables used in the vicinity for these things. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 7597077..4ecd0b2 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -2048,10 +2048,10 @@ void cmLocalUnixMakefileGenerator3::CreateCDCommand( std::vector& commands, const char* tgtDir, cmOutputConverter::RelativeRoot relRetDir) { - const char* retDir = this->GetRelativeRootPath(relRetDir); + const char* relDir = this->GetRelativeRootPath(relRetDir); // do we need to cd? - if (!strcmp(tgtDir, retDir)) { + if (!strcmp(tgtDir, relDir)) { return; } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9440d5776bf48778d452e2d3a48d4e93d7b6f7a7 commit 9440d5776bf48778d452e2d3a48d4e93d7b6f7a7 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:51 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 13:44:51 2016 +0200 Convert: Remove unused overload diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 411184c..47c2928 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -146,27 +146,6 @@ std::string cmOutputConverter::ConvertDirectorySeparatorsForShell( return result; } -std::string cmOutputConverter::Convert(RelativeRoot remote, - const std::string& local, - OutputFormat output) const -{ - // The relative root must have a path (i.e. not FULL or NONE) - assert(remote != FULL); - assert(remote != NONE); - - const char* remotePath = this->GetRelativeRootPath(remote); - assert(remotePath != CM_NULLPTR); - - if (local.empty()) { - return this->ConvertToOutputFormat(remotePath, output); - } - - std::vector components; - cmSystemTools::SplitPath(local, components); - std::string result = this->ConvertToRelativePath(components, remotePath); - return this->ConvertToOutputFormat(result, output); -} - static bool cmOutputConverterNotAbove(const char* a, const char* b) { return (cmSystemTools::ComparePath(a, b) || diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 23f2e62..d3ded25 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -57,8 +57,6 @@ public: OutputFormat output) const; std::string Convert(const std::string& remote, RelativeRoot local, OutputFormat output = UNCHANGED) const; - std::string Convert(RelativeRoot remote, const std::string& local, - OutputFormat output = UNCHANGED) const; std::string ConvertDirectorySeparatorsForShell( const std::string& source) const; ----------------------------------------------------------------------- Summary of changes: Source/cmCommonTargetGenerator.h | 6 +- Source/cmDependsC.cxx | 4 +- Source/cmDependsFortran.cxx | 10 +- Source/cmExtraEclipseCDT4Generator.cxx | 4 +- Source/cmGlobalGenerator.cxx | 4 +- Source/cmGlobalNinjaGenerator.cxx | 6 +- Source/cmGlobalUnixMakefileGenerator3.cxx | 31 ++-- Source/cmGlobalVisualStudio7Generator.cxx | 3 +- Source/cmListFileCache.cxx | 6 +- Source/cmLocalCommonGenerator.cxx | 3 +- Source/cmLocalGenerator.cxx | 25 ++-- Source/cmLocalNinjaGenerator.cxx | 23 +-- Source/cmLocalUnixMakefileGenerator3.cxx | 188 ++++++++++++------------ Source/cmLocalUnixMakefileGenerator3.h | 28 ++-- Source/cmLocalVisualStudio7Generator.cxx | 26 ++-- Source/cmLocalVisualStudioGenerator.cxx | 10 +- Source/cmMakefileExecutableTargetGenerator.cxx | 49 +++--- Source/cmMakefileLibraryTargetGenerator.cxx | 63 ++++---- Source/cmMakefileTargetGenerator.cxx | 119 ++++++++------- Source/cmMakefileUtilityTargetGenerator.cxx | 4 +- Source/cmNinjaNormalTargetGenerator.cxx | 4 +- Source/cmOutputConverter.cxx | 81 ++-------- Source/cmOutputConverter.h | 19 +-- Source/cmTarget.cxx | 3 +- Source/cmVisualStudio10TargetGenerator.cxx | 5 +- 25 files changed, 340 insertions(+), 384 deletions(-) hooks/post-receive -- CMake From steveire at gmail.com Sat Aug 27 08:46:14 2016 From: steveire at gmail.com (Stephen Kelly) Date: Sat, 27 Aug 2016 08:46:14 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1533-g2b114c4 Message-ID: <20160827124614.6C4ECF3B1F@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 2b114c41b54c4d14745b2b98c57ccc7c92111f7e (commit) via 1fc076d1fe196d2112da45a6aced04ca39594401 (commit) from 738e3e9d9af191e7f118e182bb3ba3690430e2af (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2b114c41b54c4d14745b2b98c57ccc7c92111f7e commit 2b114c41b54c4d14745b2b98c57ccc7c92111f7e Merge: 738e3e9 1fc076d Author: Stephen Kelly AuthorDate: Sat Aug 27 08:46:13 2016 -0400 Commit: CMake Topic Stage CommitDate: Sat Aug 27 08:46:13 2016 -0400 Merge topic 'cleanup-Convert' into next 1fc076d1 Revert part of branch https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1fc076d1fe196d2112da45a6aced04ca39594401 commit 1fc076d1fe196d2112da45a6aced04ca39594401 Author: Stephen Kelly AuthorDate: Sat Aug 27 14:45:29 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 14:45:45 2016 +0200 Revert part of branch diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index b433c18..d3f9d64 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -57,9 +57,9 @@ protected: // The windows module definition source file (.def), if any. cmSourceFile const* ModuleDefinitionFile; - std::string Convert(std::string const& source, - cmOutputConverter::RelativeRoot relative, - cmOutputConverter::OutputFormat output); + std::string Convert( + std::string const& source, cmOutputConverter::RelativeRoot relative, + cmOutputConverter::OutputFormat output = cmOutputConverter::UNCHANGED); void AppendFortranFormatFlags(std::string& flags, cmSourceFile const& source); diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index 928f7ec..18e123e 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -238,8 +238,8 @@ bool cmDependsC::WriteDependencies(const std::set& sources, // written by the original local generator for this directory // convert the dependencies to paths relative to the home output // directory. We must do the same here. - std::string obj_i = this->LocalGenerator->ConvertToRelativePath( - obj, cmOutputConverter::HOME_OUTPUT); + std::string obj_i = + this->LocalGenerator->Convert(obj, cmOutputConverter::HOME_OUTPUT); std::string obj_m = this->LocalGenerator->ConvertToOutputFormat( obj_i, cmOutputConverter::MAKERULE); internalDepends << obj_i << std::endl; diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index 8c0acce..c57b558 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -193,15 +193,15 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends, stamp += ".mod.stamp"; fcStream << "\n"; fcStream << " \"" - << this->LocalGenerator->ConvertToRelativePath( + << this->LocalGenerator->Convert( mod_lower, cmOutputConverter::START_OUTPUT) << "\"\n"; fcStream << " \"" - << this->LocalGenerator->ConvertToRelativePath( + << this->LocalGenerator->Convert( mod_upper, cmOutputConverter::START_OUTPUT) << "\"\n"; fcStream << " \"" - << this->LocalGenerator->ConvertToRelativePath( + << this->LocalGenerator->Convert( stamp, cmOutputConverter::START_OUTPUT) << "\"\n"; } @@ -317,8 +317,8 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, const char* src = info.Source.c_str(); // Write the include dependencies to the output stream. - std::string obj_i = this->LocalGenerator->ConvertToRelativePath( - obj, cmOutputConverter::HOME_OUTPUT); + std::string obj_i = + this->LocalGenerator->Convert(obj, cmOutputConverter::HOME_OUTPUT); std::string obj_m = this->LocalGenerator->ConvertToOutputFormat( obj_i, cmOutputConverter::MAKERULE); internalDepends << obj_i << std::endl; diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index 945ee40..e617b08 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -904,8 +904,8 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const it != this->GlobalGenerator->GetLocalGenerators().end(); ++it) { const std::vector targets = (*it)->GetGeneratorTargets(); - std::string subdir = (*it)->ConvertToRelativePath( - (*it)->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT); + std::string subdir = (*it)->Convert((*it)->GetCurrentBinaryDirectory(), + cmOutputConverter::HOME_OUTPUT); if (subdir == ".") { subdir = ""; } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 50c5a42..295f65b 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -2547,8 +2547,8 @@ void cmGlobalGenerator::AddRuleHash(const std::vector& outputs, // Shorten the output name (in expected use case). cmOutputConverter converter(this->GetMakefiles()[0]->GetStateSnapshot()); - std::string fname = converter.ConvertToRelativePath( - outputs[0], cmOutputConverter::HOME_OUTPUT); + std::string fname = + converter.Convert(outputs[0], cmOutputConverter::HOME_OUTPUT); // Associate the hash with this output. this->RuleHashes[fname] = hash; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 939c5ad..2b83479 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -747,8 +747,7 @@ std::string cmGlobalNinjaGenerator::ConvertToNinjaPath(const std::string& path) { cmLocalNinjaGenerator* ng = static_cast(this->LocalGenerators[0]); - std::string convPath = - ng->ConvertToRelativePath(path, cmOutputConverter::HOME_OUTPUT); + std::string convPath = ng->Convert(path, cmOutputConverter::HOME_OUTPUT); convPath = this->NinjaOutputPath(convPath); #ifdef _WIN32 std::replace(convPath.begin(), convPath.end(), '/', '\\'); @@ -761,8 +760,7 @@ std::string cmGlobalNinjaGenerator::ConvertToNinjaFolderRule( { cmLocalNinjaGenerator* ng = static_cast(this->LocalGenerators[0]); - std::string convPath = - ng->ConvertToRelativePath(path + "/all", cmOutputConverter::HOME); + std::string convPath = ng->Convert(path + "/all", cmOutputConverter::HOME); convPath = this->NinjaOutputPath(convPath); #ifdef _WIN32 std::replace(convPath.begin(), convPath.end(), '/', '\\'); diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 77fbbe9..f115ecb 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -311,14 +311,11 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() cmakefileStream << "# The top level Makefile was generated from the following files:\n" << "set(CMAKE_MAKEFILE_DEPENDS\n" - << " \"" - << lg->ConvertToRelativePath(cache, cmOutputConverter::START_OUTPUT) - << "\"\n"; + << " \"" << lg->Convert(cache, cmOutputConverter::START_OUTPUT) << "\"\n"; for (std::vector::const_iterator i = lfiles.begin(); i != lfiles.end(); ++i) { cmakefileStream << " \"" - << lg->ConvertToRelativePath( - *i, cmOutputConverter::START_OUTPUT) + << lg->Convert(*i, cmOutputConverter::START_OUTPUT) << "\"\n"; } cmakefileStream << " )\n\n"; @@ -332,12 +329,10 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() cmakefileStream << "# The corresponding makefile is:\n" << "set(CMAKE_MAKEFILE_OUTPUTS\n" << " \"" - << lg->ConvertToRelativePath(makefileName, - cmOutputConverter::START_OUTPUT) + << lg->Convert(makefileName, cmOutputConverter::START_OUTPUT) << "\"\n" << " \"" - << lg->ConvertToRelativePath(check, - cmOutputConverter::START_OUTPUT) + << lg->Convert(check, cmOutputConverter::START_OUTPUT) << "\"\n"; cmakefileStream << " )\n\n"; @@ -350,8 +345,7 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() for (std::vector::const_iterator k = outfiles.begin(); k != outfiles.end(); ++k) { cmakefileStream << " \"" - << lg->ConvertToRelativePath( - *k, cmOutputConverter::HOME_OUTPUT) + << lg->Convert(*k, cmOutputConverter::HOME_OUTPUT) << "\"\n"; } @@ -364,8 +358,7 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() tmpStr += cmake::GetCMakeFilesDirectory(); tmpStr += "/CMakeDirectoryInformation.cmake"; cmakefileStream << " \"" - << lg->ConvertToRelativePath( - tmpStr, cmOutputConverter::HOME_OUTPUT) + << lg->Convert(tmpStr, cmOutputConverter::HOME_OUTPUT) << "\"\n"; } cmakefileStream << " )\n\n"; @@ -526,7 +519,7 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( tname += "/fast"; } cmOutputConverter conv(mf->GetStateSnapshot()); - tname = conv.ConvertToRelativePath(tname, cmOutputConverter::HOME_OUTPUT); + tname = conv.Convert(tname, cmOutputConverter::HOME_OUTPUT); cmSystemTools::ConvertToOutputSlashes(tname); makeCommand.push_back(tname); if (this->Makefiles.empty()) { @@ -723,9 +716,8 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # in target - progCmd << lg->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(progress.Dir), - cmOutputConverter::SHELL); + progCmd << lg->Convert(progress.Dir, cmOutputConverter::FULL, + cmOutputConverter::SHELL); // std::set emitted; progCmd << " " << this->CountProgressMarksInTarget(gtarget, emitted); @@ -737,9 +729,8 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0 - progCmd << lg->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(progress.Dir), - cmOutputConverter::SHELL); + progCmd << lg->Convert(progress.Dir, cmOutputConverter::FULL, + cmOutputConverter::SHELL); progCmd << " 0"; commands.push_back(progCmd.str()); } diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 67ac230..0a83b3a 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -385,8 +385,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( if (vcprojName) { cmLocalGenerator* lg = target->GetLocalGenerator(); std::string dir = lg->GetCurrentBinaryDirectory(); - dir = root->ConvertToRelativePath(dir.c_str(), - cmOutputConverter::START_OUTPUT); + dir = root->Convert(dir.c_str(), cmOutputConverter::START_OUTPUT); if (dir == ".") { dir = ""; // msbuild cannot handle ".\" prefix } diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 3c5e333..39d9e97 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -402,8 +402,7 @@ void cmListFileBacktrace::PrintTitle(std::ostream& out) const cmOutputConverter converter(this->Bottom); cmListFileContext lfc = *this->Cur; if (!this->Bottom.GetState()->GetIsInTryCompile()) { - lfc.FilePath = - converter.ConvertToRelativePath(lfc.FilePath, cmOutputConverter::HOME); + lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME); } out << (lfc.Line ? " at " : " in ") << lfc; } @@ -428,8 +427,7 @@ void cmListFileBacktrace::PrintCallStack(std::ostream& out) const } cmListFileContext lfc = *i; if (!this->Bottom.GetState()->GetIsInTryCompile()) { - lfc.FilePath = - converter.ConvertToRelativePath(lfc.FilePath, cmOutputConverter::HOME); + lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME); } out << " " << lfc << "\n"; } diff --git a/Source/cmLocalCommonGenerator.cxx b/Source/cmLocalCommonGenerator.cxx index 1383421..5502296 100644 --- a/Source/cmLocalCommonGenerator.cxx +++ b/Source/cmLocalCommonGenerator.cxx @@ -74,7 +74,8 @@ std::string cmLocalCommonGenerator::GetTargetFortranFlags( for (std::vector::const_iterator idi = includes.begin(); idi != includes.end(); ++idi) { std::string flg = modpath_flag; - flg += this->ConvertToOutputFormat(*idi, cmOutputConverter::SHELL); + flg += + this->Convert(*idi, cmOutputConverter::NONE, cmOutputConverter::SHELL); this->AppendFlags(flags, flg); } } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index de9e1e5..d8f6bdf 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -176,7 +176,7 @@ void cmLocalGenerator::GenerateTestFiles() // TODO: Use add_subdirectory instead? fout << "subdirs("; std::string outP = children[i].GetDirectory().GetCurrentBinary(); - fout << this->ConvertToRelativePath(outP, START_OUTPUT); + fout << this->Convert(outP, START_OUTPUT); fout << ")" << std::endl; } } @@ -688,9 +688,7 @@ std::string cmLocalGenerator::ExpandRuleVariable( } } if (variable == "CMAKE_COMMAND") { - return this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()), - SHELL); + return this->Convert(cmSystemTools::GetCMakeCommand(), FULL, SHELL); } std::vector enabledLanguages = this->GetState()->GetEnabledLanguages(); @@ -1185,8 +1183,7 @@ void cmLocalGenerator::GetTargetFlags( if (sf->GetExtension() == "def") { linkFlags += this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG"); - linkFlags += this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(sf->GetFullPath()), SHELL); + linkFlags += this->Convert(sf->GetFullPath(), FULL, SHELL); linkFlags += " "; } } @@ -1396,7 +1393,7 @@ std::string cmLocalGenerator::ConvertToLinkReference(std::string const& lib, sp += lib.substr(pos); // Convert to an output path. - return this->ConvertToOutputFormat(sp.c_str(), format); + return this->Convert(sp.c_str(), NONE, format); } } } @@ -1492,7 +1489,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, for (std::vector::const_iterator fdi = fwDirs.begin(); fdi != fwDirs.end(); ++fdi) { frameworkPath += fwSearchFlag; - frameworkPath += this->ConvertToOutputFormat(*fdi, shellFormat); + frameworkPath += this->Convert(*fdi, NONE, shellFormat); frameworkPath += " "; } } @@ -1538,7 +1535,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, for (std::vector::iterator ri = runtimeDirs.begin(); ri != runtimeDirs.end(); ++ri) { rpath += cli.GetRuntimeFlag(); - rpath += this->ConvertToOutputFormat(*ri, shellFormat); + rpath += this->Convert(*ri, NONE, shellFormat); rpath += " "; } fout << rpath; @@ -1608,7 +1605,7 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags, flags += " "; flags += sysrootFlag; flags += " "; - flags += this->ConvertToOutputFormat(sysroot, SHELL); + flags += this->Convert(sysroot, NONE, SHELL); } if (deploymentTargetFlag && *deploymentTargetFlag && deploymentTarget && @@ -2240,8 +2237,7 @@ std::string cmLocalGenerator::ConstructComment( for (std::vector::const_iterator o = ccg.GetOutputs().begin(); o != ccg.GetOutputs().end(); ++o) { comment += sep; - comment += - this->ConvertToRelativePath(*o, cmOutputConverter::START_OUTPUT); + comment += this->Convert(*o, cmOutputConverter::START_OUTPUT); sep = ", "; } return comment; @@ -2509,14 +2505,13 @@ std::string cmLocalGenerator::GetObjectFileNameWithoutTarget( const char* fullPath = source.GetFullPath().c_str(); // Try referencing the source relative to the source tree. - std::string relFromSource = this->ConvertToRelativePath(fullPath, START); + std::string relFromSource = this->Convert(fullPath, START); assert(!relFromSource.empty()); bool relSource = !cmSystemTools::FileIsFullPath(relFromSource.c_str()); bool subSource = relSource && relFromSource[0] != '.'; // Try referencing the source relative to the binary tree. - std::string relFromBinary = - this->ConvertToRelativePath(fullPath, START_OUTPUT); + std::string relFromBinary = this->Convert(fullPath, START_OUTPUT); assert(!relFromBinary.empty()); bool relBinary = !cmSystemTools::FileIsFullPath(relFromBinary.c_str()); bool subBinary = relBinary && relFromBinary[0] != '.'; diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index d07bfaa..46d7e18 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -41,7 +41,7 @@ void cmLocalNinjaGenerator::Generate() { // Compute the path to use when referencing the current output // directory from the top output directory. - this->HomeRelativeOutputPath = this->ConvertToRelativePath( + this->HomeRelativeOutputPath = this->Convert( this->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT); if (this->HomeRelativeOutputPath == ".") { this->HomeRelativeOutputPath = ""; @@ -132,11 +132,9 @@ std::string cmLocalNinjaGenerator::ConvertToIncludeReference( std::string const& path, cmOutputConverter::OutputFormat format, bool forceFullPaths) { - if (forceFullPaths) { - return this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(path), - format); - } - return this->Convert(path, cmOutputConverter::HOME_OUTPUT, format); + return this->Convert(path, forceFullPaths ? cmOutputConverter::FULL + : cmOutputConverter::HOME_OUTPUT, + format); } // Private methods. @@ -488,13 +486,12 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher( std::string output; const std::vector& outputs = ccg.GetOutputs(); if (!outputs.empty()) { - if (ccg.GetWorkingDirectory().empty()) { - output = this->Convert(outputs[0], cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); - } else { - output = - this->ConvertToOutputFormat(outputs[0], cmOutputConverter::SHELL); - } + cmOutputConverter::RelativeRoot relative_root = + ccg.GetWorkingDirectory().empty() ? cmOutputConverter::START_OUTPUT + : cmOutputConverter::NONE; + + output = + this->Convert(outputs[0], relative_root, cmOutputConverter::SHELL); } vars.Output = output.c_str(); diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 81251f9..b3d601a 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -140,7 +140,7 @@ void cmLocalUnixMakefileGenerator3::ComputeHomeRelativeOutputPath() { // Compute the path to use when referencing the current output // directory from the top output directory. - this->HomeRelativeOutputPath = this->ConvertToRelativePath( + this->HomeRelativeOutputPath = this->Convert( this->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT); if (this->HomeRelativeOutputPath == ".") { this->HomeRelativeOutputPath = ""; @@ -602,7 +602,8 @@ std::string cmLocalUnixMakefileGenerator3::MaybeConvertWacomShellCommand( // lines with shell redirection operators. std::string scmd; if (cmSystemTools::GetShortPath(cmd, scmd)) { - return this->ConvertToOutputFormat(scmd, cmOutputConverter::SHELL); + return this->Convert(scmd, cmOutputConverter::NONE, + cmOutputConverter::SHELL); } } return std::string(); @@ -640,9 +641,9 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( std::string cmakeShellCommand = this->MaybeConvertWacomShellCommand(cmSystemTools::GetCMakeCommand()); if (cmakeShellCommand.empty()) { - cmakeShellCommand = this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()), - cmOutputConverter::SHELL); + cmakeShellCommand = + this->Convert(cmSystemTools::GetCMakeCommand(), cmOutputConverter::FULL, + cmOutputConverter::SHELL); } /* clang-format off */ @@ -665,14 +666,16 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( makefileStream << "# The top-level source directory on which CMake was run.\n" << "CMAKE_SOURCE_DIR = " - << this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(this->GetSourceDirectory()), + << this->Convert(this->GetSourceDirectory(), + cmOutputConverter::FULL, cmOutputConverter::SHELL) << "\n" << "\n"; makefileStream << "# The top-level build directory on which CMake was run.\n" << "CMAKE_BINARY_DIR = " - << this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(this->GetBinaryDirectory()), + << this->Convert(this->GetBinaryDirectory(), + cmOutputConverter::FULL, cmOutputConverter::SHELL) << "\n" << "\n"; @@ -787,8 +790,8 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom( std::string runRule = "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; runRule += " --check-build-system "; - runRule += - this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); + runRule += this->Convert(cmakefileName, cmOutputConverter::NONE, + cmOutputConverter::SHELL); runRule += " 0"; std::vector no_depends; @@ -964,8 +967,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( // working directory will be the start-output directory. bool had_slash = cmd.find('/') != cmd.npos; if (workingDir.empty()) { - cmd = - this->ConvertToRelativePath(cmd, cmOutputConverter::START_OUTPUT); + cmd = this->Convert(cmd, cmOutputConverter::START_OUTPUT); } bool has_slash = cmd.find('/') != cmd.npos; if (had_slash && !has_slash) { @@ -974,37 +976,9 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( // without the current directory being in the search path. cmd = "./" + cmd; } - - std::string launcher; - // Short-circuit if there is no launcher. - const char* prop = "RULE_LAUNCH_CUSTOM"; - const char* val = this->GetRuleLauncher(target, prop); - if (val && *val) { - // Expand rules in the empty string. It may insert the launcher and - // perform replacements. - RuleVariables vars; - vars.RuleLauncher = prop; - vars.CMTarget = target; - std::string output; - const std::vector& outputs = ccg.GetOutputs(); - if (!outputs.empty()) { - if (workingDir.empty()) { - output = this->Convert(outputs[0], cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); - - } else { - output = this->ConvertToOutputFormat(outputs[0], - cmOutputConverter::SHELL); - } - } - vars.Output = output.c_str(); - - this->ExpandRuleVariables(launcher, vars); - if (!launcher.empty()) { - launcher += " "; - } - } - + std::string launcher = this->MakeLauncher( + ccg, target, workingDir.empty() ? cmOutputConverter::START_OUTPUT + : cmOutputConverter::NONE); std::string shellCommand = this->MaybeConvertWacomShellCommand(cmd); if (shellCommand.empty()) { shellCommand = cmd; @@ -1052,6 +1026,37 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( commands.insert(commands.end(), commands1.begin(), commands1.end()); } +std::string cmLocalUnixMakefileGenerator3::MakeLauncher( + cmCustomCommandGenerator const& ccg, cmGeneratorTarget* target, + cmOutputConverter::RelativeRoot relative) +{ + // Short-circuit if there is no launcher. + const char* prop = "RULE_LAUNCH_CUSTOM"; + const char* val = this->GetRuleLauncher(target, prop); + if (!(val && *val)) { + return ""; + } + + // Expand rules in the empty string. It may insert the launcher and + // perform replacements. + RuleVariables vars; + vars.RuleLauncher = prop; + vars.CMTarget = target; + std::string output; + const std::vector& outputs = ccg.GetOutputs(); + if (!outputs.empty()) { + output = this->Convert(outputs[0], relative, cmOutputConverter::SHELL); + } + vars.Output = output.c_str(); + + std::string launcher; + this->ExpandRuleVariables(launcher, vars); + if (!launcher.empty()) { + launcher += " "; + } + return launcher; +} + void cmLocalUnixMakefileGenerator3::AppendCleanCommand( std::vector& commands, const std::vector& files, cmGeneratorTarget* target, const char* filename) @@ -1065,7 +1070,8 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand( cleanfile += filename; } cleanfile += ".cmake"; - std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile); + std::string cleanfilePath = + this->Convert(cleanfile, cmOutputConverter::FULL); cmsys::ofstream fout(cleanfilePath.c_str()); if (!fout) { cmSystemTools::Error("Could not create ", cleanfilePath.c_str()); @@ -1074,8 +1080,8 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand( fout << "file(REMOVE_RECURSE\n"; for (std::vector::const_iterator f = files.begin(); f != files.end(); ++f) { - std::string fc = - this->ConvertToRelativePath(*f, cmOutputConverter::START_OUTPUT); + std::string fc = this->Convert(*f, cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED); fout << " " << cmOutputConverter::EscapeForCMake(fc) << "\n"; } fout << ")\n"; @@ -1151,9 +1157,8 @@ void cmLocalUnixMakefileGenerator3::AppendEcho( cmd += color_name; if (progress) { cmd += "--progress-dir="; - cmd += this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(progress->Dir), - cmOutputConverter::SHELL); + cmd += this->Convert(progress->Dir, cmOutputConverter::FULL, + cmOutputConverter::SHELL); cmd += " "; cmd += "--progress-num="; cmd += progress->Arg; @@ -1601,16 +1606,15 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; - progCmd << this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL); + progCmd << this->Convert(progressDir, cmOutputConverter::FULL, + cmOutputConverter::SHELL); std::string progressFile = cmake::GetCMakeFilesDirectory(); progressFile += "/progress.marks"; std::string progressFileNameFull = this->ConvertToFullPath(progressFile); progCmd << " " - << this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(progressFileNameFull), - cmOutputConverter::SHELL); + << this->Convert(progressFileNameFull, cmOutputConverter::FULL, + cmOutputConverter::SHELL); commands.push_back(progCmd.str()); } std::string mf2Dir = cmake::GetCMakeFilesDirectoryPostSlash(); @@ -1622,8 +1626,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0 - progCmd << this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL); + progCmd << this->Convert(progressDir, cmOutputConverter::FULL, + cmOutputConverter::SHELL); progCmd << " 0"; commands.push_back(progCmd.str()); } @@ -1679,8 +1683,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( std::string runRule = "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; runRule += " --check-build-system "; - runRule += - this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); + runRule += this->Convert(cmakefileName, cmOutputConverter::NONE, + cmOutputConverter::SHELL); runRule += " 1"; commands.push_back(runRule); this->CreateCDCommand(commands, this->GetBinaryDirectory(), @@ -1851,8 +1855,7 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( for (std::vector::iterator i = includes.begin(); i != includes.end(); ++i) { cmakefileStream << " \"" - << this->ConvertToRelativePath( - *i, cmOutputConverter::HOME_OUTPUT) + << this->Convert(*i, cmOutputConverter::HOME_OUTPUT) << "\"\n"; } cmakefileStream << " )\n"; @@ -1894,7 +1897,8 @@ std::string cmLocalUnixMakefileGenerator3::GetRecursiveMakeCall( // Call make on the given file. std::string cmd; cmd += "$(MAKE) -f "; - cmd += this->ConvertToOutputFormat(makefile, cmOutputConverter::SHELL); + cmd += + this->Convert(makefile, cmOutputConverter::NONE, cmOutputConverter::SHELL); cmd += " "; cmGlobalUnixMakefileGenerator3* gg = @@ -1916,8 +1920,7 @@ std::string cmLocalUnixMakefileGenerator3::GetRecursiveMakeCall( // Add the target. if (!tgt.empty()) { // The make target is always relative to the top of the build tree. - std::string tgt2 = - this->ConvertToRelativePath(tgt, cmOutputConverter::HOME_OUTPUT); + std::string tgt2 = this->Convert(tgt, cmOutputConverter::HOME_OUTPUT); // The target may have been written with windows paths. cmSystemTools::ConvertToOutputSlashes(tgt2); diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index bc7566e..9541f65 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -251,6 +251,9 @@ protected: private: std::string MaybeConvertWacomShellCommand(std::string const& cmd); + std::string MakeLauncher(cmCustomCommandGenerator const& ccg, + cmGeneratorTarget* target, + cmOutputConverter::RelativeRoot relative); void ComputeObjectFilenames( std::map& mapping, diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 70fe819..e72abe9 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -269,8 +269,8 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() args += this->GetBinaryDirectory(); commandLine.push_back(args); commandLine.push_back("--check-stamp-file"); - std::string stampFilename = this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(stampName), cmOutputConverter::SHELL); + std::string stampFilename = this->Convert( + stampName.c_str(), cmOutputConverter::FULL, cmOutputConverter::SHELL); commandLine.push_back(stampFilename.c_str()); std::vector const& listFiles = this->Makefile->GetListFiles(); @@ -278,8 +278,8 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() cmCustomCommandLines commandLines; commandLines.push_back(commandLine); const char* no_working_directory = 0; - std::string fullpathStampName = - cmSystemTools::CollapseFullPath(stampName.c_str()); + std::string fullpathStampName = this->Convert( + stampName.c_str(), cmOutputConverter::FULL, cmOutputConverter::UNCHANGED); this->Makefile->AddCustomCommandToOutput( fullpathStampName.c_str(), listFiles, makefileIn.c_str(), commandLines, comment.c_str(), no_working_directory, true); @@ -788,8 +788,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( target->GetProperty("Fortran_MODULE_DIRECTORY"); std::string modDir; if (target_mod_dir) { - modDir = this->ConvertToRelativePath(target_mod_dir, - cmOutputConverter::START_OUTPUT); + modDir = this->Convert(target_mod_dir, cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED); } else { modDir = "."; } @@ -1300,8 +1300,9 @@ void cmLocalVisualStudio7GeneratorInternals::OutputLibraries( cmLocalVisualStudio7Generator* lg = this->LocalGenerator; for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) { if (l->IsPath) { - std::string rel = lg->ConvertToRelativePath( - l->Value.c_str(), cmOutputConverter::START_OUTPUT); + std::string rel = + lg->Convert(l->Value.c_str(), cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED); fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " "; } else if (!l->Target || l->Target->GetType() != cmState::INTERFACE_LIBRARY) { @@ -1321,8 +1322,8 @@ void cmLocalVisualStudio7GeneratorInternals::OutputObjects( const char* sep = isep ? isep : ""; for (std::vector::const_iterator oi = objs.begin(); oi != objs.end(); ++oi) { - std::string rel = - lg->ConvertToRelativePath(oi->c_str(), cmOutputConverter::START_OUTPUT); + std::string rel = lg->Convert(oi->c_str(), cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED); fout << sep << lg->ConvertToXMLOutputPath(rel.c_str()); sep = " "; } @@ -1345,8 +1346,9 @@ void cmLocalVisualStudio7Generator::OutputLibraryDirectories( // Switch to a relative path specification if it is shorter. if (cmSystemTools::FileIsFullPath(dir.c_str())) { - std::string rel = this->ConvertToRelativePath( - dir.c_str(), cmOutputConverter::START_OUTPUT); + std::string rel = + this->Convert(dir.c_str(), cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED); if (rel.size() < dir.size()) { dir = rel; } diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index b492962..bdb1c2b 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -127,6 +127,7 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( { bool useLocal = this->CustomCommandUseLocal(); std::string workingDirectory = ccg.GetWorkingDirectory(); + RelativeRoot relativeRoot = workingDirectory.empty() ? START_OUTPUT : NONE; // Avoid leading or trailing newlines. std::string newline = ""; @@ -155,8 +156,7 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( script += newline; newline = newline_text; script += "cd "; - script += this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(workingDirectory), SHELL); + script += this->Convert(workingDirectory, FULL, SHELL); script += check_error; // Change the working drive. @@ -203,11 +203,7 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( } } - if (workingDirectory.empty()) { - script += this->Convert(cmd.c_str(), START_OUTPUT, SHELL); - } else { - script += this->ConvertToOutputFormat(cmd.c_str(), SHELL); - } + script += this->Convert(cmd.c_str(), relativeRoot, SHELL); ccg.AppendArguments(c, script); // After each custom command, check for an error result. diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 66e1ca2..74bfedc 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -135,8 +135,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) std::string targetFullPathReal = outpath + targetNameReal; std::string targetFullPathPDB = pdbOutputPath + targetNamePDB; std::string targetFullPathImport = outpathImp + targetNameImport; - std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( - targetFullPathPDB, cmOutputConverter::SHELL); + std::string targetOutPathPDB = this->Convert( + targetFullPathPDB, cmOutputConverter::NONE, cmOutputConverter::SHELL); // Convert to the output path to use in constructing commands. std::string targetOutPath = this->Convert( targetFullPath, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); @@ -218,34 +218,40 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Construct a list of files associated with this executable that // may need to be cleaned. std::vector exeCleanFiles; - exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPath, cmOutputConverter::START_OUTPUT)); + exeCleanFiles.push_back(this->Convert(targetFullPath, + cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED)); #ifdef _WIN32 // There may be a manifest file for this target. Add it to the // clean set just in case. - exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - (targetFullPath + ".manifest").c_str(), cmOutputConverter::START_OUTPUT)); + exeCleanFiles.push_back(this->Convert((targetFullPath + ".manifest").c_str(), + cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED)); #endif if (targetNameReal != targetName) { - exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPathReal, cmOutputConverter::START_OUTPUT)); + exeCleanFiles.push_back(this->Convert(targetFullPathReal, + cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED)); } if (!targetNameImport.empty()) { - exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPathImport, cmOutputConverter::START_OUTPUT)); + exeCleanFiles.push_back(this->Convert(targetFullPathImport, + cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED)); std::string implib; if (this->GeneratorTarget->GetImplibGNUtoMS(targetFullPathImport, implib)) { - exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - implib, cmOutputConverter::START_OUTPUT)); + exeCleanFiles.push_back(this->Convert(implib, + cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED)); } } // List the PDB for cleaning only when the whole target is // cleaned. We do not want to delete the .pdb file just before // linking the target. - this->CleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPathPDB, cmOutputConverter::START_OUTPUT)); + this->CleanFiles.push_back(this->Convert(targetFullPathPDB, + cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED)); // Add the pre-build and pre-link rules building but not when relinking. if (!relink) { @@ -351,8 +357,9 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) vars.Manifests = manifests.c_str(); if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE")) { - std::string cmakeCommand = this->LocalGenerator->ConvertToOutputFormat( - cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); + std::string cmakeCommand = + this->Convert(cmSystemTools::GetCMakeCommand(), cmLocalGenerator::NONE, + cmLocalGenerator::SHELL); cmakeCommand += " -E __run_iwyu --lwyu="; cmakeCommand += targetOutPathReal; real_link_commands.push_back(cmakeCommand); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index b85243e..6727bd0 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -310,8 +310,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // Construct the output path version of the names for use in command // arguments. - std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( - targetFullPathPDB, cmOutputConverter::SHELL); + std::string targetOutPathPDB = this->Convert( + targetFullPathPDB, cmOutputConverter::NONE, cmOutputConverter::SHELL); std::string targetOutPath = this->Convert( targetFullPath, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); std::string targetOutPathSO = @@ -367,40 +367,46 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // Clean files associated with this library. std::vector libCleanFiles; - libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPath, cmOutputConverter::START_OUTPUT)); + libCleanFiles.push_back(this->Convert(targetFullPath, + cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED)); if (targetNameReal != targetName) { - libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPathReal, cmOutputConverter::START_OUTPUT)); + libCleanFiles.push_back(this->Convert(targetFullPathReal, + cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED)); } if (targetNameSO != targetName && targetNameSO != targetNameReal) { - libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPathSO, cmOutputConverter::START_OUTPUT)); + libCleanFiles.push_back(this->Convert(targetFullPathSO, + cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED)); } if (!targetNameImport.empty()) { - libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPathImport, cmOutputConverter::START_OUTPUT)); + libCleanFiles.push_back(this->Convert(targetFullPathImport, + cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED)); std::string implib; if (this->GeneratorTarget->GetImplibGNUtoMS(targetFullPathImport, implib)) { - libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - implib, cmOutputConverter::START_OUTPUT)); + libCleanFiles.push_back(this->Convert(implib, + cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED)); } } // List the PDB for cleaning only when the whole target is // cleaned. We do not want to delete the .pdb file just before // linking the target. - this->CleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPathPDB, cmOutputConverter::START_OUTPUT)); + this->CleanFiles.push_back(this->Convert(targetFullPathPDB, + cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED)); #ifdef _WIN32 // There may be a manifest file for this target. Add it to the // clean set just in case. if (this->GeneratorTarget->GetType() != cmState::STATIC_LIBRARY) { - libCleanFiles.push_back( - this->ConvertToRelativePath((targetFullPath + ".manifest").c_str(), - cmOutputConverter::START_OUTPUT)); + libCleanFiles.push_back(this->Convert( + (targetFullPath + ".manifest").c_str(), cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED)); } #endif @@ -566,8 +572,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( vars.TargetInstallNameDir = ""; } else { // Convert to a path for the native build tool. - install_name_dir = this->LocalGenerator->ConvertToOutputFormat( - install_name_dir, cmOutputConverter::SHELL); + install_name_dir = this->LocalGenerator->Convert( + install_name_dir, cmOutputConverter::NONE, cmOutputConverter::SHELL); vars.TargetInstallNameDir = install_name_dir.c_str(); } } @@ -634,8 +640,9 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( cmSystemTools::ExpandListArgument(linkRule, real_link_commands); if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE") && (this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY)) { - std::string cmakeCommand = this->LocalGenerator->ConvertToOutputFormat( - cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); + std::string cmakeCommand = + this->Convert(cmSystemTools::GetCMakeCommand(), + cmLocalGenerator::NONE, cmLocalGenerator::SHELL); cmakeCommand += " -E __run_iwyu --lwyu="; cmakeCommand += targetOutPathReal; real_link_commands.push_back(cmakeCommand); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 165f96c..5bba29c 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -172,8 +172,8 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() const std::vector& outputs = ccg.GetOutputs(); for (std::vector::const_iterator o = outputs.begin(); o != outputs.end(); ++o) { - this->CleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - *o, cmOutputConverter::START_OUTPUT)); + this->CleanFiles.push_back(this->Convert( + *o, cmOutputConverter::START_OUTPUT, cmOutputConverter::UNCHANGED)); } } } @@ -312,10 +312,8 @@ void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()( output += "/"; output += cmSystemTools::GetFilenameName(input); this->Generator->CleanFiles.push_back( - this->Generator->LocalGenerator->ConvertToRelativePath( - output, cmOutputConverter::START_OUTPUT)); - output = this->Generator->LocalGenerator->ConvertToRelativePath( - output, cmOutputConverter::HOME_OUTPUT); + this->Generator->Convert(output, cmOutputConverter::START_OUTPUT)); + output = this->Generator->Convert(output, cmOutputConverter::HOME_OUTPUT); // Create a rule to copy the content into the bundle. std::vector depends; @@ -326,11 +324,11 @@ void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()( this->Generator->LocalGenerator->AppendEcho( commands, copyEcho, cmLocalUnixMakefileGenerator3::EchoBuild); std::string copyCommand = "$(CMAKE_COMMAND) -E copy "; - copyCommand += this->Generator->LocalGenerator->ConvertToOutputFormat( - input, cmOutputConverter::SHELL); + copyCommand += this->Generator->Convert(input, cmOutputConverter::NONE, + cmOutputConverter::SHELL); copyCommand += " "; - copyCommand += this->Generator->LocalGenerator->ConvertToOutputFormat( - output, cmOutputConverter::SHELL); + copyCommand += this->Generator->Convert(output, cmOutputConverter::NONE, + cmOutputConverter::SHELL); commands.push_back(copyCommand); this->Generator->LocalGenerator->WriteMakeRule( *this->Generator->BuildFileStream, CM_NULLPTR, output, depends, commands, @@ -395,9 +393,9 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( std::string objFullPath = this->LocalGenerator->GetCurrentBinaryDirectory(); objFullPath += "/"; objFullPath += obj; - objFullPath = cmSystemTools::CollapseFullPath(objFullPath); + objFullPath = this->Convert(objFullPath, cmOutputConverter::FULL); std::string srcFullPath = - cmSystemTools::CollapseFullPath(source.GetFullPath()); + this->Convert(source.GetFullPath(), cmOutputConverter::FULL); this->LocalGenerator->AddImplicitDepends( this->GeneratorTarget, lang, objFullPath.c_str(), srcFullPath.c_str()); } @@ -466,8 +464,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( } // Get the output paths for source and object files. - std::string sourceFile = this->LocalGenerator->ConvertToOutputFormat( - source.GetFullPath(), cmOutputConverter::SHELL); + std::string sourceFile = this->Convert( + source.GetFullPath(), cmOutputConverter::NONE, cmOutputConverter::SHELL); // Construct the build message. std::vector no_commands; @@ -518,8 +516,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( targetOutPathReal = this->Convert(targetFullPathReal, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); - targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( - targetFullPathPDB, cmOutputConverter::SHELL); + targetOutPathPDB = this->Convert( + targetFullPathPDB, cmOutputConverter::NONE, cmOutputConverter::SHELL); targetOutPathCompilePDB = this->Convert(targetFullPathCompilePDB, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); @@ -541,7 +539,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( vars.TargetCompilePDB = targetOutPathCompilePDB.c_str(); vars.Source = sourceFile.c_str(); std::string shellObj = - this->LocalGenerator->ConvertToOutputFormat(obj, cmOutputConverter::SHELL); + this->Convert(obj, cmOutputConverter::NONE, cmOutputConverter::SHELL); vars.Object = shellObj.c_str(); std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); objectDir = this->Convert(objectDir, cmOutputConverter::START_OUTPUT, @@ -586,8 +584,9 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( lang_can_export_cmds && compileCommands.size() == 1) { std::string compileCommand = compileCommands[0]; this->LocalGenerator->ExpandRuleVariables(compileCommand, vars); - std::string workingDirectory = cmSystemTools::CollapseFullPath( - this->LocalGenerator->GetCurrentBinaryDirectory()); + std::string workingDirectory = this->LocalGenerator->Convert( + this->LocalGenerator->GetCurrentBinaryDirectory(), + cmOutputConverter::FULL); compileCommand.replace(compileCommand.find(langFlags), langFlags.size(), this->GetFlags(lang)); std::string langDefines = std::string("$(") + lang + "_DEFINES)"; @@ -700,8 +699,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( std::vector preprocessCommands; cmSystemTools::ExpandListArgument(preprocessRule, preprocessCommands); - std::string shellObjI = this->LocalGenerator->ConvertToOutputFormat( - objI, cmOutputConverter::SHELL); + std::string shellObjI = this->Convert(objI, cmOutputConverter::NONE, + cmOutputConverter::SHELL); vars.PreprocessedSource = shellObjI.c_str(); // Expand placeholders in the commands. @@ -747,8 +746,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( std::vector assemblyCommands; cmSystemTools::ExpandListArgument(assemblyRule, assemblyCommands); - std::string shellObjS = this->LocalGenerator->ConvertToOutputFormat( - objS, cmOutputConverter::SHELL); + std::string shellObjS = this->Convert(objS, cmOutputConverter::NONE, + cmOutputConverter::SHELL); vars.AssemblySource = shellObjS.c_str(); // Expand placeholders in the commands. @@ -1000,10 +999,9 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() // paths. Make sure PWD is set to the original name of the home // output directory to help cmSystemTools to create the same // translation table for the dependency scanning process. - depCmd << "cd " << (this->LocalGenerator->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath( - this->LocalGenerator->GetBinaryDirectory()), - cmOutputConverter::SHELL)) + depCmd << "cd " << (this->LocalGenerator->Convert( + this->LocalGenerator->GetBinaryDirectory(), + cmOutputConverter::FULL, cmOutputConverter::SHELL)) << " && "; #endif // Generate a call this signature: @@ -1017,29 +1015,20 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() // the state of our local generator sufficiently for its needs. depCmd << "$(CMAKE_COMMAND) -E cmake_depends \"" << this->GlobalGenerator->GetName() << "\" " - << this->LocalGenerator->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath( - this->LocalGenerator->GetSourceDirectory()), - cmOutputConverter::SHELL) + << this->Convert(this->LocalGenerator->GetSourceDirectory(), + cmOutputConverter::FULL, cmOutputConverter::SHELL) << " " - << this->LocalGenerator->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath( - this->LocalGenerator->GetCurrentSourceDirectory()), - cmOutputConverter::SHELL) + << this->Convert(this->LocalGenerator->GetCurrentSourceDirectory(), + cmOutputConverter::FULL, cmOutputConverter::SHELL) << " " - << this->LocalGenerator->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath( - this->LocalGenerator->GetBinaryDirectory()), - cmOutputConverter::SHELL) + << this->Convert(this->LocalGenerator->GetBinaryDirectory(), + cmOutputConverter::FULL, cmOutputConverter::SHELL) << " " - << this->LocalGenerator->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath( - this->LocalGenerator->GetCurrentBinaryDirectory()), - cmOutputConverter::SHELL) + << this->Convert(this->LocalGenerator->GetCurrentBinaryDirectory(), + cmOutputConverter::FULL, cmOutputConverter::SHELL) << " " - << this->LocalGenerator->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(this->InfoFileNameFull), - cmOutputConverter::SHELL); + << this->Convert(this->InfoFileNameFull, cmOutputConverter::FULL, + cmOutputConverter::SHELL); if (this->LocalGenerator->GetColorMakefile()) { depCmd << " --color=$(COLOR)"; } @@ -1126,8 +1115,10 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile( for (cmCustomCommand::ImplicitDependsList::const_iterator idi = ccg.GetCC().GetImplicitDepends().begin(); idi != ccg.GetCC().GetImplicitDepends().end(); ++idi) { - std::string objFullPath = cmSystemTools::CollapseFullPath(outputs[0]); - std::string srcFullPath = cmSystemTools::CollapseFullPath(idi->second); + std::string objFullPath = + this->Convert(outputs[0], cmOutputConverter::FULL); + std::string srcFullPath = + this->Convert(idi->second, cmOutputConverter::FULL); this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, idi->first, objFullPath.c_str(), srcFullPath.c_str()); @@ -1183,8 +1174,7 @@ void cmMakefileTargetGenerator::WriteObjectsVariable( for (std::vector::const_iterator i = this->ExternalObjects.begin(); i != this->ExternalObjects.end(); ++i) { - object = this->LocalGenerator->ConvertToRelativePath( - *i, cmOutputConverter::START_OUTPUT); + object = this->Convert(*i, cmOutputConverter::START_OUTPUT); *this->BuildFileStream << " " << lineContinue << "\n" << this->Makefile->GetSafeDefinition( "CMAKE_OBJECT_NAME"); @@ -1271,8 +1261,9 @@ void cmMakefileTargetGenerator::WriteTargetDriverRule( this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget); std::string buildTargetRuleName = dir; buildTargetRuleName += relink ? "/preinstall" : "/build"; - buildTargetRuleName = this->LocalGenerator->ConvertToRelativePath( - buildTargetRuleName, cmOutputConverter::HOME_OUTPUT); + buildTargetRuleName = + this->Convert(buildTargetRuleName, cmOutputConverter::HOME_OUTPUT, + cmOutputConverter::UNCHANGED); // Build the list of target outputs to drive. std::vector depends; @@ -1585,8 +1576,8 @@ void cmMakefileTargetGenerator::CreateLinkLibs( // Reference the response file. linkLibs = responseFlag; - linkLibs += this->LocalGenerator->ConvertToOutputFormat( - link_rsp, cmOutputConverter::SHELL); + linkLibs += this->Convert(link_rsp, cmOutputConverter::NONE, + cmOutputConverter::SHELL); } } @@ -1634,8 +1625,8 @@ void cmMakefileTargetGenerator::CreateObjectLists( // Reference the response file. buildObjs += responseFlag; - buildObjs += this->LocalGenerator->ConvertToOutputFormat( - objects_rsp, cmOutputConverter::SHELL); + buildObjs += this->Convert(objects_rsp, cmOutputConverter::NONE, + cmOutputConverter::SHELL); } } else if (useLinkScript) { if (!useArchiveRules) { @@ -1692,8 +1683,8 @@ void cmMakefileTargetGenerator::GenDefFile( name_of_def_file += std::string("/") + this->GeneratorTarget->GetName(); name_of_def_file += ".def"; std::string cmd = cmSystemTools::GetCMakeCommand(); - cmd = this->LocalGenerator->ConvertToOutputFormat( - cmd, cmOutputConverter::SHELL); + cmd = + this->Convert(cmd, cmOutputConverter::NONE, cmOutputConverter::SHELL); cmd += " -E __create_def "; cmd += this->Convert(name_of_def_file, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 335b552..d0db133 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -543,8 +543,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() std::string install_dir = this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName); if (!install_dir.empty()) { - vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat( - install_dir, cmOutputConverter::SHELL); + vars["INSTALLNAME_DIR"] = localGen.Convert( + install_dir, cmOutputConverter::NONE, cmOutputConverter::SHELL); } } } diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 630da42..98872d6 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -46,40 +46,38 @@ std::string cmOutputConverter::ConvertToOutputForExisting( return this->ConvertToOutputFormat(remote, format); } -std::string cmOutputConverter::ConvertToRelativePath( - const std::string& source, RelativeRoot relative) const +std::string cmOutputConverter::Convert(const std::string& source, + RelativeRoot relative, + OutputFormat output) const { - std::string result; + // Convert the path to a relative path. + std::string result = source; switch (relative) { case HOME: result = this->ConvertToRelativePath( - this->GetState()->GetSourceDirectoryComponents(), source); + this->GetState()->GetSourceDirectoryComponents(), result); break; case START: result = this->ConvertToRelativePath( this->StateSnapshot.GetDirectory().GetCurrentSourceComponents(), - source); + result); break; case HOME_OUTPUT: result = this->ConvertToRelativePath( - this->GetState()->GetBinaryDirectoryComponents(), source); + this->GetState()->GetBinaryDirectoryComponents(), result); break; case START_OUTPUT: result = this->ConvertToRelativePath( this->StateSnapshot.GetDirectory().GetCurrentBinaryComponents(), - source); + result); + break; + case FULL: + result = cmSystemTools::CollapseFullPath(result); + break; + case NONE: break; } - return result; -} - -std::string cmOutputConverter::Convert(const std::string& source, - RelativeRoot relative, - OutputFormat output) const -{ - // Convert the path to a relative path. - std::string result = this->ConvertToRelativePath(source, relative); return this->ConvertToOutputFormat(result, output); } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 9af9659..ff06ab6 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -38,6 +38,8 @@ public: */ enum RelativeRoot { + NONE, + FULL, HOME, START, HOME_OUTPUT, @@ -45,6 +47,7 @@ public: }; enum OutputFormat { + UNCHANGED, MAKERULE, SHELL, WATCOMQUOTE, @@ -53,9 +56,7 @@ public: std::string ConvertToOutputFormat(const std::string& source, OutputFormat output) const; std::string Convert(const std::string& remote, RelativeRoot local, - OutputFormat output) const; - std::string ConvertToRelativePath(const std::string& remote, - RelativeRoot local) const; + OutputFormat output = UNCHANGED) const; std::string ConvertDirectorySeparatorsForShell( const std::string& source) const; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index d5274cd..ed04d2f 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -602,8 +602,7 @@ void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const it != this->TLLCommands.end(); ++it) { if (it->first == sig) { cmListFileContext lfc = it->second; - lfc.FilePath = - converter.ConvertToRelativePath(lfc.FilePath, cmOutputConverter::HOME); + lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME); s << " * " << lfc << std::endl; } } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 216de03..1b1d04b 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2416,8 +2416,9 @@ void cmVisualStudio10TargetGenerator::AddLibraries( ItemVector libs = cli.GetItems(); for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) { if (l->IsPath) { - std::string path = this->LocalGenerator->ConvertToRelativePath( - l->Value.c_str(), cmOutputConverter::START_OUTPUT); + std::string path = this->LocalGenerator->Convert( + l->Value.c_str(), cmOutputConverter::START_OUTPUT, + cmOutputConverter::UNCHANGED); this->ConvertToWindowsSlash(path); libVec.push_back(path); } else if (!l->Target || ----------------------------------------------------------------------- Summary of changes: Source/cmCommonTargetGenerator.h | 6 +- Source/cmDependsC.cxx | 4 +- Source/cmDependsFortran.cxx | 10 +- Source/cmExtraEclipseCDT4Generator.cxx | 4 +- Source/cmGlobalGenerator.cxx | 4 +- Source/cmGlobalNinjaGenerator.cxx | 6 +- Source/cmGlobalUnixMakefileGenerator3.cxx | 31 ++---- Source/cmGlobalVisualStudio7Generator.cxx | 3 +- Source/cmListFileCache.cxx | 6 +- Source/cmLocalCommonGenerator.cxx | 3 +- Source/cmLocalGenerator.cxx | 25 ++--- Source/cmLocalNinjaGenerator.cxx | 23 ++--- Source/cmLocalUnixMakefileGenerator3.cxx | 127 ++++++++++++------------ Source/cmLocalUnixMakefileGenerator3.h | 3 + Source/cmLocalVisualStudio7Generator.cxx | 26 ++--- Source/cmLocalVisualStudioGenerator.cxx | 10 +- Source/cmMakefileExecutableTargetGenerator.cxx | 39 +++++--- Source/cmMakefileLibraryTargetGenerator.cxx | 49 +++++---- Source/cmMakefileTargetGenerator.cxx | 107 +++++++++----------- Source/cmNinjaNormalTargetGenerator.cxx | 4 +- Source/cmOutputConverter.cxx | 30 +++--- Source/cmOutputConverter.h | 7 +- Source/cmTarget.cxx | 3 +- Source/cmVisualStudio10TargetGenerator.cxx | 5 +- 24 files changed, 261 insertions(+), 274 deletions(-) hooks/post-receive -- CMake From steveire at gmail.com Sat Aug 27 08:47:44 2016 From: steveire at gmail.com (Stephen Kelly) Date: Sat, 27 Aug 2016 08:47:44 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1535-g677090f Message-ID: <20160827124744.AAD73F3D33@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 677090f0749b78f9cc44e33c7a77c6eda977be0f (commit) via ad4b7e05980bd53686fd48ba341c954985ad3056 (commit) from 2b114c41b54c4d14745b2b98c57ccc7c92111f7e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=677090f0749b78f9cc44e33c7a77c6eda977be0f commit 677090f0749b78f9cc44e33c7a77c6eda977be0f Merge: 2b114c4 ad4b7e0 Author: Stephen Kelly AuthorDate: Sat Aug 27 08:47:44 2016 -0400 Commit: CMake Topic Stage CommitDate: Sat Aug 27 08:47:44 2016 -0400 Merge topic 'cleanup-Convert' into next ad4b7e05 Makefiles: Remove uselss uses of Convert https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ad4b7e05980bd53686fd48ba341c954985ad3056 commit ad4b7e05980bd53686fd48ba341c954985ad3056 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:53 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 14:47:13 2016 +0200 Makefiles: Remove uselss uses of Convert Convert with NONE and UNCHANGED is a no-op. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index cb82d0a..b3d601a 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -835,8 +835,7 @@ std::string cmLocalUnixMakefileGenerator3::GetRelativeTargetDirectory( { std::string dir = this->HomeRelativeOutputPath; dir += this->GetTargetDirectory(target); - return this->Convert(dir, cmOutputConverter::NONE, - cmOutputConverter::UNCHANGED); + return dir; } void cmLocalUnixMakefileGenerator3::AppendFlags(std::string& flags, @@ -982,7 +981,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( : cmOutputConverter::NONE); std::string shellCommand = this->MaybeConvertWacomShellCommand(cmd); if (shellCommand.empty()) { - shellCommand = this->Convert(cmd, cmOutputConverter::NONE); + shellCommand = cmd; } cmd = launcher + shellCommand; ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From steveire at gmail.com Sat Aug 27 09:13:45 2016 From: steveire at gmail.com (Stephen Kelly) Date: Sat, 27 Aug 2016 09:13:45 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1537-g978941f Message-ID: <20160827131345.9F377F34DB@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 978941f83ab3e4bd80ac52100a13c68a85bb8ce0 (commit) via 99483b9f9828e459e3e7887cea02d82aae887866 (commit) from 677090f0749b78f9cc44e33c7a77c6eda977be0f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=978941f83ab3e4bd80ac52100a13c68a85bb8ce0 commit 978941f83ab3e4bd80ac52100a13c68a85bb8ce0 Merge: 677090f 99483b9 Author: Stephen Kelly AuthorDate: Sat Aug 27 09:13:44 2016 -0400 Commit: CMake Topic Stage CommitDate: Sat Aug 27 09:13:44 2016 -0400 Merge topic 'cleanup-Convert' into next 99483b9f Revert "Makefiles: Remove uselss uses of Convert" https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=99483b9f9828e459e3e7887cea02d82aae887866 commit 99483b9f9828e459e3e7887cea02d82aae887866 Author: Stephen Kelly AuthorDate: Sat Aug 27 15:13:29 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:13:29 2016 +0200 Revert "Makefiles: Remove uselss uses of Convert" This reverts commit ad4b7e05980bd53686fd48ba341c954985ad3056. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index b3d601a..cb82d0a 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -835,7 +835,8 @@ std::string cmLocalUnixMakefileGenerator3::GetRelativeTargetDirectory( { std::string dir = this->HomeRelativeOutputPath; dir += this->GetTargetDirectory(target); - return dir; + return this->Convert(dir, cmOutputConverter::NONE, + cmOutputConverter::UNCHANGED); } void cmLocalUnixMakefileGenerator3::AppendFlags(std::string& flags, @@ -981,7 +982,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( : cmOutputConverter::NONE); std::string shellCommand = this->MaybeConvertWacomShellCommand(cmd); if (shellCommand.empty()) { - shellCommand = cmd; + shellCommand = this->Convert(cmd, cmOutputConverter::NONE); } cmd = launcher + shellCommand; ----------------------------------------------------------------------- Summary of changes: Source/cmLocalUnixMakefileGenerator3.cxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) hooks/post-receive -- CMake From steveire at gmail.com Sat Aug 27 09:14:17 2016 From: steveire at gmail.com (Stephen Kelly) Date: Sat, 27 Aug 2016 09:14:17 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1539-g4812110 Message-ID: <20160827131417.1EB23F3715@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 4812110823f42f84573a23c87459afa91349995f (commit) via dc0edf29b65c50d25da84ecca0c48131f5da69c0 (commit) from 978941f83ab3e4bd80ac52100a13c68a85bb8ce0 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4812110823f42f84573a23c87459afa91349995f commit 4812110823f42f84573a23c87459afa91349995f Merge: 978941f dc0edf2 Author: Stephen Kelly AuthorDate: Sat Aug 27 09:14:16 2016 -0400 Commit: CMake Topic Stage CommitDate: Sat Aug 27 09:14:16 2016 -0400 Merge topic 'cleanup-Convert' into next dc0edf29 Fixup commit https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=dc0edf29b65c50d25da84ecca0c48131f5da69c0 commit dc0edf29b65c50d25da84ecca0c48131f5da69c0 Author: Stephen Kelly AuthorDate: Sat Aug 27 15:12:41 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:13:56 2016 +0200 Fixup commit diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index cb82d0a..085cc91 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -982,7 +982,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( : cmOutputConverter::NONE); std::string shellCommand = this->MaybeConvertWacomShellCommand(cmd); if (shellCommand.empty()) { - shellCommand = this->Convert(cmd, cmOutputConverter::NONE); + shellCommand = this->Convert(cmd, cmOutputConverter::NONE, cmOutputConverter::SHELL); } cmd = launcher + shellCommand; ----------------------------------------------------------------------- Summary of changes: Source/cmLocalUnixMakefileGenerator3.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From steveire at gmail.com Sat Aug 27 09:14:42 2016 From: steveire at gmail.com (Stephen Kelly) Date: Sat, 27 Aug 2016 09:14:42 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1541-ga0d49a9 Message-ID: <20160827131442.288F2F37D7@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via a0d49a9213400b3bbb9f2505d09e47c3680a4680 (commit) via 8bdd65e82731fc93ad9a9c63658b104c50fca82b (commit) from 4812110823f42f84573a23c87459afa91349995f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a0d49a9213400b3bbb9f2505d09e47c3680a4680 commit a0d49a9213400b3bbb9f2505d09e47c3680a4680 Merge: 4812110 8bdd65e Author: Stephen Kelly AuthorDate: Sat Aug 27 09:14:41 2016 -0400 Commit: CMake Topic Stage CommitDate: Sat Aug 27 09:14:41 2016 -0400 Merge topic 'cleanup-Convert' into next 8bdd65e8 Makefiles: Replace method with Wacom specific API https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8bdd65e82731fc93ad9a9c63658b104c50fca82b commit 8bdd65e82731fc93ad9a9c63658b104c50fca82b Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:53 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:14:28 2016 +0200 Makefiles: Replace method with Wacom specific API The existing method uses RelativeRoot NONE and FULL values. In principle, those should be segregated interfaces. Mixing NONE and FULL into the RelativeRoot enum is a case of http://thedailywtf.com/articles/What_Is_Truth_0x3f_ diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index f2ef5c8..085cc91 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -592,8 +592,8 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule( } } -std::string cmLocalUnixMakefileGenerator3::ConvertShellCommand( - std::string const& cmd, cmOutputConverter::RelativeRoot root) +std::string cmLocalUnixMakefileGenerator3::MaybeConvertWacomShellCommand( + std::string const& cmd) { if (this->IsWatcomWMake() && cmSystemTools::FileIsFullPath(cmd.c_str()) && cmd.find_first_of("( )") != cmd.npos) { @@ -606,7 +606,7 @@ std::string cmLocalUnixMakefileGenerator3::ConvertShellCommand( cmOutputConverter::SHELL); } } - return this->Convert(cmd, root, cmOutputConverter::SHELL); + return std::string(); } void cmLocalUnixMakefileGenerator3::WriteMakeVariables( @@ -638,8 +638,13 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( #endif } - std::string cmakeShellCommand = this->ConvertShellCommand( - cmSystemTools::GetCMakeCommand(), cmOutputConverter::FULL); + std::string cmakeShellCommand = + this->MaybeConvertWacomShellCommand(cmSystemTools::GetCMakeCommand()); + if (cmakeShellCommand.empty()) { + cmakeShellCommand = + this->Convert(cmSystemTools::GetCMakeCommand(), cmOutputConverter::FULL, + cmOutputConverter::SHELL); + } /* clang-format off */ makefileStream @@ -975,7 +980,11 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( std::string launcher = this->MakeLauncher( ccg, target, workingDir.empty() ? cmOutputConverter::START_OUTPUT : cmOutputConverter::NONE); - cmd = launcher + this->ConvertShellCommand(cmd, cmOutputConverter::NONE); + std::string shellCommand = this->MaybeConvertWacomShellCommand(cmd); + if (shellCommand.empty()) { + shellCommand = this->Convert(cmd, cmOutputConverter::NONE, cmOutputConverter::SHELL); + } + cmd = launcher + shellCommand; ccg.AppendArguments(c, cmd); if (content) { diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index 243cc3d..9541f65 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -250,8 +250,7 @@ protected: void CheckMultipleOutputs(bool verbose); private: - std::string ConvertShellCommand(std::string const& cmd, - cmOutputConverter::RelativeRoot root); + std::string MaybeConvertWacomShellCommand(std::string const& cmd); std::string MakeLauncher(cmCustomCommandGenerator const& ccg, cmGeneratorTarget* target, cmOutputConverter::RelativeRoot relative); ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From steveire at gmail.com Sat Aug 27 09:16:40 2016 From: steveire at gmail.com (Stephen Kelly) Date: Sat, 27 Aug 2016 09:16:40 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1543-g11a80af Message-ID: <20160827131640.9D2F2F3970@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 11a80af5b291997c173df0451fddfa3aaa4f4752 (commit) via 62f19fc531e2d3cc292005bcfaedc341966c01e9 (commit) from a0d49a9213400b3bbb9f2505d09e47c3680a4680 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=11a80af5b291997c173df0451fddfa3aaa4f4752 commit 11a80af5b291997c173df0451fddfa3aaa4f4752 Merge: a0d49a9 62f19fc Author: Stephen Kelly AuthorDate: Sat Aug 27 09:16:39 2016 -0400 Commit: CMake Topic Stage CommitDate: Sat Aug 27 09:16:39 2016 -0400 Merge topic 'cleanup-Convert' into next 62f19fc5 fixup! Makefiles: Replace method with Wacom specific API https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=62f19fc531e2d3cc292005bcfaedc341966c01e9 commit 62f19fc531e2d3cc292005bcfaedc341966c01e9 Author: Stephen Kelly AuthorDate: Sat Aug 27 15:16:15 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:16:15 2016 +0200 fixup! Makefiles: Replace method with Wacom specific API diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 085cc91..2ef9a39 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -982,7 +982,8 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( : cmOutputConverter::NONE); std::string shellCommand = this->MaybeConvertWacomShellCommand(cmd); if (shellCommand.empty()) { - shellCommand = this->Convert(cmd, cmOutputConverter::NONE, cmOutputConverter::SHELL); + shellCommand = this->Convert(cmd, cmOutputConverter::NONE, + cmOutputConverter::SHELL); } cmd = launcher + shellCommand; ----------------------------------------------------------------------- Summary of changes: Source/cmLocalUnixMakefileGenerator3.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) hooks/post-receive -- CMake From steveire at gmail.com Sat Aug 27 09:17:12 2016 From: steveire at gmail.com (Stephen Kelly) Date: Sat, 27 Aug 2016 09:17:12 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1545-ge0cb867 Message-ID: <20160827131712.412F5F470B@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via e0cb8675975b1ca4d3576c1f0847ff9a6bad1b1e (commit) via 638f907bc6f61935714d688df20611fc65385c27 (commit) from 11a80af5b291997c173df0451fddfa3aaa4f4752 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e0cb8675975b1ca4d3576c1f0847ff9a6bad1b1e commit e0cb8675975b1ca4d3576c1f0847ff9a6bad1b1e Merge: 11a80af 638f907 Author: Stephen Kelly AuthorDate: Sat Aug 27 09:17:11 2016 -0400 Commit: CMake Topic Stage CommitDate: Sat Aug 27 09:17:11 2016 -0400 Merge topic 'cleanup-Convert' into next 638f907b Makefiles: Replace method with Wacom specific API https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=638f907bc6f61935714d688df20611fc65385c27 commit 638f907bc6f61935714d688df20611fc65385c27 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:53 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:16:50 2016 +0200 Makefiles: Replace method with Wacom specific API The existing method uses RelativeRoot NONE and FULL values. In principle, those should be segregated interfaces. Mixing NONE and FULL into the RelativeRoot enum is a case of http://thedailywtf.com/articles/What_Is_Truth_0x3f_ diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index f2ef5c8..2ef9a39 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -592,8 +592,8 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule( } } -std::string cmLocalUnixMakefileGenerator3::ConvertShellCommand( - std::string const& cmd, cmOutputConverter::RelativeRoot root) +std::string cmLocalUnixMakefileGenerator3::MaybeConvertWacomShellCommand( + std::string const& cmd) { if (this->IsWatcomWMake() && cmSystemTools::FileIsFullPath(cmd.c_str()) && cmd.find_first_of("( )") != cmd.npos) { @@ -606,7 +606,7 @@ std::string cmLocalUnixMakefileGenerator3::ConvertShellCommand( cmOutputConverter::SHELL); } } - return this->Convert(cmd, root, cmOutputConverter::SHELL); + return std::string(); } void cmLocalUnixMakefileGenerator3::WriteMakeVariables( @@ -638,8 +638,13 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( #endif } - std::string cmakeShellCommand = this->ConvertShellCommand( - cmSystemTools::GetCMakeCommand(), cmOutputConverter::FULL); + std::string cmakeShellCommand = + this->MaybeConvertWacomShellCommand(cmSystemTools::GetCMakeCommand()); + if (cmakeShellCommand.empty()) { + cmakeShellCommand = + this->Convert(cmSystemTools::GetCMakeCommand(), cmOutputConverter::FULL, + cmOutputConverter::SHELL); + } /* clang-format off */ makefileStream @@ -975,7 +980,12 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( std::string launcher = this->MakeLauncher( ccg, target, workingDir.empty() ? cmOutputConverter::START_OUTPUT : cmOutputConverter::NONE); - cmd = launcher + this->ConvertShellCommand(cmd, cmOutputConverter::NONE); + std::string shellCommand = this->MaybeConvertWacomShellCommand(cmd); + if (shellCommand.empty()) { + shellCommand = this->Convert(cmd, cmOutputConverter::NONE, + cmOutputConverter::SHELL); + } + cmd = launcher + shellCommand; ccg.AppendArguments(c, cmd); if (content) { diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index 243cc3d..9541f65 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -250,8 +250,7 @@ protected: void CheckMultipleOutputs(bool verbose); private: - std::string ConvertShellCommand(std::string const& cmd, - cmOutputConverter::RelativeRoot root); + std::string MaybeConvertWacomShellCommand(std::string const& cmd); std::string MakeLauncher(cmCustomCommandGenerator const& ccg, cmGeneratorTarget* target, cmOutputConverter::RelativeRoot relative); ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From steveire at gmail.com Sat Aug 27 09:28:14 2016 From: steveire at gmail.com (Stephen Kelly) Date: Sat, 27 Aug 2016 09:28:14 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1564-g799348a Message-ID: <20160827132814.23A32F53DC@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 799348a2d38e6237561168184fcab801262ffe3a (commit) via 0bfbf20d0abf33e79f29b30989681b93905b71bb (commit) via e638beafc895732f2e1ebb91bd6f5c8ea7989f28 (commit) via 8770a8e095d9c6a8da636054bdf0ac72f3659e42 (commit) via 25cb07603b4381a857f39189bd96e3dfec9bef20 (commit) via ef50bcbd7b73dab0bd20ec0b9ae72aab01511bc6 (commit) via effa38cd6f4ef4b71e04733002871c492bc203e5 (commit) via d34a12ad76c1566ecc4fe02ed25670b0d679540f (commit) via 1e3dba183f2b00b25ef9a8ce3b02b8ee3f0fc256 (commit) via fa8df52d0e03b45cb8a46f2c6e9647cee33fd60a (commit) via 0a47e1d9ac4ffac21874daae332422e125e3aa41 (commit) via 1bf869716b00f925b6a315737d8c5553b2d04a26 (commit) via 8be68b73457470bf886b9d633142c8d3e91f1d80 (commit) via d7bc7c89771a582fb390d2f8c922515acddaa2b5 (commit) via 5761b1dd875d857991a0827e65b7128b73d7f8f7 (commit) via 16dad45d29f6fc8a84c2ff5ae2ca7c098b532c9c (commit) via e80e6644bb7f4eaf681390b5071a01856d6545d4 (commit) via ab07619914e3857c213d733c8c46a1a439a85ed1 (commit) via 85997982e51177c966c691dcd660b133b74f6229 (commit) from e0cb8675975b1ca4d3576c1f0847ff9a6bad1b1e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=799348a2d38e6237561168184fcab801262ffe3a commit 799348a2d38e6237561168184fcab801262ffe3a Merge: e0cb867 0bfbf20 Author: Stephen Kelly AuthorDate: Sat Aug 27 09:28:12 2016 -0400 Commit: CMake Topic Stage CommitDate: Sat Aug 27 09:28:12 2016 -0400 Merge topic 'cleanup-Convert' into next 0bfbf20d Convert: Make variables a bit more clear e638beaf Convert: Remove UNCHANGED enum value 8770a8e0 Convert: Remove 'FULL' conversion 25cb0760 Convert: Replace Convert(FULL) with equivalent ef50bcbd Ninja: Replace ternary with if() effa38cd Convert: Replace trivial conversion with new method d34a12ad Convert: Replace UNCHANGED conversions with new API call 1e3dba18 Convert: Extract ConvertToRelativePath from Convert() fa8df52d Convert: Replace FULL conversions with equivalent 0a47e1d9 VS: Replace FULL/UNCHANGED conversion with equivalent 1bf86971 Convert: Remove NONE conversion 8be68b73 Convert: Replace uses of Convert(NONE) d7bc7c89 VS: Replace variable with an if() 5761b1dd Makefiles: Replace ternaries with if()s 16dad45d Makefiles: Inline MakeLauncher into only caller e80e6644 Makefiles: Simplify MakeLauncher return value ... https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0bfbf20d0abf33e79f29b30989681b93905b71bb commit 0bfbf20d0abf33e79f29b30989681b93905b71bb Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:58 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:38 2016 +0200 Convert: Make variables a bit more clear diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index f056a1b..630da42 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -49,26 +49,26 @@ std::string cmOutputConverter::ConvertToOutputForExisting( std::string cmOutputConverter::ConvertToRelativePath( const std::string& source, RelativeRoot relative) const { - std::string result = source; + std::string result; switch (relative) { case HOME: result = this->ConvertToRelativePath( - this->GetState()->GetSourceDirectoryComponents(), result); + this->GetState()->GetSourceDirectoryComponents(), source); break; case START: result = this->ConvertToRelativePath( this->StateSnapshot.GetDirectory().GetCurrentSourceComponents(), - result); + source); break; case HOME_OUTPUT: result = this->ConvertToRelativePath( - this->GetState()->GetBinaryDirectoryComponents(), result); + this->GetState()->GetBinaryDirectoryComponents(), source); break; case START_OUTPUT: result = this->ConvertToRelativePath( this->StateSnapshot.GetDirectory().GetCurrentBinaryComponents(), - result); + source); break; } return result; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e638beafc895732f2e1ebb91bd6f5c8ea7989f28 commit e638beafc895732f2e1ebb91bd6f5c8ea7989f28 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:57 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:38 2016 +0200 Convert: Remove UNCHANGED enum value It is no longer used. diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index d3f9d64..b433c18 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -57,9 +57,9 @@ protected: // The windows module definition source file (.def), if any. cmSourceFile const* ModuleDefinitionFile; - std::string Convert( - std::string const& source, cmOutputConverter::RelativeRoot relative, - cmOutputConverter::OutputFormat output = cmOutputConverter::UNCHANGED); + std::string Convert(std::string const& source, + cmOutputConverter::RelativeRoot relative, + cmOutputConverter::OutputFormat output); void AppendFortranFormatFlags(std::string& flags, cmSourceFile const& source); diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index c2403db..9af9659 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -45,7 +45,6 @@ public: }; enum OutputFormat { - UNCHANGED, MAKERULE, SHELL, WATCOMQUOTE, @@ -54,7 +53,7 @@ public: std::string ConvertToOutputFormat(const std::string& source, OutputFormat output) const; std::string Convert(const std::string& remote, RelativeRoot local, - OutputFormat output = UNCHANGED) const; + OutputFormat output) const; std::string ConvertToRelativePath(const std::string& remote, RelativeRoot local) const; std::string ConvertDirectorySeparatorsForShell( https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8770a8e095d9c6a8da636054bdf0ac72f3659e42 commit 8770a8e095d9c6a8da636054bdf0ac72f3659e42 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:57 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:38 2016 +0200 Convert: Remove 'FULL' conversion It is no longer used. diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 176c9a0..f056a1b 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -70,9 +70,6 @@ std::string cmOutputConverter::ConvertToRelativePath( this->StateSnapshot.GetDirectory().GetCurrentBinaryComponents(), result); break; - case FULL: - result = cmSystemTools::CollapseFullPath(result); - break; } return result; } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 71bb086..c2403db 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -38,7 +38,6 @@ public: */ enum RelativeRoot { - FULL, HOME, START, HOME_OUTPUT, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=25cb07603b4381a857f39189bd96e3dfec9bef20 commit 25cb07603b4381a857f39189bd96e3dfec9bef20 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:57 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:38 2016 +0200 Convert: Replace Convert(FULL) with equivalent This is more explicit than funnelling everything through the Convert method. diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index bbc794d..77fbbe9 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -723,8 +723,9 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # in target - progCmd << lg->Convert(progress.Dir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << lg->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progress.Dir), + cmOutputConverter::SHELL); // std::set emitted; progCmd << " " << this->CountProgressMarksInTarget(gtarget, emitted); @@ -736,8 +737,9 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0 - progCmd << lg->Convert(progress.Dir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << lg->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progress.Dir), + cmOutputConverter::SHELL); progCmd << " 0"; commands.push_back(progCmd.str()); } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 2fa3f86..de9e1e5 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -688,7 +688,9 @@ std::string cmLocalGenerator::ExpandRuleVariable( } } if (variable == "CMAKE_COMMAND") { - return this->Convert(cmSystemTools::GetCMakeCommand(), FULL, SHELL); + return this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()), + SHELL); } std::vector enabledLanguages = this->GetState()->GetEnabledLanguages(); @@ -1183,7 +1185,8 @@ void cmLocalGenerator::GetTargetFlags( if (sf->GetExtension() == "def") { linkFlags += this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG"); - linkFlags += this->Convert(sf->GetFullPath(), FULL, SHELL); + linkFlags += this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(sf->GetFullPath()), SHELL); linkFlags += " "; } } diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index bbec634..d07bfaa 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -133,7 +133,8 @@ std::string cmLocalNinjaGenerator::ConvertToIncludeReference( bool forceFullPaths) { if (forceFullPaths) { - return this->Convert(path, cmOutputConverter::FULL, format); + return this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(path), + format); } return this->Convert(path, cmOutputConverter::HOME_OUTPUT, format); } diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 0a0089b..660483e 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -640,9 +640,9 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( std::string cmakeShellCommand = this->MaybeConvertWacomShellCommand(cmSystemTools::GetCMakeCommand()); if (cmakeShellCommand.empty()) { - cmakeShellCommand = - this->Convert(cmSystemTools::GetCMakeCommand(), cmOutputConverter::FULL, - cmOutputConverter::SHELL); + cmakeShellCommand = this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()), + cmOutputConverter::SHELL); } /* clang-format off */ @@ -665,16 +665,14 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( makefileStream << "# The top-level source directory on which CMake was run.\n" << "CMAKE_SOURCE_DIR = " - << this->Convert(this->GetSourceDirectory(), - cmOutputConverter::FULL, + << this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(this->GetSourceDirectory()), cmOutputConverter::SHELL) << "\n" << "\n"; makefileStream << "# The top-level build directory on which CMake was run.\n" << "CMAKE_BINARY_DIR = " - << this->Convert(this->GetBinaryDirectory(), - cmOutputConverter::FULL, + << this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(this->GetBinaryDirectory()), cmOutputConverter::SHELL) << "\n" << "\n"; @@ -1154,8 +1152,9 @@ void cmLocalUnixMakefileGenerator3::AppendEcho( cmd += color_name; if (progress) { cmd += "--progress-dir="; - cmd += this->Convert(progress->Dir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + cmd += this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progress->Dir), + cmOutputConverter::SHELL); cmd += " "; cmd += "--progress-num="; cmd += progress->Arg; @@ -1603,15 +1602,16 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; - progCmd << this->Convert(progressDir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL); std::string progressFile = cmake::GetCMakeFilesDirectory(); progressFile += "/progress.marks"; std::string progressFileNameFull = this->ConvertToFullPath(progressFile); progCmd << " " - << this->Convert(progressFileNameFull, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progressFileNameFull), + cmOutputConverter::SHELL); commands.push_back(progCmd.str()); } std::string mf2Dir = cmake::GetCMakeFilesDirectoryPostSlash(); @@ -1623,8 +1623,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0 - progCmd << this->Convert(progressDir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL); progCmd << " 0"; commands.push_back(progCmd.str()); } diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 1beaa87..70fe819 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -269,8 +269,8 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() args += this->GetBinaryDirectory(); commandLine.push_back(args); commandLine.push_back("--check-stamp-file"); - std::string stampFilename = this->Convert( - stampName.c_str(), cmOutputConverter::FULL, cmOutputConverter::SHELL); + std::string stampFilename = this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(stampName), cmOutputConverter::SHELL); commandLine.push_back(stampFilename.c_str()); std::vector const& listFiles = this->Makefile->GetListFiles(); diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index d1cefe3..b492962 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -155,7 +155,8 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( script += newline; newline = newline_text; script += "cd "; - script += this->Convert(workingDirectory, FULL, SHELL); + script += this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(workingDirectory), SHELL); script += check_error; // Change the working drive. diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index b34cd6e..165f96c 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1000,9 +1000,10 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() // paths. Make sure PWD is set to the original name of the home // output directory to help cmSystemTools to create the same // translation table for the dependency scanning process. - depCmd << "cd " << (this->LocalGenerator->Convert( - this->LocalGenerator->GetBinaryDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL)) + depCmd << "cd " << (this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetBinaryDirectory()), + cmOutputConverter::SHELL)) << " && "; #endif // Generate a call this signature: @@ -1016,20 +1017,29 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() // the state of our local generator sufficiently for its needs. depCmd << "$(CMAKE_COMMAND) -E cmake_depends \"" << this->GlobalGenerator->GetName() << "\" " - << this->Convert(this->LocalGenerator->GetSourceDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetSourceDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->LocalGenerator->GetCurrentSourceDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetCurrentSourceDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->LocalGenerator->GetBinaryDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetBinaryDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->LocalGenerator->GetCurrentBinaryDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetCurrentBinaryDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->InfoFileNameFull, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(this->InfoFileNameFull), + cmOutputConverter::SHELL); if (this->LocalGenerator->GetColorMakefile()) { depCmd << " --color=$(COLOR)"; } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ef50bcbd7b73dab0bd20ec0b9ae72aab01511bc6 commit ef50bcbd7b73dab0bd20ec0b9ae72aab01511bc6 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:57 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:38 2016 +0200 Ninja: Replace ternary with if() On principle of segregating the interface. diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 9e2c920..bbec634 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -132,9 +132,10 @@ std::string cmLocalNinjaGenerator::ConvertToIncludeReference( std::string const& path, cmOutputConverter::OutputFormat format, bool forceFullPaths) { - return this->Convert(path, forceFullPaths ? cmOutputConverter::FULL - : cmOutputConverter::HOME_OUTPUT, - format); + if (forceFullPaths) { + return this->Convert(path, cmOutputConverter::FULL, format); + } + return this->Convert(path, cmOutputConverter::HOME_OUTPUT, format); } // Private methods. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=effa38cd6f4ef4b71e04733002871c492bc203e5 commit effa38cd6f4ef4b71e04733002871c492bc203e5 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:56 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:37 2016 +0200 Convert: Replace trivial conversion with new method diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index 18e123e..928f7ec 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -238,8 +238,8 @@ bool cmDependsC::WriteDependencies(const std::set& sources, // written by the original local generator for this directory // convert the dependencies to paths relative to the home output // directory. We must do the same here. - std::string obj_i = - this->LocalGenerator->Convert(obj, cmOutputConverter::HOME_OUTPUT); + std::string obj_i = this->LocalGenerator->ConvertToRelativePath( + obj, cmOutputConverter::HOME_OUTPUT); std::string obj_m = this->LocalGenerator->ConvertToOutputFormat( obj_i, cmOutputConverter::MAKERULE); internalDepends << obj_i << std::endl; diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index c57b558..8c0acce 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -193,15 +193,15 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends, stamp += ".mod.stamp"; fcStream << "\n"; fcStream << " \"" - << this->LocalGenerator->Convert( + << this->LocalGenerator->ConvertToRelativePath( mod_lower, cmOutputConverter::START_OUTPUT) << "\"\n"; fcStream << " \"" - << this->LocalGenerator->Convert( + << this->LocalGenerator->ConvertToRelativePath( mod_upper, cmOutputConverter::START_OUTPUT) << "\"\n"; fcStream << " \"" - << this->LocalGenerator->Convert( + << this->LocalGenerator->ConvertToRelativePath( stamp, cmOutputConverter::START_OUTPUT) << "\"\n"; } @@ -317,8 +317,8 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, const char* src = info.Source.c_str(); // Write the include dependencies to the output stream. - std::string obj_i = - this->LocalGenerator->Convert(obj, cmOutputConverter::HOME_OUTPUT); + std::string obj_i = this->LocalGenerator->ConvertToRelativePath( + obj, cmOutputConverter::HOME_OUTPUT); std::string obj_m = this->LocalGenerator->ConvertToOutputFormat( obj_i, cmOutputConverter::MAKERULE); internalDepends << obj_i << std::endl; diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index e617b08..945ee40 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -904,8 +904,8 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const it != this->GlobalGenerator->GetLocalGenerators().end(); ++it) { const std::vector targets = (*it)->GetGeneratorTargets(); - std::string subdir = (*it)->Convert((*it)->GetCurrentBinaryDirectory(), - cmOutputConverter::HOME_OUTPUT); + std::string subdir = (*it)->ConvertToRelativePath( + (*it)->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT); if (subdir == ".") { subdir = ""; } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 295f65b..50c5a42 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -2547,8 +2547,8 @@ void cmGlobalGenerator::AddRuleHash(const std::vector& outputs, // Shorten the output name (in expected use case). cmOutputConverter converter(this->GetMakefiles()[0]->GetStateSnapshot()); - std::string fname = - converter.Convert(outputs[0], cmOutputConverter::HOME_OUTPUT); + std::string fname = converter.ConvertToRelativePath( + outputs[0], cmOutputConverter::HOME_OUTPUT); // Associate the hash with this output. this->RuleHashes[fname] = hash; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 2b83479..939c5ad 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -747,7 +747,8 @@ std::string cmGlobalNinjaGenerator::ConvertToNinjaPath(const std::string& path) { cmLocalNinjaGenerator* ng = static_cast(this->LocalGenerators[0]); - std::string convPath = ng->Convert(path, cmOutputConverter::HOME_OUTPUT); + std::string convPath = + ng->ConvertToRelativePath(path, cmOutputConverter::HOME_OUTPUT); convPath = this->NinjaOutputPath(convPath); #ifdef _WIN32 std::replace(convPath.begin(), convPath.end(), '/', '\\'); @@ -760,7 +761,8 @@ std::string cmGlobalNinjaGenerator::ConvertToNinjaFolderRule( { cmLocalNinjaGenerator* ng = static_cast(this->LocalGenerators[0]); - std::string convPath = ng->Convert(path + "/all", cmOutputConverter::HOME); + std::string convPath = + ng->ConvertToRelativePath(path + "/all", cmOutputConverter::HOME); convPath = this->NinjaOutputPath(convPath); #ifdef _WIN32 std::replace(convPath.begin(), convPath.end(), '/', '\\'); diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index f115ecb..bbc794d 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -311,11 +311,14 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() cmakefileStream << "# The top level Makefile was generated from the following files:\n" << "set(CMAKE_MAKEFILE_DEPENDS\n" - << " \"" << lg->Convert(cache, cmOutputConverter::START_OUTPUT) << "\"\n"; + << " \"" + << lg->ConvertToRelativePath(cache, cmOutputConverter::START_OUTPUT) + << "\"\n"; for (std::vector::const_iterator i = lfiles.begin(); i != lfiles.end(); ++i) { cmakefileStream << " \"" - << lg->Convert(*i, cmOutputConverter::START_OUTPUT) + << lg->ConvertToRelativePath( + *i, cmOutputConverter::START_OUTPUT) << "\"\n"; } cmakefileStream << " )\n\n"; @@ -329,10 +332,12 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() cmakefileStream << "# The corresponding makefile is:\n" << "set(CMAKE_MAKEFILE_OUTPUTS\n" << " \"" - << lg->Convert(makefileName, cmOutputConverter::START_OUTPUT) + << lg->ConvertToRelativePath(makefileName, + cmOutputConverter::START_OUTPUT) << "\"\n" << " \"" - << lg->Convert(check, cmOutputConverter::START_OUTPUT) + << lg->ConvertToRelativePath(check, + cmOutputConverter::START_OUTPUT) << "\"\n"; cmakefileStream << " )\n\n"; @@ -345,7 +350,8 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() for (std::vector::const_iterator k = outfiles.begin(); k != outfiles.end(); ++k) { cmakefileStream << " \"" - << lg->Convert(*k, cmOutputConverter::HOME_OUTPUT) + << lg->ConvertToRelativePath( + *k, cmOutputConverter::HOME_OUTPUT) << "\"\n"; } @@ -358,7 +364,8 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() tmpStr += cmake::GetCMakeFilesDirectory(); tmpStr += "/CMakeDirectoryInformation.cmake"; cmakefileStream << " \"" - << lg->Convert(tmpStr, cmOutputConverter::HOME_OUTPUT) + << lg->ConvertToRelativePath( + tmpStr, cmOutputConverter::HOME_OUTPUT) << "\"\n"; } cmakefileStream << " )\n\n"; @@ -519,7 +526,7 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( tname += "/fast"; } cmOutputConverter conv(mf->GetStateSnapshot()); - tname = conv.Convert(tname, cmOutputConverter::HOME_OUTPUT); + tname = conv.ConvertToRelativePath(tname, cmOutputConverter::HOME_OUTPUT); cmSystemTools::ConvertToOutputSlashes(tname); makeCommand.push_back(tname); if (this->Makefiles.empty()) { diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 0a83b3a..67ac230 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -385,7 +385,8 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( if (vcprojName) { cmLocalGenerator* lg = target->GetLocalGenerator(); std::string dir = lg->GetCurrentBinaryDirectory(); - dir = root->Convert(dir.c_str(), cmOutputConverter::START_OUTPUT); + dir = root->ConvertToRelativePath(dir.c_str(), + cmOutputConverter::START_OUTPUT); if (dir == ".") { dir = ""; // msbuild cannot handle ".\" prefix } diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 39d9e97..3c5e333 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -402,7 +402,8 @@ void cmListFileBacktrace::PrintTitle(std::ostream& out) const cmOutputConverter converter(this->Bottom); cmListFileContext lfc = *this->Cur; if (!this->Bottom.GetState()->GetIsInTryCompile()) { - lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME); + lfc.FilePath = + converter.ConvertToRelativePath(lfc.FilePath, cmOutputConverter::HOME); } out << (lfc.Line ? " at " : " in ") << lfc; } @@ -427,7 +428,8 @@ void cmListFileBacktrace::PrintCallStack(std::ostream& out) const } cmListFileContext lfc = *i; if (!this->Bottom.GetState()->GetIsInTryCompile()) { - lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME); + lfc.FilePath = + converter.ConvertToRelativePath(lfc.FilePath, cmOutputConverter::HOME); } out << " " << lfc << "\n"; } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 20a1e21..2fa3f86 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -176,7 +176,7 @@ void cmLocalGenerator::GenerateTestFiles() // TODO: Use add_subdirectory instead? fout << "subdirs("; std::string outP = children[i].GetDirectory().GetCurrentBinary(); - fout << this->Convert(outP, START_OUTPUT); + fout << this->ConvertToRelativePath(outP, START_OUTPUT); fout << ")" << std::endl; } } @@ -2237,7 +2237,8 @@ std::string cmLocalGenerator::ConstructComment( for (std::vector::const_iterator o = ccg.GetOutputs().begin(); o != ccg.GetOutputs().end(); ++o) { comment += sep; - comment += this->Convert(*o, cmOutputConverter::START_OUTPUT); + comment += + this->ConvertToRelativePath(*o, cmOutputConverter::START_OUTPUT); sep = ", "; } return comment; @@ -2505,13 +2506,14 @@ std::string cmLocalGenerator::GetObjectFileNameWithoutTarget( const char* fullPath = source.GetFullPath().c_str(); // Try referencing the source relative to the source tree. - std::string relFromSource = this->Convert(fullPath, START); + std::string relFromSource = this->ConvertToRelativePath(fullPath, START); assert(!relFromSource.empty()); bool relSource = !cmSystemTools::FileIsFullPath(relFromSource.c_str()); bool subSource = relSource && relFromSource[0] != '.'; // Try referencing the source relative to the binary tree. - std::string relFromBinary = this->Convert(fullPath, START_OUTPUT); + std::string relFromBinary = + this->ConvertToRelativePath(fullPath, START_OUTPUT); assert(!relFromBinary.empty()); bool relBinary = !cmSystemTools::FileIsFullPath(relFromBinary.c_str()); bool subBinary = relBinary && relFromBinary[0] != '.'; diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 8c092e7..9e2c920 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -41,7 +41,7 @@ void cmLocalNinjaGenerator::Generate() { // Compute the path to use when referencing the current output // directory from the top output directory. - this->HomeRelativeOutputPath = this->Convert( + this->HomeRelativeOutputPath = this->ConvertToRelativePath( this->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT); if (this->HomeRelativeOutputPath == ".") { this->HomeRelativeOutputPath = ""; diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index cc909f0..0a0089b 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -140,7 +140,7 @@ void cmLocalUnixMakefileGenerator3::ComputeHomeRelativeOutputPath() { // Compute the path to use when referencing the current output // directory from the top output directory. - this->HomeRelativeOutputPath = this->Convert( + this->HomeRelativeOutputPath = this->ConvertToRelativePath( this->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT); if (this->HomeRelativeOutputPath == ".") { this->HomeRelativeOutputPath = ""; @@ -966,7 +966,8 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( // working directory will be the start-output directory. bool had_slash = cmd.find('/') != cmd.npos; if (workingDir.empty()) { - cmd = this->Convert(cmd, cmOutputConverter::START_OUTPUT); + cmd = + this->ConvertToRelativePath(cmd, cmOutputConverter::START_OUTPUT); } bool has_slash = cmd.find('/') != cmd.npos; if (had_slash && !has_slash) { @@ -1851,7 +1852,8 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( for (std::vector::iterator i = includes.begin(); i != includes.end(); ++i) { cmakefileStream << " \"" - << this->Convert(*i, cmOutputConverter::HOME_OUTPUT) + << this->ConvertToRelativePath( + *i, cmOutputConverter::HOME_OUTPUT) << "\"\n"; } cmakefileStream << " )\n"; @@ -1915,7 +1917,8 @@ std::string cmLocalUnixMakefileGenerator3::GetRecursiveMakeCall( // Add the target. if (!tgt.empty()) { // The make target is always relative to the top of the build tree. - std::string tgt2 = this->Convert(tgt, cmOutputConverter::HOME_OUTPUT); + std::string tgt2 = + this->ConvertToRelativePath(tgt, cmOutputConverter::HOME_OUTPUT); // The target may have been written with windows paths. cmSystemTools::ConvertToOutputSlashes(tgt2); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 2d53669..b34cd6e 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -312,8 +312,10 @@ void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()( output += "/"; output += cmSystemTools::GetFilenameName(input); this->Generator->CleanFiles.push_back( - this->Generator->Convert(output, cmOutputConverter::START_OUTPUT)); - output = this->Generator->Convert(output, cmOutputConverter::HOME_OUTPUT); + this->Generator->LocalGenerator->ConvertToRelativePath( + output, cmOutputConverter::START_OUTPUT)); + output = this->Generator->LocalGenerator->ConvertToRelativePath( + output, cmOutputConverter::HOME_OUTPUT); // Create a rule to copy the content into the bundle. std::vector depends; @@ -1171,7 +1173,8 @@ void cmMakefileTargetGenerator::WriteObjectsVariable( for (std::vector::const_iterator i = this->ExternalObjects.begin(); i != this->ExternalObjects.end(); ++i) { - object = this->Convert(*i, cmOutputConverter::START_OUTPUT); + object = this->LocalGenerator->ConvertToRelativePath( + *i, cmOutputConverter::START_OUTPUT); *this->BuildFileStream << " " << lineContinue << "\n" << this->Makefile->GetSafeDefinition( "CMAKE_OBJECT_NAME"); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index ed04d2f..d5274cd 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -602,7 +602,8 @@ void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const it != this->TLLCommands.end(); ++it) { if (it->first == sig) { cmListFileContext lfc = it->second; - lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME); + lfc.FilePath = + converter.ConvertToRelativePath(lfc.FilePath, cmOutputConverter::HOME); s << " * " << lfc << std::endl; } } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d34a12ad76c1566ecc4fe02ed25670b0d679540f commit d34a12ad76c1566ecc4fe02ed25670b0d679540f Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:56 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:37 2016 +0200 Convert: Replace UNCHANGED conversions with new API call diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index c450b91..cc909f0 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1076,8 +1076,8 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand( fout << "file(REMOVE_RECURSE\n"; for (std::vector::const_iterator f = files.begin(); f != files.end(); ++f) { - std::string fc = this->Convert(*f, cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + std::string fc = + this->ConvertToRelativePath(*f, cmOutputConverter::START_OUTPUT); fout << " " << cmOutputConverter::EscapeForCMake(fc) << "\n"; } fout << ")\n"; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 497defb..1beaa87 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -788,8 +788,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( target->GetProperty("Fortran_MODULE_DIRECTORY"); std::string modDir; if (target_mod_dir) { - modDir = this->Convert(target_mod_dir, cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + modDir = this->ConvertToRelativePath(target_mod_dir, + cmOutputConverter::START_OUTPUT); } else { modDir = "."; } @@ -1300,9 +1300,8 @@ void cmLocalVisualStudio7GeneratorInternals::OutputLibraries( cmLocalVisualStudio7Generator* lg = this->LocalGenerator; for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) { if (l->IsPath) { - std::string rel = - lg->Convert(l->Value.c_str(), cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + std::string rel = lg->ConvertToRelativePath( + l->Value.c_str(), cmOutputConverter::START_OUTPUT); fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " "; } else if (!l->Target || l->Target->GetType() != cmState::INTERFACE_LIBRARY) { @@ -1322,8 +1321,8 @@ void cmLocalVisualStudio7GeneratorInternals::OutputObjects( const char* sep = isep ? isep : ""; for (std::vector::const_iterator oi = objs.begin(); oi != objs.end(); ++oi) { - std::string rel = lg->Convert(oi->c_str(), cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + std::string rel = + lg->ConvertToRelativePath(oi->c_str(), cmOutputConverter::START_OUTPUT); fout << sep << lg->ConvertToXMLOutputPath(rel.c_str()); sep = " "; } @@ -1346,9 +1345,8 @@ void cmLocalVisualStudio7Generator::OutputLibraryDirectories( // Switch to a relative path specification if it is shorter. if (cmSystemTools::FileIsFullPath(dir.c_str())) { - std::string rel = - this->Convert(dir.c_str(), cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + std::string rel = this->ConvertToRelativePath( + dir.c_str(), cmOutputConverter::START_OUTPUT); if (rel.size() < dir.size()) { dir = rel; } diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index a14df79..66e1ca2 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -218,40 +218,34 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Construct a list of files associated with this executable that // may need to be cleaned. std::vector exeCleanFiles; - exeCleanFiles.push_back(this->Convert(targetFullPath, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPath, cmOutputConverter::START_OUTPUT)); #ifdef _WIN32 // There may be a manifest file for this target. Add it to the // clean set just in case. - exeCleanFiles.push_back(this->Convert((targetFullPath + ".manifest").c_str(), - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + (targetFullPath + ".manifest").c_str(), cmOutputConverter::START_OUTPUT)); #endif if (targetNameReal != targetName) { - exeCleanFiles.push_back(this->Convert(targetFullPathReal, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathReal, cmOutputConverter::START_OUTPUT)); } if (!targetNameImport.empty()) { - exeCleanFiles.push_back(this->Convert(targetFullPathImport, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathImport, cmOutputConverter::START_OUTPUT)); std::string implib; if (this->GeneratorTarget->GetImplibGNUtoMS(targetFullPathImport, implib)) { - exeCleanFiles.push_back(this->Convert(implib, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + implib, cmOutputConverter::START_OUTPUT)); } } // List the PDB for cleaning only when the whole target is // cleaned. We do not want to delete the .pdb file just before // linking the target. - this->CleanFiles.push_back(this->Convert(targetFullPathPDB, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + this->CleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathPDB, cmOutputConverter::START_OUTPUT)); // Add the pre-build and pre-link rules building but not when relinking. if (!relink) { diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index c8ee05f..c31c469 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -367,46 +367,40 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // Clean files associated with this library. std::vector libCleanFiles; - libCleanFiles.push_back(this->Convert(targetFullPath, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPath, cmOutputConverter::START_OUTPUT)); if (targetNameReal != targetName) { - libCleanFiles.push_back(this->Convert(targetFullPathReal, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathReal, cmOutputConverter::START_OUTPUT)); } if (targetNameSO != targetName && targetNameSO != targetNameReal) { - libCleanFiles.push_back(this->Convert(targetFullPathSO, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathSO, cmOutputConverter::START_OUTPUT)); } if (!targetNameImport.empty()) { - libCleanFiles.push_back(this->Convert(targetFullPathImport, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathImport, cmOutputConverter::START_OUTPUT)); std::string implib; if (this->GeneratorTarget->GetImplibGNUtoMS(targetFullPathImport, implib)) { - libCleanFiles.push_back(this->Convert(implib, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + implib, cmOutputConverter::START_OUTPUT)); } } // List the PDB for cleaning only when the whole target is // cleaned. We do not want to delete the .pdb file just before // linking the target. - this->CleanFiles.push_back(this->Convert(targetFullPathPDB, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + this->CleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathPDB, cmOutputConverter::START_OUTPUT)); #ifdef _WIN32 // There may be a manifest file for this target. Add it to the // clean set just in case. if (this->GeneratorTarget->GetType() != cmState::STATIC_LIBRARY) { - libCleanFiles.push_back(this->Convert( - (targetFullPath + ".manifest").c_str(), cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + (targetFullPath + ".manifest").c_str(), + cmOutputConverter::START_OUTPUT)); } #endif diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index dd4333d..2d53669 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -172,8 +172,8 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() const std::vector& outputs = ccg.GetOutputs(); for (std::vector::const_iterator o = outputs.begin(); o != outputs.end(); ++o) { - this->CleanFiles.push_back(this->Convert( - *o, cmOutputConverter::START_OUTPUT, cmOutputConverter::UNCHANGED)); + this->CleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + *o, cmOutputConverter::START_OUTPUT)); } } } @@ -1258,9 +1258,8 @@ void cmMakefileTargetGenerator::WriteTargetDriverRule( this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget); std::string buildTargetRuleName = dir; buildTargetRuleName += relink ? "/preinstall" : "/build"; - buildTargetRuleName = - this->Convert(buildTargetRuleName, cmOutputConverter::HOME_OUTPUT, - cmOutputConverter::UNCHANGED); + buildTargetRuleName = this->LocalGenerator->ConvertToRelativePath( + buildTargetRuleName, cmOutputConverter::HOME_OUTPUT); // Build the list of target outputs to drive. std::vector depends; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 1b1d04b..216de03 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2416,9 +2416,8 @@ void cmVisualStudio10TargetGenerator::AddLibraries( ItemVector libs = cli.GetItems(); for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) { if (l->IsPath) { - std::string path = this->LocalGenerator->Convert( - l->Value.c_str(), cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + std::string path = this->LocalGenerator->ConvertToRelativePath( + l->Value.c_str(), cmOutputConverter::START_OUTPUT); this->ConvertToWindowsSlash(path); libVec.push_back(path); } else if (!l->Target || https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1e3dba183f2b00b25ef9a8ce3b02b8ee3f0fc256 commit 1e3dba183f2b00b25ef9a8ce3b02b8ee3f0fc256 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:56 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:37 2016 +0200 Convert: Extract ConvertToRelativePath from Convert() Convert() does some kind of relative conversion, followed by a conversion to 'output format'. Make it possible to do the former without the latter. diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 80fa4bf..176c9a0 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -46,11 +46,9 @@ std::string cmOutputConverter::ConvertToOutputForExisting( return this->ConvertToOutputFormat(remote, format); } -std::string cmOutputConverter::Convert(const std::string& source, - RelativeRoot relative, - OutputFormat output) const +std::string cmOutputConverter::ConvertToRelativePath( + const std::string& source, RelativeRoot relative) const { - // Convert the path to a relative path. std::string result = source; switch (relative) { @@ -76,6 +74,15 @@ std::string cmOutputConverter::Convert(const std::string& source, result = cmSystemTools::CollapseFullPath(result); break; } + return result; +} + +std::string cmOutputConverter::Convert(const std::string& source, + RelativeRoot relative, + OutputFormat output) const +{ + // Convert the path to a relative path. + std::string result = this->ConvertToRelativePath(source, relative); return this->ConvertToOutputFormat(result, output); } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 0f4884e..71bb086 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -56,6 +56,8 @@ public: OutputFormat output) const; std::string Convert(const std::string& remote, RelativeRoot local, OutputFormat output = UNCHANGED) const; + std::string ConvertToRelativePath(const std::string& remote, + RelativeRoot local) const; std::string ConvertDirectorySeparatorsForShell( const std::string& source) const; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=fa8df52d0e03b45cb8a46f2c6e9647cee33fd60a commit fa8df52d0e03b45cb8a46f2c6e9647cee33fd60a Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:55 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:37 2016 +0200 Convert: Replace FULL conversions with equivalent diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 7748883..c450b91 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1067,8 +1067,7 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand( cleanfile += filename; } cleanfile += ".cmake"; - std::string cleanfilePath = - this->Convert(cleanfile, cmOutputConverter::FULL); + std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile); cmsys::ofstream fout(cleanfilePath.c_str()); if (!fout) { cmSystemTools::Error("Could not create ", cleanfilePath.c_str()); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 7747aa7..dd4333d 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -393,9 +393,9 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( std::string objFullPath = this->LocalGenerator->GetCurrentBinaryDirectory(); objFullPath += "/"; objFullPath += obj; - objFullPath = this->Convert(objFullPath, cmOutputConverter::FULL); + objFullPath = cmSystemTools::CollapseFullPath(objFullPath); std::string srcFullPath = - this->Convert(source.GetFullPath(), cmOutputConverter::FULL); + cmSystemTools::CollapseFullPath(source.GetFullPath()); this->LocalGenerator->AddImplicitDepends( this->GeneratorTarget, lang, objFullPath.c_str(), srcFullPath.c_str()); } @@ -584,9 +584,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( lang_can_export_cmds && compileCommands.size() == 1) { std::string compileCommand = compileCommands[0]; this->LocalGenerator->ExpandRuleVariables(compileCommand, vars); - std::string workingDirectory = this->LocalGenerator->Convert( - this->LocalGenerator->GetCurrentBinaryDirectory(), - cmOutputConverter::FULL); + std::string workingDirectory = cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetCurrentBinaryDirectory()); compileCommand.replace(compileCommand.find(langFlags), langFlags.size(), this->GetFlags(lang)); std::string langDefines = std::string("$(") + lang + "_DEFINES)"; @@ -1115,10 +1114,8 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile( for (cmCustomCommand::ImplicitDependsList::const_iterator idi = ccg.GetCC().GetImplicitDepends().begin(); idi != ccg.GetCC().GetImplicitDepends().end(); ++idi) { - std::string objFullPath = - this->Convert(outputs[0], cmOutputConverter::FULL); - std::string srcFullPath = - this->Convert(idi->second, cmOutputConverter::FULL); + std::string objFullPath = cmSystemTools::CollapseFullPath(outputs[0]); + std::string srcFullPath = cmSystemTools::CollapseFullPath(idi->second); this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, idi->first, objFullPath.c_str(), srcFullPath.c_str()); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0a47e1d9ac4ffac21874daae332422e125e3aa41 commit 0a47e1d9ac4ffac21874daae332422e125e3aa41 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:55 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:37 2016 +0200 VS: Replace FULL/UNCHANGED conversion with equivalent diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index e72abe9..497defb 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -278,8 +278,8 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() cmCustomCommandLines commandLines; commandLines.push_back(commandLine); const char* no_working_directory = 0; - std::string fullpathStampName = this->Convert( - stampName.c_str(), cmOutputConverter::FULL, cmOutputConverter::UNCHANGED); + std::string fullpathStampName = + cmSystemTools::CollapseFullPath(stampName.c_str()); this->Makefile->AddCustomCommandToOutput( fullpathStampName.c_str(), listFiles, makefileIn.c_str(), commandLines, comment.c_str(), no_working_directory, true); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1bf869716b00f925b6a315737d8c5553b2d04a26 commit 1bf869716b00f925b6a315737d8c5553b2d04a26 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:55 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:37 2016 +0200 Convert: Remove NONE conversion It is no longer used. diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 98872d6..80fa4bf 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -75,8 +75,6 @@ std::string cmOutputConverter::Convert(const std::string& source, case FULL: result = cmSystemTools::CollapseFullPath(result); break; - case NONE: - break; } return this->ConvertToOutputFormat(result, output); } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index ff06ab6..0f4884e 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -38,7 +38,6 @@ public: */ enum RelativeRoot { - NONE, FULL, HOME, START, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8be68b73457470bf886b9d633142c8d3e91f1d80 commit 8be68b73457470bf886b9d633142c8d3e91f1d80 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:55 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:36 2016 +0200 Convert: Replace uses of Convert(NONE) These are equivalent to ConvertToOutputFormat. diff --git a/Source/cmLocalCommonGenerator.cxx b/Source/cmLocalCommonGenerator.cxx index 5502296..1383421 100644 --- a/Source/cmLocalCommonGenerator.cxx +++ b/Source/cmLocalCommonGenerator.cxx @@ -74,8 +74,7 @@ std::string cmLocalCommonGenerator::GetTargetFortranFlags( for (std::vector::const_iterator idi = includes.begin(); idi != includes.end(); ++idi) { std::string flg = modpath_flag; - flg += - this->Convert(*idi, cmOutputConverter::NONE, cmOutputConverter::SHELL); + flg += this->ConvertToOutputFormat(*idi, cmOutputConverter::SHELL); this->AppendFlags(flags, flg); } } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index d8f6bdf..20a1e21 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1393,7 +1393,7 @@ std::string cmLocalGenerator::ConvertToLinkReference(std::string const& lib, sp += lib.substr(pos); // Convert to an output path. - return this->Convert(sp.c_str(), NONE, format); + return this->ConvertToOutputFormat(sp.c_str(), format); } } } @@ -1489,7 +1489,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, for (std::vector::const_iterator fdi = fwDirs.begin(); fdi != fwDirs.end(); ++fdi) { frameworkPath += fwSearchFlag; - frameworkPath += this->Convert(*fdi, NONE, shellFormat); + frameworkPath += this->ConvertToOutputFormat(*fdi, shellFormat); frameworkPath += " "; } } @@ -1535,7 +1535,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, for (std::vector::iterator ri = runtimeDirs.begin(); ri != runtimeDirs.end(); ++ri) { rpath += cli.GetRuntimeFlag(); - rpath += this->Convert(*ri, NONE, shellFormat); + rpath += this->ConvertToOutputFormat(*ri, shellFormat); rpath += " "; } fout << rpath; @@ -1605,7 +1605,7 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags, flags += " "; flags += sysrootFlag; flags += " "; - flags += this->Convert(sysroot, NONE, SHELL); + flags += this->ConvertToOutputFormat(sysroot, SHELL); } if (deploymentTargetFlag && *deploymentTargetFlag && deploymentTarget && diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 58c336d..8c092e7 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -490,8 +490,8 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher( output = this->Convert(outputs[0], cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); } else { - output = this->Convert(outputs[0], cmOutputConverter::NONE, - cmOutputConverter::SHELL); + output = + this->ConvertToOutputFormat(outputs[0], cmOutputConverter::SHELL); } } vars.Output = output.c_str(); diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index d36e592..7748883 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -602,8 +602,7 @@ std::string cmLocalUnixMakefileGenerator3::MaybeConvertWacomShellCommand( // lines with shell redirection operators. std::string scmd; if (cmSystemTools::GetShortPath(cmd, scmd)) { - return this->Convert(scmd, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + return this->ConvertToOutputFormat(scmd, cmOutputConverter::SHELL); } } return std::string(); @@ -790,8 +789,8 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom( std::string runRule = "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; runRule += " --check-build-system "; - runRule += this->Convert(cmakefileName, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + runRule += + this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); runRule += " 0"; std::vector no_depends; @@ -995,8 +994,8 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( cmOutputConverter::SHELL); } else { - output = this->Convert(outputs[0], cmOutputConverter::NONE, - cmOutputConverter::SHELL); + output = this->ConvertToOutputFormat(outputs[0], + cmOutputConverter::SHELL); } } vars.Output = output.c_str(); @@ -1009,8 +1008,8 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( std::string shellCommand = this->MaybeConvertWacomShellCommand(cmd); if (shellCommand.empty()) { - shellCommand = this->Convert(cmd, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + shellCommand = + this->ConvertToOutputFormat(cmd, cmOutputConverter::SHELL); } cmd = launcher + shellCommand; @@ -1681,8 +1680,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( std::string runRule = "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; runRule += " --check-build-system "; - runRule += this->Convert(cmakefileName, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + runRule += + this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); runRule += " 1"; commands.push_back(runRule); this->CreateCDCommand(commands, this->GetBinaryDirectory(), @@ -1895,8 +1894,7 @@ std::string cmLocalUnixMakefileGenerator3::GetRecursiveMakeCall( // Call make on the given file. std::string cmd; cmd += "$(MAKE) -f "; - cmd += - this->Convert(makefile, cmOutputConverter::NONE, cmOutputConverter::SHELL); + cmd += this->ConvertToOutputFormat(makefile, cmOutputConverter::SHELL); cmd += " "; cmGlobalUnixMakefileGenerator3* gg = diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index ca006b7..d1cefe3 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -205,7 +205,7 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( if (workingDirectory.empty()) { script += this->Convert(cmd.c_str(), START_OUTPUT, SHELL); } else { - script += this->Convert(cmd.c_str(), NONE, SHELL); + script += this->ConvertToOutputFormat(cmd.c_str(), SHELL); } ccg.AppendArguments(c, script); diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 74bfedc..a14df79 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -135,8 +135,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) std::string targetFullPathReal = outpath + targetNameReal; std::string targetFullPathPDB = pdbOutputPath + targetNamePDB; std::string targetFullPathImport = outpathImp + targetNameImport; - std::string targetOutPathPDB = this->Convert( - targetFullPathPDB, cmOutputConverter::NONE, cmOutputConverter::SHELL); + std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( + targetFullPathPDB, cmOutputConverter::SHELL); // Convert to the output path to use in constructing commands. std::string targetOutPath = this->Convert( targetFullPath, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); @@ -357,9 +357,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) vars.Manifests = manifests.c_str(); if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE")) { - std::string cmakeCommand = - this->Convert(cmSystemTools::GetCMakeCommand(), cmLocalGenerator::NONE, - cmLocalGenerator::SHELL); + std::string cmakeCommand = this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); cmakeCommand += " -E __run_iwyu --lwyu="; cmakeCommand += targetOutPathReal; real_link_commands.push_back(cmakeCommand); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 6727bd0..c8ee05f 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -310,8 +310,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // Construct the output path version of the names for use in command // arguments. - std::string targetOutPathPDB = this->Convert( - targetFullPathPDB, cmOutputConverter::NONE, cmOutputConverter::SHELL); + std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( + targetFullPathPDB, cmOutputConverter::SHELL); std::string targetOutPath = this->Convert( targetFullPath, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); std::string targetOutPathSO = @@ -572,8 +572,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( vars.TargetInstallNameDir = ""; } else { // Convert to a path for the native build tool. - install_name_dir = this->LocalGenerator->Convert( - install_name_dir, cmOutputConverter::NONE, cmOutputConverter::SHELL); + install_name_dir = this->LocalGenerator->ConvertToOutputFormat( + install_name_dir, cmOutputConverter::SHELL); vars.TargetInstallNameDir = install_name_dir.c_str(); } } @@ -640,9 +640,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( cmSystemTools::ExpandListArgument(linkRule, real_link_commands); if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE") && (this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY)) { - std::string cmakeCommand = - this->Convert(cmSystemTools::GetCMakeCommand(), - cmLocalGenerator::NONE, cmLocalGenerator::SHELL); + std::string cmakeCommand = this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); cmakeCommand += " -E __run_iwyu --lwyu="; cmakeCommand += targetOutPathReal; real_link_commands.push_back(cmakeCommand); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 5bba29c..7747aa7 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -324,11 +324,11 @@ void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()( this->Generator->LocalGenerator->AppendEcho( commands, copyEcho, cmLocalUnixMakefileGenerator3::EchoBuild); std::string copyCommand = "$(CMAKE_COMMAND) -E copy "; - copyCommand += this->Generator->Convert(input, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + copyCommand += this->Generator->LocalGenerator->ConvertToOutputFormat( + input, cmOutputConverter::SHELL); copyCommand += " "; - copyCommand += this->Generator->Convert(output, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + copyCommand += this->Generator->LocalGenerator->ConvertToOutputFormat( + output, cmOutputConverter::SHELL); commands.push_back(copyCommand); this->Generator->LocalGenerator->WriteMakeRule( *this->Generator->BuildFileStream, CM_NULLPTR, output, depends, commands, @@ -464,8 +464,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( } // Get the output paths for source and object files. - std::string sourceFile = this->Convert( - source.GetFullPath(), cmOutputConverter::NONE, cmOutputConverter::SHELL); + std::string sourceFile = this->LocalGenerator->ConvertToOutputFormat( + source.GetFullPath(), cmOutputConverter::SHELL); // Construct the build message. std::vector no_commands; @@ -516,8 +516,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( targetOutPathReal = this->Convert(targetFullPathReal, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); - targetOutPathPDB = this->Convert( - targetFullPathPDB, cmOutputConverter::NONE, cmOutputConverter::SHELL); + targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( + targetFullPathPDB, cmOutputConverter::SHELL); targetOutPathCompilePDB = this->Convert(targetFullPathCompilePDB, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); @@ -539,7 +539,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( vars.TargetCompilePDB = targetOutPathCompilePDB.c_str(); vars.Source = sourceFile.c_str(); std::string shellObj = - this->Convert(obj, cmOutputConverter::NONE, cmOutputConverter::SHELL); + this->LocalGenerator->ConvertToOutputFormat(obj, cmOutputConverter::SHELL); vars.Object = shellObj.c_str(); std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); objectDir = this->Convert(objectDir, cmOutputConverter::START_OUTPUT, @@ -699,8 +699,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( std::vector preprocessCommands; cmSystemTools::ExpandListArgument(preprocessRule, preprocessCommands); - std::string shellObjI = this->Convert(objI, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + std::string shellObjI = this->LocalGenerator->ConvertToOutputFormat( + objI, cmOutputConverter::SHELL); vars.PreprocessedSource = shellObjI.c_str(); // Expand placeholders in the commands. @@ -746,8 +746,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( std::vector assemblyCommands; cmSystemTools::ExpandListArgument(assemblyRule, assemblyCommands); - std::string shellObjS = this->Convert(objS, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + std::string shellObjS = this->LocalGenerator->ConvertToOutputFormat( + objS, cmOutputConverter::SHELL); vars.AssemblySource = shellObjS.c_str(); // Expand placeholders in the commands. @@ -1576,8 +1576,8 @@ void cmMakefileTargetGenerator::CreateLinkLibs( // Reference the response file. linkLibs = responseFlag; - linkLibs += this->Convert(link_rsp, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + linkLibs += this->LocalGenerator->ConvertToOutputFormat( + link_rsp, cmOutputConverter::SHELL); } } @@ -1625,8 +1625,8 @@ void cmMakefileTargetGenerator::CreateObjectLists( // Reference the response file. buildObjs += responseFlag; - buildObjs += this->Convert(objects_rsp, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + buildObjs += this->LocalGenerator->ConvertToOutputFormat( + objects_rsp, cmOutputConverter::SHELL); } } else if (useLinkScript) { if (!useArchiveRules) { @@ -1683,8 +1683,8 @@ void cmMakefileTargetGenerator::GenDefFile( name_of_def_file += std::string("/") + this->GeneratorTarget->GetName(); name_of_def_file += ".def"; std::string cmd = cmSystemTools::GetCMakeCommand(); - cmd = - this->Convert(cmd, cmOutputConverter::NONE, cmOutputConverter::SHELL); + cmd = this->LocalGenerator->ConvertToOutputFormat( + cmd, cmOutputConverter::SHELL); cmd += " -E __create_def "; cmd += this->Convert(name_of_def_file, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index d0db133..335b552 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -543,8 +543,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() std::string install_dir = this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName); if (!install_dir.empty()) { - vars["INSTALLNAME_DIR"] = localGen.Convert( - install_dir, cmOutputConverter::NONE, cmOutputConverter::SHELL); + vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat( + install_dir, cmOutputConverter::SHELL); } } } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d7bc7c89771a582fb390d2f8c922515acddaa2b5 commit d7bc7c89771a582fb390d2f8c922515acddaa2b5 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:54 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:21:24 2016 +0200 VS: Replace variable with an if() diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index bdb1c2b..ca006b7 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -127,7 +127,6 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( { bool useLocal = this->CustomCommandUseLocal(); std::string workingDirectory = ccg.GetWorkingDirectory(); - RelativeRoot relativeRoot = workingDirectory.empty() ? START_OUTPUT : NONE; // Avoid leading or trailing newlines. std::string newline = ""; @@ -203,7 +202,11 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( } } - script += this->Convert(cmd.c_str(), relativeRoot, SHELL); + if (workingDirectory.empty()) { + script += this->Convert(cmd.c_str(), START_OUTPUT, SHELL); + } else { + script += this->Convert(cmd.c_str(), NONE, SHELL); + } ccg.AppendArguments(c, script); // After each custom command, check for an error result. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5761b1dd875d857991a0827e65b7128b73d7f8f7 commit 5761b1dd875d857991a0827e65b7128b73d7f8f7 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:54 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:21:24 2016 +0200 Makefiles: Replace ternaries with if()s diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 46d7e18..58c336d 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -486,12 +486,13 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher( std::string output; const std::vector& outputs = ccg.GetOutputs(); if (!outputs.empty()) { - cmOutputConverter::RelativeRoot relative_root = - ccg.GetWorkingDirectory().empty() ? cmOutputConverter::START_OUTPUT - : cmOutputConverter::NONE; - - output = - this->Convert(outputs[0], relative_root, cmOutputConverter::SHELL); + if (ccg.GetWorkingDirectory().empty()) { + output = this->Convert(outputs[0], cmOutputConverter::START_OUTPUT, + cmOutputConverter::SHELL); + } else { + output = this->Convert(outputs[0], cmOutputConverter::NONE, + cmOutputConverter::SHELL); + } } vars.Output = output.c_str(); diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 6dc0b7e..d36e592 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -990,10 +990,14 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( std::string output; const std::vector& outputs = ccg.GetOutputs(); if (!outputs.empty()) { - output = this->Convert(outputs[0], workingDir.empty() - ? cmOutputConverter::START_OUTPUT - : cmOutputConverter::NONE, - cmOutputConverter::SHELL); + if (workingDir.empty()) { + output = this->Convert(outputs[0], cmOutputConverter::START_OUTPUT, + cmOutputConverter::SHELL); + + } else { + output = this->Convert(outputs[0], cmOutputConverter::NONE, + cmOutputConverter::SHELL); + } } vars.Output = output.c_str(); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=16dad45d29f6fc8a84c2ff5ae2ca7c098b532c9c commit 16dad45d29f6fc8a84c2ff5ae2ca7c098b532c9c Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:54 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:21:24 2016 +0200 Makefiles: Inline MakeLauncher into only caller diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index b7673db..6dc0b7e 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -976,9 +976,33 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( // without the current directory being in the search path. cmd = "./" + cmd; } - std::string launcher = this->MakeLauncher( - ccg, target, workingDir.empty() ? cmOutputConverter::START_OUTPUT - : cmOutputConverter::NONE); + + std::string launcher; + // Short-circuit if there is no launcher. + const char* prop = "RULE_LAUNCH_CUSTOM"; + const char* val = this->GetRuleLauncher(target, prop); + if (val && *val) { + // Expand rules in the empty string. It may insert the launcher and + // perform replacements. + RuleVariables vars; + vars.RuleLauncher = prop; + vars.CMTarget = target; + std::string output; + const std::vector& outputs = ccg.GetOutputs(); + if (!outputs.empty()) { + output = this->Convert(outputs[0], workingDir.empty() + ? cmOutputConverter::START_OUTPUT + : cmOutputConverter::NONE, + cmOutputConverter::SHELL); + } + vars.Output = output.c_str(); + + this->ExpandRuleVariables(launcher, vars); + if (!launcher.empty()) { + launcher += " "; + } + } + std::string shellCommand = this->MaybeConvertWacomShellCommand(cmd); if (shellCommand.empty()) { shellCommand = this->Convert(cmd, cmOutputConverter::NONE, @@ -1027,35 +1051,6 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( commands.insert(commands.end(), commands1.begin(), commands1.end()); } -std::string cmLocalUnixMakefileGenerator3::MakeLauncher( - cmCustomCommandGenerator const& ccg, cmGeneratorTarget* target, - cmOutputConverter::RelativeRoot relative) -{ - std::string launcher; - // Short-circuit if there is no launcher. - const char* prop = "RULE_LAUNCH_CUSTOM"; - const char* val = this->GetRuleLauncher(target, prop); - if (val && *val) { - // Expand rules in the empty string. It may insert the launcher and - // perform replacements. - RuleVariables vars; - vars.RuleLauncher = prop; - vars.CMTarget = target; - std::string output; - const std::vector& outputs = ccg.GetOutputs(); - if (!outputs.empty()) { - output = this->Convert(outputs[0], relative, cmOutputConverter::SHELL); - } - vars.Output = output.c_str(); - - this->ExpandRuleVariables(launcher, vars); - if (!launcher.empty()) { - launcher += " "; - } - } - return launcher; -} - void cmLocalUnixMakefileGenerator3::AppendCleanCommand( std::vector& commands, const std::vector& files, cmGeneratorTarget* target, const char* filename) diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index 9541f65..bc7566e 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -251,9 +251,6 @@ protected: private: std::string MaybeConvertWacomShellCommand(std::string const& cmd); - std::string MakeLauncher(cmCustomCommandGenerator const& ccg, - cmGeneratorTarget* target, - cmOutputConverter::RelativeRoot relative); void ComputeObjectFilenames( std::map& mapping, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e80e6644bb7f4eaf681390b5071a01856d6545d4 commit e80e6644bb7f4eaf681390b5071a01856d6545d4 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:54 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:21:24 2016 +0200 Makefiles: Simplify MakeLauncher return value Bonus NRVO. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 5e890d1..b7673db 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1031,6 +1031,7 @@ std::string cmLocalUnixMakefileGenerator3::MakeLauncher( cmCustomCommandGenerator const& ccg, cmGeneratorTarget* target, cmOutputConverter::RelativeRoot relative) { + std::string launcher; // Short-circuit if there is no launcher. const char* prop = "RULE_LAUNCH_CUSTOM"; const char* val = this->GetRuleLauncher(target, prop); @@ -1047,14 +1048,12 @@ std::string cmLocalUnixMakefileGenerator3::MakeLauncher( } vars.Output = output.c_str(); - std::string launcher; this->ExpandRuleVariables(launcher, vars); if (!launcher.empty()) { launcher += " "; } - return launcher; } - return ""; + return launcher; } void cmLocalUnixMakefileGenerator3::AppendCleanCommand( https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ab07619914e3857c213d733c8c46a1a439a85ed1 commit ab07619914e3857c213d733c8c46a1a439a85ed1 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:54 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:21:23 2016 +0200 Makefiles: Invert logic in MakeLauncher Make it easier to inline into the caller. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 8cf0708..5e890d1 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1034,28 +1034,27 @@ std::string cmLocalUnixMakefileGenerator3::MakeLauncher( // Short-circuit if there is no launcher. const char* prop = "RULE_LAUNCH_CUSTOM"; const char* val = this->GetRuleLauncher(target, prop); - if (!(val && *val)) { - return ""; - } - - // Expand rules in the empty string. It may insert the launcher and - // perform replacements. - RuleVariables vars; - vars.RuleLauncher = prop; - vars.CMTarget = target; - std::string output; - const std::vector& outputs = ccg.GetOutputs(); - if (!outputs.empty()) { - output = this->Convert(outputs[0], relative, cmOutputConverter::SHELL); - } - vars.Output = output.c_str(); + if (val && *val) { + // Expand rules in the empty string. It may insert the launcher and + // perform replacements. + RuleVariables vars; + vars.RuleLauncher = prop; + vars.CMTarget = target; + std::string output; + const std::vector& outputs = ccg.GetOutputs(); + if (!outputs.empty()) { + output = this->Convert(outputs[0], relative, cmOutputConverter::SHELL); + } + vars.Output = output.c_str(); - std::string launcher; - this->ExpandRuleVariables(launcher, vars); - if (!launcher.empty()) { - launcher += " "; + std::string launcher; + this->ExpandRuleVariables(launcher, vars); + if (!launcher.empty()) { + launcher += " "; + } + return launcher; } - return launcher; + return ""; } void cmLocalUnixMakefileGenerator3::AppendCleanCommand( https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=85997982e51177c966c691dcd660b133b74f6229 commit 85997982e51177c966c691dcd660b133b74f6229 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:53 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:21:14 2016 +0200 Makefiles: Remove useless use of Convert Convert with NONE and UNCHANGED is a no-op. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 2ef9a39..8cf0708 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -835,8 +835,7 @@ std::string cmLocalUnixMakefileGenerator3::GetRelativeTargetDirectory( { std::string dir = this->HomeRelativeOutputPath; dir += this->GetTargetDirectory(target); - return this->Convert(dir, cmOutputConverter::NONE, - cmOutputConverter::UNCHANGED); + return dir; } void cmLocalUnixMakefileGenerator3::AppendFlags(std::string& flags, ----------------------------------------------------------------------- Summary of changes: Source/cmCommonTargetGenerator.h | 6 +- Source/cmDependsC.cxx | 4 +- Source/cmDependsFortran.cxx | 10 +- Source/cmExtraEclipseCDT4Generator.cxx | 4 +- Source/cmGlobalGenerator.cxx | 4 +- Source/cmGlobalNinjaGenerator.cxx | 6 +- Source/cmGlobalUnixMakefileGenerator3.cxx | 31 ++++-- Source/cmGlobalVisualStudio7Generator.cxx | 3 +- Source/cmListFileCache.cxx | 6 +- Source/cmLocalCommonGenerator.cxx | 3 +- Source/cmLocalGenerator.cxx | 25 +++-- Source/cmLocalNinjaGenerator.cxx | 23 ++-- Source/cmLocalUnixMakefileGenerator3.cxx | 134 ++++++++++++------------ Source/cmLocalUnixMakefileGenerator3.h | 3 - Source/cmLocalVisualStudio7Generator.cxx | 26 +++-- Source/cmLocalVisualStudioGenerator.cxx | 10 +- Source/cmMakefileExecutableTargetGenerator.cxx | 39 +++---- Source/cmMakefileLibraryTargetGenerator.cxx | 49 ++++----- Source/cmMakefileTargetGenerator.cxx | 107 ++++++++++--------- Source/cmNinjaNormalTargetGenerator.cxx | 4 +- Source/cmOutputConverter.cxx | 30 +++--- Source/cmOutputConverter.h | 7 +- Source/cmTarget.cxx | 3 +- Source/cmVisualStudio10TargetGenerator.cxx | 5 +- 24 files changed, 277 insertions(+), 265 deletions(-) hooks/post-receive -- CMake From steveire at gmail.com Sat Aug 27 09:41:09 2016 From: steveire at gmail.com (Stephen Kelly) Date: Sat, 27 Aug 2016 09:41:09 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1566-g32389a1 Message-ID: <20160827134109.D5F32F2EAA@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 32389a10550df33224522978f5b9d6794c628d55 (commit) via 9040d96d3dad86d081f76f957e9dfc54b7379406 (commit) from 799348a2d38e6237561168184fcab801262ffe3a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=32389a10550df33224522978f5b9d6794c628d55 commit 32389a10550df33224522978f5b9d6794c628d55 Merge: 799348a 9040d96 Author: Stephen Kelly AuthorDate: Sat Aug 27 09:41:09 2016 -0400 Commit: CMake Topic Stage CommitDate: Sat Aug 27 09:41:09 2016 -0400 Merge topic 'cleanup-Convert' into next 9040d96d format code https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9040d96d3dad86d081f76f957e9dfc54b7379406 commit 9040d96d3dad86d081f76f957e9dfc54b7379406 Author: Stephen Kelly AuthorDate: Sat Aug 27 15:40:44 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:40:47 2016 +0200 format code diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 660483e..7fa35b8 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -665,14 +665,16 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( makefileStream << "# The top-level source directory on which CMake was run.\n" << "CMAKE_SOURCE_DIR = " - << this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(this->GetSourceDirectory()), + << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(this->GetSourceDirectory()), cmOutputConverter::SHELL) << "\n" << "\n"; makefileStream << "# The top-level build directory on which CMake was run.\n" << "CMAKE_BINARY_DIR = " - << this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(this->GetBinaryDirectory()), + << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(this->GetBinaryDirectory()), cmOutputConverter::SHELL) << "\n" << "\n"; ----------------------------------------------------------------------- Summary of changes: Source/cmLocalUnixMakefileGenerator3.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) hooks/post-receive -- CMake From steveire at gmail.com Sat Aug 27 09:41:32 2016 From: steveire at gmail.com (Stephen Kelly) Date: Sat, 27 Aug 2016 09:41:32 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1571-g0dd8dc6 Message-ID: <20160827134132.8775FF34D9@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 0dd8dc67bc08d52744d501bdbedd077d2a1641a9 (commit) via 9cc5a4dd1f6d764830c7da33fa0c735124b6cd80 (commit) via d71230b33fea484a758726f12dc98bed95b5336c (commit) via f4028af43e062cb4b01e743236fd3efc3d0ff47d (commit) via e5d8ff5cf57be72c60911b6e2bf5e47dd8ad4c04 (commit) from 32389a10550df33224522978f5b9d6794c628d55 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0dd8dc67bc08d52744d501bdbedd077d2a1641a9 commit 0dd8dc67bc08d52744d501bdbedd077d2a1641a9 Merge: 32389a1 9cc5a4d Author: Stephen Kelly AuthorDate: Sat Aug 27 09:41:31 2016 -0400 Commit: CMake Topic Stage CommitDate: Sat Aug 27 09:41:31 2016 -0400 Merge topic 'cleanup-Convert' into next 9cc5a4dd Convert: Make variables a bit more clear d71230b3 Convert: Remove UNCHANGED enum value f4028af4 Convert: Remove 'FULL' conversion e5d8ff5c Convert: Replace Convert(FULL) with equivalent https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9cc5a4dd1f6d764830c7da33fa0c735124b6cd80 commit 9cc5a4dd1f6d764830c7da33fa0c735124b6cd80 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:58 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:41:18 2016 +0200 Convert: Make variables a bit more clear diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index f056a1b..630da42 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -49,26 +49,26 @@ std::string cmOutputConverter::ConvertToOutputForExisting( std::string cmOutputConverter::ConvertToRelativePath( const std::string& source, RelativeRoot relative) const { - std::string result = source; + std::string result; switch (relative) { case HOME: result = this->ConvertToRelativePath( - this->GetState()->GetSourceDirectoryComponents(), result); + this->GetState()->GetSourceDirectoryComponents(), source); break; case START: result = this->ConvertToRelativePath( this->StateSnapshot.GetDirectory().GetCurrentSourceComponents(), - result); + source); break; case HOME_OUTPUT: result = this->ConvertToRelativePath( - this->GetState()->GetBinaryDirectoryComponents(), result); + this->GetState()->GetBinaryDirectoryComponents(), source); break; case START_OUTPUT: result = this->ConvertToRelativePath( this->StateSnapshot.GetDirectory().GetCurrentBinaryComponents(), - result); + source); break; } return result; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d71230b33fea484a758726f12dc98bed95b5336c commit d71230b33fea484a758726f12dc98bed95b5336c Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:57 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:41:17 2016 +0200 Convert: Remove UNCHANGED enum value It is no longer used. diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index d3f9d64..b433c18 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -57,9 +57,9 @@ protected: // The windows module definition source file (.def), if any. cmSourceFile const* ModuleDefinitionFile; - std::string Convert( - std::string const& source, cmOutputConverter::RelativeRoot relative, - cmOutputConverter::OutputFormat output = cmOutputConverter::UNCHANGED); + std::string Convert(std::string const& source, + cmOutputConverter::RelativeRoot relative, + cmOutputConverter::OutputFormat output); void AppendFortranFormatFlags(std::string& flags, cmSourceFile const& source); diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index c2403db..9af9659 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -45,7 +45,6 @@ public: }; enum OutputFormat { - UNCHANGED, MAKERULE, SHELL, WATCOMQUOTE, @@ -54,7 +53,7 @@ public: std::string ConvertToOutputFormat(const std::string& source, OutputFormat output) const; std::string Convert(const std::string& remote, RelativeRoot local, - OutputFormat output = UNCHANGED) const; + OutputFormat output) const; std::string ConvertToRelativePath(const std::string& remote, RelativeRoot local) const; std::string ConvertDirectorySeparatorsForShell( https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f4028af43e062cb4b01e743236fd3efc3d0ff47d commit f4028af43e062cb4b01e743236fd3efc3d0ff47d Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:57 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:41:17 2016 +0200 Convert: Remove 'FULL' conversion It is no longer used. diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 176c9a0..f056a1b 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -70,9 +70,6 @@ std::string cmOutputConverter::ConvertToRelativePath( this->StateSnapshot.GetDirectory().GetCurrentBinaryComponents(), result); break; - case FULL: - result = cmSystemTools::CollapseFullPath(result); - break; } return result; } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 71bb086..c2403db 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -38,7 +38,6 @@ public: */ enum RelativeRoot { - FULL, HOME, START, HOME_OUTPUT, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e5d8ff5cf57be72c60911b6e2bf5e47dd8ad4c04 commit e5d8ff5cf57be72c60911b6e2bf5e47dd8ad4c04 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:57 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:41:17 2016 +0200 Convert: Replace Convert(FULL) with equivalent This is more explicit than funnelling everything through the Convert method. diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index bbc794d..77fbbe9 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -723,8 +723,9 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # in target - progCmd << lg->Convert(progress.Dir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << lg->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progress.Dir), + cmOutputConverter::SHELL); // std::set emitted; progCmd << " " << this->CountProgressMarksInTarget(gtarget, emitted); @@ -736,8 +737,9 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0 - progCmd << lg->Convert(progress.Dir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << lg->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progress.Dir), + cmOutputConverter::SHELL); progCmd << " 0"; commands.push_back(progCmd.str()); } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 2fa3f86..de9e1e5 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -688,7 +688,9 @@ std::string cmLocalGenerator::ExpandRuleVariable( } } if (variable == "CMAKE_COMMAND") { - return this->Convert(cmSystemTools::GetCMakeCommand(), FULL, SHELL); + return this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()), + SHELL); } std::vector enabledLanguages = this->GetState()->GetEnabledLanguages(); @@ -1183,7 +1185,8 @@ void cmLocalGenerator::GetTargetFlags( if (sf->GetExtension() == "def") { linkFlags += this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG"); - linkFlags += this->Convert(sf->GetFullPath(), FULL, SHELL); + linkFlags += this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(sf->GetFullPath()), SHELL); linkFlags += " "; } } diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index bbec634..d07bfaa 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -133,7 +133,8 @@ std::string cmLocalNinjaGenerator::ConvertToIncludeReference( bool forceFullPaths) { if (forceFullPaths) { - return this->Convert(path, cmOutputConverter::FULL, format); + return this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(path), + format); } return this->Convert(path, cmOutputConverter::HOME_OUTPUT, format); } diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 0a0089b..7fa35b8 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -640,9 +640,9 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( std::string cmakeShellCommand = this->MaybeConvertWacomShellCommand(cmSystemTools::GetCMakeCommand()); if (cmakeShellCommand.empty()) { - cmakeShellCommand = - this->Convert(cmSystemTools::GetCMakeCommand(), cmOutputConverter::FULL, - cmOutputConverter::SHELL); + cmakeShellCommand = this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()), + cmOutputConverter::SHELL); } /* clang-format off */ @@ -665,16 +665,16 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( makefileStream << "# The top-level source directory on which CMake was run.\n" << "CMAKE_SOURCE_DIR = " - << this->Convert(this->GetSourceDirectory(), - cmOutputConverter::FULL, + << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(this->GetSourceDirectory()), cmOutputConverter::SHELL) << "\n" << "\n"; makefileStream << "# The top-level build directory on which CMake was run.\n" << "CMAKE_BINARY_DIR = " - << this->Convert(this->GetBinaryDirectory(), - cmOutputConverter::FULL, + << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(this->GetBinaryDirectory()), cmOutputConverter::SHELL) << "\n" << "\n"; @@ -1154,8 +1154,9 @@ void cmLocalUnixMakefileGenerator3::AppendEcho( cmd += color_name; if (progress) { cmd += "--progress-dir="; - cmd += this->Convert(progress->Dir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + cmd += this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progress->Dir), + cmOutputConverter::SHELL); cmd += " "; cmd += "--progress-num="; cmd += progress->Arg; @@ -1603,15 +1604,16 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; - progCmd << this->Convert(progressDir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL); std::string progressFile = cmake::GetCMakeFilesDirectory(); progressFile += "/progress.marks"; std::string progressFileNameFull = this->ConvertToFullPath(progressFile); progCmd << " " - << this->Convert(progressFileNameFull, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progressFileNameFull), + cmOutputConverter::SHELL); commands.push_back(progCmd.str()); } std::string mf2Dir = cmake::GetCMakeFilesDirectoryPostSlash(); @@ -1623,8 +1625,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0 - progCmd << this->Convert(progressDir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL); progCmd << " 0"; commands.push_back(progCmd.str()); } diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 1beaa87..70fe819 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -269,8 +269,8 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() args += this->GetBinaryDirectory(); commandLine.push_back(args); commandLine.push_back("--check-stamp-file"); - std::string stampFilename = this->Convert( - stampName.c_str(), cmOutputConverter::FULL, cmOutputConverter::SHELL); + std::string stampFilename = this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(stampName), cmOutputConverter::SHELL); commandLine.push_back(stampFilename.c_str()); std::vector const& listFiles = this->Makefile->GetListFiles(); diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index d1cefe3..b492962 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -155,7 +155,8 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( script += newline; newline = newline_text; script += "cd "; - script += this->Convert(workingDirectory, FULL, SHELL); + script += this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(workingDirectory), SHELL); script += check_error; // Change the working drive. diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index b34cd6e..165f96c 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1000,9 +1000,10 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() // paths. Make sure PWD is set to the original name of the home // output directory to help cmSystemTools to create the same // translation table for the dependency scanning process. - depCmd << "cd " << (this->LocalGenerator->Convert( - this->LocalGenerator->GetBinaryDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL)) + depCmd << "cd " << (this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetBinaryDirectory()), + cmOutputConverter::SHELL)) << " && "; #endif // Generate a call this signature: @@ -1016,20 +1017,29 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() // the state of our local generator sufficiently for its needs. depCmd << "$(CMAKE_COMMAND) -E cmake_depends \"" << this->GlobalGenerator->GetName() << "\" " - << this->Convert(this->LocalGenerator->GetSourceDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetSourceDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->LocalGenerator->GetCurrentSourceDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetCurrentSourceDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->LocalGenerator->GetBinaryDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetBinaryDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->LocalGenerator->GetCurrentBinaryDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetCurrentBinaryDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->InfoFileNameFull, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(this->InfoFileNameFull), + cmOutputConverter::SHELL); if (this->LocalGenerator->GetColorMakefile()) { depCmd << " --color=$(COLOR)"; } ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From kwrobot at kitware.com Sun Aug 28 00:01:10 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Sun, 28 Aug 2016 00:01:10 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-750-g4ce52ab Message-ID: <20160828040110.9D15BF5780@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 4ce52abc03e3fe5475a8dd22014b9a9eb00a184d (commit) from 897346032b33ebd033cda9bcb5d094f1c112f37d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4ce52abc03e3fe5475a8dd22014b9a9eb00a184d commit 4ce52abc03e3fe5475a8dd22014b9a9eb00a184d Author: Kitware Robot AuthorDate: Sun Aug 28 00:01:07 2016 -0400 Commit: Kitware Robot CommitDate: Sun Aug 28 00:01:07 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 770b6bd..c502036 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160827) +set(CMake_VERSION_PATCH 20160828) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From kwrobot at kitware.com Mon Aug 29 00:01:06 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Mon, 29 Aug 2016 00:01:06 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-751-gb38aa00 Message-ID: <20160829040106.E05E4F5AA3@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via b38aa000334c35193140c6b544067b0b30d916c5 (commit) from 4ce52abc03e3fe5475a8dd22014b9a9eb00a184d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b38aa000334c35193140c6b544067b0b30d916c5 commit b38aa000334c35193140c6b544067b0b30d916c5 Author: Kitware Robot AuthorDate: Mon Aug 29 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Mon Aug 29 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index c502036..22bab72 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160828) +set(CMake_VERSION_PATCH 20160829) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From kwrobot at kitware.com Tue Aug 30 00:01:09 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Tue, 30 Aug 2016 00:01:09 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-752-g57d121f Message-ID: <20160830040109.8CE25F5666@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 57d121fbb1f2e9e2ac0622dd4049dedc3968d894 (commit) from b38aa000334c35193140c6b544067b0b30d916c5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=57d121fbb1f2e9e2ac0622dd4049dedc3968d894 commit 57d121fbb1f2e9e2ac0622dd4049dedc3968d894 Author: Kitware Robot AuthorDate: Tue Aug 30 00:01:05 2016 -0400 Commit: Kitware Robot CommitDate: Tue Aug 30 00:01:05 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 22bab72..52986e2 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160829) +set(CMake_VERSION_PATCH 20160830) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 30 09:05:45 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 30 Aug 2016 09:05:45 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1573-g39c455a Message-ID: <20160830130546.0679CF5366@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 39c455a26827178bf2b2cc585dc59fad3329b5ee (commit) via 048d1adb4ede50e49dce00873a5961e424e149f9 (commit) from 0dd8dc67bc08d52744d501bdbedd077d2a1641a9 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=39c455a26827178bf2b2cc585dc59fad3329b5ee commit 39c455a26827178bf2b2cc585dc59fad3329b5ee Merge: 0dd8dc6 048d1ad Author: Brad King AuthorDate: Tue Aug 30 09:05:44 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 30 09:05:44 2016 -0400 Merge topic 'ninja-add_custom_command-depfile' into next 048d1adb add_custom_command: Add DEPFILE option for Ninja https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=048d1adb4ede50e49dce00873a5961e424e149f9 commit 048d1adb4ede50e49dce00873a5961e424e149f9 Author: Kulla Christoph AuthorDate: Fri Aug 5 14:39:31 2016 +0200 Commit: Brad King CommitDate: Tue Aug 30 09:05:18 2016 -0400 add_custom_command: Add DEPFILE option for Ninja Provide a way for custom commands to inform the ninja build tool about their implicit dependencies. For now simply make use of the option an error on other generators. Closes: #15479 diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst index d421364..4ab4298 100644 --- a/Help/command/add_custom_command.rst +++ b/Help/command/add_custom_command.rst @@ -20,6 +20,7 @@ The first signature is for adding a custom command to produce an output:: [ depend2] ...] [WORKING_DIRECTORY dir] [COMMENT comment] + [DEPFILE depfile] [VERBATIM] [APPEND] [USES_TERMINAL]) This defines a command to generate specified ``OUTPUT`` file(s). @@ -170,6 +171,12 @@ The options are: If it is a relative path it will be interpreted relative to the build tree directory corresponding to the current source directory. +``DEPFILE`` + Specify a ``.d`` depfile for the :generator:`Ninja` generator. + A ``.d`` file holds dependencies usually emitted by the custom + command itself. + Using ``DEPFILE`` with other generators than Ninja is an error. + Build Events ^^^^^^^^^^^^ diff --git a/Help/release/dev/ninja-add_custom_command-depfile.rst b/Help/release/dev/ninja-add_custom_command-depfile.rst new file mode 100644 index 0000000..c8099fe --- /dev/null +++ b/Help/release/dev/ninja-add_custom_command-depfile.rst @@ -0,0 +1,6 @@ +ninja-add_custom_command-depfile +-------------------------------- + +* The :command:`add_custom_command` command gained a new ``DEPFILE`` + option that works with the :generator:`Ninja` generator to provide + implicit dependency information to the build tool. diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx index 400be77..2c4a4ca 100644 --- a/Source/cmAddCustomCommandCommand.cxx +++ b/Source/cmAddCustomCommandCommand.cxx @@ -15,6 +15,8 @@ #include "cmSourceFile.h" +#include "cmGlobalGenerator.h" + // cmAddCustomCommandCommand bool cmAddCustomCommandCommand::InitialPass( std::vector const& args, cmExecutionStatus&) @@ -28,7 +30,7 @@ bool cmAddCustomCommandCommand::InitialPass( return false; } - std::string source, target, main_dependency, working; + std::string source, target, main_dependency, working, depfile; std::string comment_buffer; const char* comment = CM_NULLPTR; std::vector depends, outputs, output, byproducts; @@ -60,6 +62,7 @@ bool cmAddCustomCommandCommand::InitialPass( doing_byproducts, doing_comment, doing_working_directory, + doing_depfile, doing_nothing }; @@ -110,6 +113,13 @@ bool cmAddCustomCommandCommand::InitialPass( doing = doing_implicit_depends_lang; } else if (copy == "COMMENT") { doing = doing_comment; + } else if (copy == "DEPFILE") { + doing = doing_depfile; + if (this->Makefile->GetGlobalGenerator()->GetName() != "Ninja") { + this->SetError("Option DEPFILE not supported by " + + this->Makefile->GetGlobalGenerator()->GetName()); + return false; + } } else { std::string filename; switch (doing) { @@ -147,6 +157,9 @@ bool cmAddCustomCommandCommand::InitialPass( filename = cmSystemTools::CollapseFullPath(filename); } switch (doing) { + case doing_depfile: + depfile = copy; + break; case doing_working_directory: working = copy; break; @@ -269,12 +282,12 @@ bool cmAddCustomCommandCommand::InitialPass( std::vector no_depends; this->Makefile->AddCustomCommandToTarget( target, byproducts, no_depends, commandLines, cctype, comment, - working.c_str(), escapeOldStyle, uses_terminal); + working.c_str(), escapeOldStyle, uses_terminal, depfile); } else if (target.empty()) { // Target is empty, use the output. this->Makefile->AddCustomCommandToOutput( output, byproducts, depends, main_dependency, commandLines, comment, - working.c_str(), false, escapeOldStyle, uses_terminal); + working.c_str(), false, escapeOldStyle, uses_terminal, depfile); // Add implicit dependency scanning requests if any were given. if (!implicit_depends.empty()) { diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx index 7533369..eaa49b0 100644 --- a/Source/cmCustomCommand.cxx +++ b/Source/cmCustomCommand.cxx @@ -135,3 +135,13 @@ void cmCustomCommand::SetUsesTerminal(bool b) { this->UsesTerminal = b; } + +const std::string& cmCustomCommand::GetDepfile() const +{ + return this->Depfile; +} + +void cmCustomCommand::SetDepfile(const std::string& depfile) +{ + this->Depfile = depfile; +} diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h index c2b9738..34753f4 100644 --- a/Source/cmCustomCommand.h +++ b/Source/cmCustomCommand.h @@ -88,6 +88,10 @@ public: bool GetUsesTerminal() const; void SetUsesTerminal(bool b); + /** Set/Get the depfile (used by the Ninja generator) */ + const std::string& GetDepfile() const; + void SetDepfile(const std::string& depfile); + private: std::vector Outputs; std::vector Byproducts; @@ -97,6 +101,7 @@ private: ImplicitDependsList ImplicitDepends; std::string Comment; std::string WorkingDirectory; + std::string Depfile; bool HaveComment; bool EscapeAllowMakeVars; bool EscapeOldStyle; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 2b83479..9bc8246 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -251,8 +251,8 @@ void cmGlobalNinjaGenerator::AddCustomCommandRule() void cmGlobalNinjaGenerator::WriteCustomCommandBuild( const std::string& command, const std::string& description, - const std::string& comment, bool uses_terminal, bool restat, - const cmNinjaDeps& outputs, const cmNinjaDeps& deps, + const std::string& comment, const std::string& depfile, bool uses_terminal, + bool restat, const cmNinjaDeps& outputs, const cmNinjaDeps& deps, const cmNinjaDeps& orderOnly) { std::string cmd = command; @@ -273,7 +273,9 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild( if (uses_terminal && SupportsConsolePool()) { vars["pool"] = "console"; } - + if (!depfile.empty()) { + vars["depfile"] = depfile; + } this->WriteBuild(*this->BuildFileStream, comment, "CUSTOM_COMMAND", outputs, deps, cmNinjaDeps(), orderOnly, vars); @@ -839,7 +841,7 @@ void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies() std::copy(i->second.begin(), i->second.end(), std::back_inserter(deps)); WriteCustomCommandBuild(/*command=*/"", /*description=*/"", "Assume dependencies for generated source file.", - /*uses_terminal*/ false, + /*depfile*/ "", /*uses_terminal*/ false, /*restat*/ true, cmNinjaDeps(1, i->first), deps); } } diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 52fa5c9..082ee3a 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -113,7 +113,8 @@ public: void WriteCustomCommandBuild(const std::string& command, const std::string& description, - const std::string& comment, bool uses_terminal, + const std::string& comment, + const std::string& depfile, bool uses_terminal, bool restat, const cmNinjaDeps& outputs, const cmNinjaDeps& deps = cmNinjaDeps(), const cmNinjaDeps& orderOnly = cmNinjaDeps()); diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 46d7e18..4200e5d 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -412,7 +412,8 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( } else { this->GetGlobalNinjaGenerator()->WriteCustomCommandBuild( this->BuildCommandLine(cmdLines), this->ConstructComment(ccg), - "Custom command for " + ninjaOutputs[0], cc->GetUsesTerminal(), + "Custom command for " + ninjaOutputs[0], cc->GetDepfile(), + cc->GetUsesTerminal(), /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, ninjaDeps, orderOnlyDeps); } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 6e47797..d1fddca 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -701,7 +701,7 @@ void cmMakefile::AddCustomCommandToTarget( const std::vector& depends, const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type, const char* comment, const char* workingDir, bool escapeOldStyle, - bool uses_terminal) + bool uses_terminal, const std::string& depfile) { // Find the target to which to add the custom command. cmTargets::iterator ti = this->Targets.find(target); @@ -773,6 +773,7 @@ void cmMakefile::AddCustomCommandToTarget( cc.SetEscapeOldStyle(escapeOldStyle); cc.SetEscapeAllowMakeVars(true); cc.SetUsesTerminal(uses_terminal); + cc.SetDepfile(depfile); switch (type) { case cmTarget::PRE_BUILD: ti->second.AddPreBuildCommand(cc); @@ -792,7 +793,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput( const std::vector& depends, const std::string& main_dependency, const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace, bool escapeOldStyle, - bool uses_terminal) + bool uses_terminal, const std::string& depfile) { // Make sure there is at least one output. if (outputs.empty()) { @@ -886,6 +887,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput( cc->SetEscapeOldStyle(escapeOldStyle); cc->SetEscapeAllowMakeVars(true); cc->SetUsesTerminal(uses_terminal); + cc->SetDepfile(depfile); file->SetCustomCommand(cc); this->UpdateOutputToSourceMap(outputs, file); } @@ -923,14 +925,14 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput( const std::string& output, const std::vector& depends, const std::string& main_dependency, const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace, - bool escapeOldStyle, bool uses_terminal) + bool escapeOldStyle, bool uses_terminal, const std::string& depfile) { std::vector outputs; outputs.push_back(output); std::vector no_byproducts; return this->AddCustomCommandToOutput( outputs, no_byproducts, depends, main_dependency, commandLines, comment, - workingDir, replace, escapeOldStyle, uses_terminal); + workingDir, replace, escapeOldStyle, uses_terminal, depfile); } void cmMakefile::AddCustomCommandOldStyle( diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index b3587c5..4d137db 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -135,14 +135,12 @@ public: void FinalPass(); /** Add a custom command to the build. */ - void AddCustomCommandToTarget(const std::string& target, - const std::vector& byproducts, - const std::vector& depends, - const cmCustomCommandLines& commandLines, - cmTarget::CustomCommandType type, - const char* comment, const char* workingDir, - bool escapeOldStyle = true, - bool uses_terminal = false); + void AddCustomCommandToTarget( + const std::string& target, const std::vector& byproducts, + const std::vector& depends, + const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type, + const char* comment, const char* workingDir, bool escapeOldStyle = true, + bool uses_terminal = false, const std::string& depfile = ""); cmSourceFile* AddCustomCommandToOutput( const std::vector& outputs, const std::vector& byproducts, @@ -150,13 +148,13 @@ public: const std::string& main_dependency, const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace = false, bool escapeOldStyle = true, - bool uses_terminal = false); + bool uses_terminal = false, const std::string& depfile = ""); cmSourceFile* AddCustomCommandToOutput( const std::string& output, const std::vector& depends, const std::string& main_dependency, const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace = false, bool escapeOldStyle = true, - bool uses_terminal = false); + bool uses_terminal = false, const std::string& depfile = ""); void AddCustomCommandOldStyle(const std::string& target, const std::vector& outputs, const std::vector& depends, diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx index 49836f2..0664104 100644 --- a/Source/cmNinjaUtilityTargetGenerator.cxx +++ b/Source/cmNinjaUtilityTargetGenerator.cxx @@ -150,7 +150,7 @@ void cmNinjaUtilityTargetGenerator::Generate() this->GetGlobalGenerator()->WriteCustomCommandBuild( command, desc, "Utility command for " + this->GetTargetName(), - uses_terminal, + /*depfile*/ "", uses_terminal, /*restat*/ true, util_outputs, deps); this->GetGlobalGenerator()->WritePhonyBuild( diff --git a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-result.txt b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt new file mode 100644 index 0000000..74d62a4 --- /dev/null +++ b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt @@ -0,0 +1,5 @@ +^CMake Error at CustomCommandDepfile-ERROR.cmake:1 \(add_custom_command\): + add_custom_command Option DEPFILE not supported by [^ +]+ +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR.cmake b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR.cmake new file mode 100644 index 0000000..bad7955 --- /dev/null +++ b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR.cmake @@ -0,0 +1,8 @@ +add_custom_command( + OUTPUT hello.copy.c + COMMAND "${CMAKE_COMMAND}" -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/hello.c" + hello.copy.c + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + DEPFILE "test.d" + ) diff --git a/Tests/RunCMake/Make/RunCMakeTest.cmake b/Tests/RunCMake/Make/RunCMakeTest.cmake index c6bbd03..869d11e 100644 --- a/Tests/RunCMake/Make/RunCMakeTest.cmake +++ b/Tests/RunCMake/Make/RunCMakeTest.cmake @@ -15,3 +15,5 @@ run_TargetMessages(OFF) run_TargetMessages(VAR-ON -DCMAKE_TARGET_MESSAGES=ON) run_TargetMessages(VAR-OFF -DCMAKE_TARGET_MESSAGES=OFF) + +run_cmake(CustomCommandDepfile-ERROR) diff --git a/Tests/RunCMake/Ninja/CustomCommandDepfile-check.cmake b/Tests/RunCMake/Ninja/CustomCommandDepfile-check.cmake new file mode 100644 index 0000000..189de64 --- /dev/null +++ b/Tests/RunCMake/Ninja/CustomCommandDepfile-check.cmake @@ -0,0 +1,5 @@ +set(log "${RunCMake_BINARY_DIR}/CustomCommandDepfile-build/build.ninja") +file(READ "${log}" build_file) +if(NOT "${build_file}" MATCHES "depfile = test\\.d") + set(RunCMake_TEST_FAILED "Log file:\n ${log}\ndoes not have expected line: depfile = test.d") +endif() diff --git a/Tests/RunCMake/Ninja/CustomCommandDepfile.cmake b/Tests/RunCMake/Ninja/CustomCommandDepfile.cmake new file mode 100644 index 0000000..dbef2a5 --- /dev/null +++ b/Tests/RunCMake/Ninja/CustomCommandDepfile.cmake @@ -0,0 +1,11 @@ +add_custom_command( + OUTPUT hello.copy.c + COMMAND "${CMAKE_COMMAND}" -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/hello.c" + hello.copy.c + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + DEPFILE "test.d" + ) +add_custom_target(copy ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/hello.copy.c") + +include(CheckNoPrefixSubDir.cmake) diff --git a/Tests/RunCMake/Ninja/RunCMakeTest.cmake b/Tests/RunCMake/Ninja/RunCMakeTest.cmake index 622c327..778f2c1 100644 --- a/Tests/RunCMake/Ninja/RunCMakeTest.cmake +++ b/Tests/RunCMake/Ninja/RunCMakeTest.cmake @@ -32,6 +32,8 @@ run_CMP0058(WARN-by) run_CMP0058(NEW-no) run_CMP0058(NEW-by) +run_cmake(CustomCommandDepfile) + function(run_SubDir) # Use a single build tree for a few tests without cleaning. set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SubDir-build) ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 30 09:18:38 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 30 Aug 2016 09:18:38 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1575-g50eca8d Message-ID: <20160830131838.924F7F56C5@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 50eca8d02d62159621925b248b6525df2e974892 (commit) via 062a47f11cbdd8de610c82aa94f3fc5307817e80 (commit) from 39c455a26827178bf2b2cc585dc59fad3329b5ee (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=50eca8d02d62159621925b248b6525df2e974892 commit 50eca8d02d62159621925b248b6525df2e974892 Merge: 39c455a 062a47f Author: Brad King AuthorDate: Tue Aug 30 09:18:37 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 30 09:18:37 2016 -0400 Merge topic 'cleanup-Convert' into next 062a47f1 fixup! Makefiles: Replace method with Wacom specific API https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=062a47f11cbdd8de610c82aa94f3fc5307817e80 commit 062a47f11cbdd8de610c82aa94f3fc5307817e80 Author: Brad King AuthorDate: Tue Aug 30 09:15:16 2016 -0400 Commit: Brad King CommitDate: Tue Aug 30 09:15:16 2016 -0400 fixup! Makefiles: Replace method with Wacom specific API diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 7fa35b8..3c4841e 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -592,7 +592,7 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule( } } -std::string cmLocalUnixMakefileGenerator3::MaybeConvertWacomShellCommand( +std::string cmLocalUnixMakefileGenerator3::MaybeConvertWatcomShellCommand( std::string const& cmd) { if (this->IsWatcomWMake() && cmSystemTools::FileIsFullPath(cmd.c_str()) && @@ -638,7 +638,7 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( } std::string cmakeShellCommand = - this->MaybeConvertWacomShellCommand(cmSystemTools::GetCMakeCommand()); + this->MaybeConvertWatcomShellCommand(cmSystemTools::GetCMakeCommand()); if (cmakeShellCommand.empty()) { cmakeShellCommand = this->ConvertToOutputFormat( cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()), @@ -1007,7 +1007,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( } } - std::string shellCommand = this->MaybeConvertWacomShellCommand(cmd); + std::string shellCommand = this->MaybeConvertWatcomShellCommand(cmd); if (shellCommand.empty()) { shellCommand = this->ConvertToOutputFormat(cmd, cmOutputConverter::SHELL); diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index bc7566e..3e90055 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -250,7 +250,7 @@ protected: void CheckMultipleOutputs(bool verbose); private: - std::string MaybeConvertWacomShellCommand(std::string const& cmd); + std::string MaybeConvertWatcomShellCommand(std::string const& cmd); void ComputeObjectFilenames( std::map& mapping, ----------------------------------------------------------------------- Summary of changes: Source/cmLocalUnixMakefileGenerator3.cxx | 6 +++--- Source/cmLocalUnixMakefileGenerator3.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 30 09:21:21 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 30 Aug 2016 09:21:21 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1595-g40b8e22 Message-ID: <20160830132121.22F7AF57C0@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 40b8e22e55c20d2ecf31fe51ebc22453ec28996f (commit) via 4332131dcca03b262e0dd51352eb2e27522887c8 (commit) via 5aca066c5bbb7263624eb140378dd2f49e9d80ec (commit) via 146bf9267ca88831d7cff4d121f414a3a73e26de (commit) via 58ba87f892316b9f9cbb7851a940ec808527e36a (commit) via e80314d7a8208214ac85bf9b2e769a7e3b5aaa04 (commit) via 563ac22a1646f1287d1baac755e13cbe33c1fe7b (commit) via 08be47cf939c3adfe653809c46c7b23b7a912a39 (commit) via 564d3a1dc8e19f16db6ddccca38e21d89634c1b4 (commit) via 95a659f1801701b02528c22f0287bb57056dc627 (commit) via a8c7ccb1839d912edc972384de6641f3c17ad8ff (commit) via 5ad25ef4b690252a4251e8824e00b053ea61d000 (commit) via ac46384171c54a0fb9c47c32642fbca4ff1e925b (commit) via 998d9ee967f6795c71ff23cf16601f7e974b21ba (commit) via ee49f006cf657fa6f1c2d112f44d762441fd5cf1 (commit) via 51f7dcb0a55874e71e4695f5154548a41c87ad56 (commit) via ba4ba7c39de82b805652efbb7dc5e1659c53f36b (commit) via e804d410cd4e391cd81ff3d8981cfba1fae28742 (commit) via 2722c4dcc55605b7946f3c9bfa4b2fe5ce4161cb (commit) via 112c87b28afac71617bcbb552ae1f2027bb548b6 (commit) from 50eca8d02d62159621925b248b6525df2e974892 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=40b8e22e55c20d2ecf31fe51ebc22453ec28996f commit 40b8e22e55c20d2ecf31fe51ebc22453ec28996f Merge: 50eca8d 4332131 Author: Brad King AuthorDate: Tue Aug 30 09:21:18 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 30 09:21:18 2016 -0400 Merge topic 'cleanup-Convert' into next 4332131d Convert: Make variables a bit more clear 5aca066c Convert: Remove UNCHANGED enum value 146bf926 Convert: Remove 'FULL' conversion 58ba87f8 Convert: Replace Convert(FULL) with equivalent e80314d7 Ninja: Replace ternary with if() 563ac22a Convert: Replace trivial conversion with new method 08be47cf Convert: Replace UNCHANGED conversions with new API call 564d3a1d Convert: Extract ConvertToRelativePath from Convert() 95a659f1 Convert: Replace FULL conversions with equivalent a8c7ccb1 VS: Replace FULL/UNCHANGED conversion with equivalent 5ad25ef4 Convert: Remove NONE conversion ac463841 Convert: Replace uses of Convert(NONE) 998d9ee9 VS: Replace variable with an if() ee49f006 Makefiles: Replace ternaries with if()s 51f7dcb0 Makefiles: Inline MakeLauncher into only caller ba4ba7c3 Makefiles: Simplify MakeLauncher return value ... https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4332131dcca03b262e0dd51352eb2e27522887c8 commit 4332131dcca03b262e0dd51352eb2e27522887c8 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:58 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:41:18 2016 +0200 Convert: Make variables a bit more clear diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index f056a1b..630da42 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -49,26 +49,26 @@ std::string cmOutputConverter::ConvertToOutputForExisting( std::string cmOutputConverter::ConvertToRelativePath( const std::string& source, RelativeRoot relative) const { - std::string result = source; + std::string result; switch (relative) { case HOME: result = this->ConvertToRelativePath( - this->GetState()->GetSourceDirectoryComponents(), result); + this->GetState()->GetSourceDirectoryComponents(), source); break; case START: result = this->ConvertToRelativePath( this->StateSnapshot.GetDirectory().GetCurrentSourceComponents(), - result); + source); break; case HOME_OUTPUT: result = this->ConvertToRelativePath( - this->GetState()->GetBinaryDirectoryComponents(), result); + this->GetState()->GetBinaryDirectoryComponents(), source); break; case START_OUTPUT: result = this->ConvertToRelativePath( this->StateSnapshot.GetDirectory().GetCurrentBinaryComponents(), - result); + source); break; } return result; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5aca066c5bbb7263624eb140378dd2f49e9d80ec commit 5aca066c5bbb7263624eb140378dd2f49e9d80ec Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:57 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:41:17 2016 +0200 Convert: Remove UNCHANGED enum value It is no longer used. diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index d3f9d64..b433c18 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -57,9 +57,9 @@ protected: // The windows module definition source file (.def), if any. cmSourceFile const* ModuleDefinitionFile; - std::string Convert( - std::string const& source, cmOutputConverter::RelativeRoot relative, - cmOutputConverter::OutputFormat output = cmOutputConverter::UNCHANGED); + std::string Convert(std::string const& source, + cmOutputConverter::RelativeRoot relative, + cmOutputConverter::OutputFormat output); void AppendFortranFormatFlags(std::string& flags, cmSourceFile const& source); diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index c2403db..9af9659 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -45,7 +45,6 @@ public: }; enum OutputFormat { - UNCHANGED, MAKERULE, SHELL, WATCOMQUOTE, @@ -54,7 +53,7 @@ public: std::string ConvertToOutputFormat(const std::string& source, OutputFormat output) const; std::string Convert(const std::string& remote, RelativeRoot local, - OutputFormat output = UNCHANGED) const; + OutputFormat output) const; std::string ConvertToRelativePath(const std::string& remote, RelativeRoot local) const; std::string ConvertDirectorySeparatorsForShell( https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=146bf9267ca88831d7cff4d121f414a3a73e26de commit 146bf9267ca88831d7cff4d121f414a3a73e26de Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:57 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:41:17 2016 +0200 Convert: Remove 'FULL' conversion It is no longer used. diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 176c9a0..f056a1b 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -70,9 +70,6 @@ std::string cmOutputConverter::ConvertToRelativePath( this->StateSnapshot.GetDirectory().GetCurrentBinaryComponents(), result); break; - case FULL: - result = cmSystemTools::CollapseFullPath(result); - break; } return result; } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 71bb086..c2403db 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -38,7 +38,6 @@ public: */ enum RelativeRoot { - FULL, HOME, START, HOME_OUTPUT, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=58ba87f892316b9f9cbb7851a940ec808527e36a commit 58ba87f892316b9f9cbb7851a940ec808527e36a Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:57 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:41:17 2016 +0200 Convert: Replace Convert(FULL) with equivalent This is more explicit than funnelling everything through the Convert method. diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index bbc794d..77fbbe9 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -723,8 +723,9 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # in target - progCmd << lg->Convert(progress.Dir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << lg->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progress.Dir), + cmOutputConverter::SHELL); // std::set emitted; progCmd << " " << this->CountProgressMarksInTarget(gtarget, emitted); @@ -736,8 +737,9 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0 - progCmd << lg->Convert(progress.Dir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << lg->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progress.Dir), + cmOutputConverter::SHELL); progCmd << " 0"; commands.push_back(progCmd.str()); } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 2fa3f86..de9e1e5 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -688,7 +688,9 @@ std::string cmLocalGenerator::ExpandRuleVariable( } } if (variable == "CMAKE_COMMAND") { - return this->Convert(cmSystemTools::GetCMakeCommand(), FULL, SHELL); + return this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()), + SHELL); } std::vector enabledLanguages = this->GetState()->GetEnabledLanguages(); @@ -1183,7 +1185,8 @@ void cmLocalGenerator::GetTargetFlags( if (sf->GetExtension() == "def") { linkFlags += this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG"); - linkFlags += this->Convert(sf->GetFullPath(), FULL, SHELL); + linkFlags += this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(sf->GetFullPath()), SHELL); linkFlags += " "; } } diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index bbec634..d07bfaa 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -133,7 +133,8 @@ std::string cmLocalNinjaGenerator::ConvertToIncludeReference( bool forceFullPaths) { if (forceFullPaths) { - return this->Convert(path, cmOutputConverter::FULL, format); + return this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(path), + format); } return this->Convert(path, cmOutputConverter::HOME_OUTPUT, format); } diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 5b83b3d..3c4841e 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -640,9 +640,9 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( std::string cmakeShellCommand = this->MaybeConvertWatcomShellCommand(cmSystemTools::GetCMakeCommand()); if (cmakeShellCommand.empty()) { - cmakeShellCommand = - this->Convert(cmSystemTools::GetCMakeCommand(), cmOutputConverter::FULL, - cmOutputConverter::SHELL); + cmakeShellCommand = this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()), + cmOutputConverter::SHELL); } /* clang-format off */ @@ -665,16 +665,16 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( makefileStream << "# The top-level source directory on which CMake was run.\n" << "CMAKE_SOURCE_DIR = " - << this->Convert(this->GetSourceDirectory(), - cmOutputConverter::FULL, + << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(this->GetSourceDirectory()), cmOutputConverter::SHELL) << "\n" << "\n"; makefileStream << "# The top-level build directory on which CMake was run.\n" << "CMAKE_BINARY_DIR = " - << this->Convert(this->GetBinaryDirectory(), - cmOutputConverter::FULL, + << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(this->GetBinaryDirectory()), cmOutputConverter::SHELL) << "\n" << "\n"; @@ -1154,8 +1154,9 @@ void cmLocalUnixMakefileGenerator3::AppendEcho( cmd += color_name; if (progress) { cmd += "--progress-dir="; - cmd += this->Convert(progress->Dir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + cmd += this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progress->Dir), + cmOutputConverter::SHELL); cmd += " "; cmd += "--progress-num="; cmd += progress->Arg; @@ -1603,15 +1604,16 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; - progCmd << this->Convert(progressDir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL); std::string progressFile = cmake::GetCMakeFilesDirectory(); progressFile += "/progress.marks"; std::string progressFileNameFull = this->ConvertToFullPath(progressFile); progCmd << " " - << this->Convert(progressFileNameFull, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progressFileNameFull), + cmOutputConverter::SHELL); commands.push_back(progCmd.str()); } std::string mf2Dir = cmake::GetCMakeFilesDirectoryPostSlash(); @@ -1623,8 +1625,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0 - progCmd << this->Convert(progressDir, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + progCmd << this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL); progCmd << " 0"; commands.push_back(progCmd.str()); } diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 1beaa87..70fe819 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -269,8 +269,8 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() args += this->GetBinaryDirectory(); commandLine.push_back(args); commandLine.push_back("--check-stamp-file"); - std::string stampFilename = this->Convert( - stampName.c_str(), cmOutputConverter::FULL, cmOutputConverter::SHELL); + std::string stampFilename = this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(stampName), cmOutputConverter::SHELL); commandLine.push_back(stampFilename.c_str()); std::vector const& listFiles = this->Makefile->GetListFiles(); diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index d1cefe3..b492962 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -155,7 +155,8 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( script += newline; newline = newline_text; script += "cd "; - script += this->Convert(workingDirectory, FULL, SHELL); + script += this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(workingDirectory), SHELL); script += check_error; // Change the working drive. diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index b34cd6e..165f96c 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1000,9 +1000,10 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() // paths. Make sure PWD is set to the original name of the home // output directory to help cmSystemTools to create the same // translation table for the dependency scanning process. - depCmd << "cd " << (this->LocalGenerator->Convert( - this->LocalGenerator->GetBinaryDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL)) + depCmd << "cd " << (this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetBinaryDirectory()), + cmOutputConverter::SHELL)) << " && "; #endif // Generate a call this signature: @@ -1016,20 +1017,29 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() // the state of our local generator sufficiently for its needs. depCmd << "$(CMAKE_COMMAND) -E cmake_depends \"" << this->GlobalGenerator->GetName() << "\" " - << this->Convert(this->LocalGenerator->GetSourceDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetSourceDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->LocalGenerator->GetCurrentSourceDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetCurrentSourceDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->LocalGenerator->GetBinaryDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetBinaryDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->LocalGenerator->GetCurrentBinaryDirectory(), - cmOutputConverter::FULL, cmOutputConverter::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetCurrentBinaryDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->InfoFileNameFull, cmOutputConverter::FULL, - cmOutputConverter::SHELL); + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(this->InfoFileNameFull), + cmOutputConverter::SHELL); if (this->LocalGenerator->GetColorMakefile()) { depCmd << " --color=$(COLOR)"; } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e80314d7a8208214ac85bf9b2e769a7e3b5aaa04 commit e80314d7a8208214ac85bf9b2e769a7e3b5aaa04 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:57 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:38 2016 +0200 Ninja: Replace ternary with if() On principle of segregating the interface. diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 9e2c920..bbec634 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -132,9 +132,10 @@ std::string cmLocalNinjaGenerator::ConvertToIncludeReference( std::string const& path, cmOutputConverter::OutputFormat format, bool forceFullPaths) { - return this->Convert(path, forceFullPaths ? cmOutputConverter::FULL - : cmOutputConverter::HOME_OUTPUT, - format); + if (forceFullPaths) { + return this->Convert(path, cmOutputConverter::FULL, format); + } + return this->Convert(path, cmOutputConverter::HOME_OUTPUT, format); } // Private methods. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=563ac22a1646f1287d1baac755e13cbe33c1fe7b commit 563ac22a1646f1287d1baac755e13cbe33c1fe7b Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:56 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:37 2016 +0200 Convert: Replace trivial conversion with new method diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index 18e123e..928f7ec 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -238,8 +238,8 @@ bool cmDependsC::WriteDependencies(const std::set& sources, // written by the original local generator for this directory // convert the dependencies to paths relative to the home output // directory. We must do the same here. - std::string obj_i = - this->LocalGenerator->Convert(obj, cmOutputConverter::HOME_OUTPUT); + std::string obj_i = this->LocalGenerator->ConvertToRelativePath( + obj, cmOutputConverter::HOME_OUTPUT); std::string obj_m = this->LocalGenerator->ConvertToOutputFormat( obj_i, cmOutputConverter::MAKERULE); internalDepends << obj_i << std::endl; diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index c57b558..8c0acce 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -193,15 +193,15 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends, stamp += ".mod.stamp"; fcStream << "\n"; fcStream << " \"" - << this->LocalGenerator->Convert( + << this->LocalGenerator->ConvertToRelativePath( mod_lower, cmOutputConverter::START_OUTPUT) << "\"\n"; fcStream << " \"" - << this->LocalGenerator->Convert( + << this->LocalGenerator->ConvertToRelativePath( mod_upper, cmOutputConverter::START_OUTPUT) << "\"\n"; fcStream << " \"" - << this->LocalGenerator->Convert( + << this->LocalGenerator->ConvertToRelativePath( stamp, cmOutputConverter::START_OUTPUT) << "\"\n"; } @@ -317,8 +317,8 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, const char* src = info.Source.c_str(); // Write the include dependencies to the output stream. - std::string obj_i = - this->LocalGenerator->Convert(obj, cmOutputConverter::HOME_OUTPUT); + std::string obj_i = this->LocalGenerator->ConvertToRelativePath( + obj, cmOutputConverter::HOME_OUTPUT); std::string obj_m = this->LocalGenerator->ConvertToOutputFormat( obj_i, cmOutputConverter::MAKERULE); internalDepends << obj_i << std::endl; diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index e617b08..945ee40 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -904,8 +904,8 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const it != this->GlobalGenerator->GetLocalGenerators().end(); ++it) { const std::vector targets = (*it)->GetGeneratorTargets(); - std::string subdir = (*it)->Convert((*it)->GetCurrentBinaryDirectory(), - cmOutputConverter::HOME_OUTPUT); + std::string subdir = (*it)->ConvertToRelativePath( + (*it)->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT); if (subdir == ".") { subdir = ""; } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 295f65b..50c5a42 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -2547,8 +2547,8 @@ void cmGlobalGenerator::AddRuleHash(const std::vector& outputs, // Shorten the output name (in expected use case). cmOutputConverter converter(this->GetMakefiles()[0]->GetStateSnapshot()); - std::string fname = - converter.Convert(outputs[0], cmOutputConverter::HOME_OUTPUT); + std::string fname = converter.ConvertToRelativePath( + outputs[0], cmOutputConverter::HOME_OUTPUT); // Associate the hash with this output. this->RuleHashes[fname] = hash; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 2b83479..939c5ad 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -747,7 +747,8 @@ std::string cmGlobalNinjaGenerator::ConvertToNinjaPath(const std::string& path) { cmLocalNinjaGenerator* ng = static_cast(this->LocalGenerators[0]); - std::string convPath = ng->Convert(path, cmOutputConverter::HOME_OUTPUT); + std::string convPath = + ng->ConvertToRelativePath(path, cmOutputConverter::HOME_OUTPUT); convPath = this->NinjaOutputPath(convPath); #ifdef _WIN32 std::replace(convPath.begin(), convPath.end(), '/', '\\'); @@ -760,7 +761,8 @@ std::string cmGlobalNinjaGenerator::ConvertToNinjaFolderRule( { cmLocalNinjaGenerator* ng = static_cast(this->LocalGenerators[0]); - std::string convPath = ng->Convert(path + "/all", cmOutputConverter::HOME); + std::string convPath = + ng->ConvertToRelativePath(path + "/all", cmOutputConverter::HOME); convPath = this->NinjaOutputPath(convPath); #ifdef _WIN32 std::replace(convPath.begin(), convPath.end(), '/', '\\'); diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index f115ecb..bbc794d 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -311,11 +311,14 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() cmakefileStream << "# The top level Makefile was generated from the following files:\n" << "set(CMAKE_MAKEFILE_DEPENDS\n" - << " \"" << lg->Convert(cache, cmOutputConverter::START_OUTPUT) << "\"\n"; + << " \"" + << lg->ConvertToRelativePath(cache, cmOutputConverter::START_OUTPUT) + << "\"\n"; for (std::vector::const_iterator i = lfiles.begin(); i != lfiles.end(); ++i) { cmakefileStream << " \"" - << lg->Convert(*i, cmOutputConverter::START_OUTPUT) + << lg->ConvertToRelativePath( + *i, cmOutputConverter::START_OUTPUT) << "\"\n"; } cmakefileStream << " )\n\n"; @@ -329,10 +332,12 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() cmakefileStream << "# The corresponding makefile is:\n" << "set(CMAKE_MAKEFILE_OUTPUTS\n" << " \"" - << lg->Convert(makefileName, cmOutputConverter::START_OUTPUT) + << lg->ConvertToRelativePath(makefileName, + cmOutputConverter::START_OUTPUT) << "\"\n" << " \"" - << lg->Convert(check, cmOutputConverter::START_OUTPUT) + << lg->ConvertToRelativePath(check, + cmOutputConverter::START_OUTPUT) << "\"\n"; cmakefileStream << " )\n\n"; @@ -345,7 +350,8 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() for (std::vector::const_iterator k = outfiles.begin(); k != outfiles.end(); ++k) { cmakefileStream << " \"" - << lg->Convert(*k, cmOutputConverter::HOME_OUTPUT) + << lg->ConvertToRelativePath( + *k, cmOutputConverter::HOME_OUTPUT) << "\"\n"; } @@ -358,7 +364,8 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() tmpStr += cmake::GetCMakeFilesDirectory(); tmpStr += "/CMakeDirectoryInformation.cmake"; cmakefileStream << " \"" - << lg->Convert(tmpStr, cmOutputConverter::HOME_OUTPUT) + << lg->ConvertToRelativePath( + tmpStr, cmOutputConverter::HOME_OUTPUT) << "\"\n"; } cmakefileStream << " )\n\n"; @@ -519,7 +526,7 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( tname += "/fast"; } cmOutputConverter conv(mf->GetStateSnapshot()); - tname = conv.Convert(tname, cmOutputConverter::HOME_OUTPUT); + tname = conv.ConvertToRelativePath(tname, cmOutputConverter::HOME_OUTPUT); cmSystemTools::ConvertToOutputSlashes(tname); makeCommand.push_back(tname); if (this->Makefiles.empty()) { diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 0a83b3a..67ac230 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -385,7 +385,8 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( if (vcprojName) { cmLocalGenerator* lg = target->GetLocalGenerator(); std::string dir = lg->GetCurrentBinaryDirectory(); - dir = root->Convert(dir.c_str(), cmOutputConverter::START_OUTPUT); + dir = root->ConvertToRelativePath(dir.c_str(), + cmOutputConverter::START_OUTPUT); if (dir == ".") { dir = ""; // msbuild cannot handle ".\" prefix } diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 39d9e97..3c5e333 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -402,7 +402,8 @@ void cmListFileBacktrace::PrintTitle(std::ostream& out) const cmOutputConverter converter(this->Bottom); cmListFileContext lfc = *this->Cur; if (!this->Bottom.GetState()->GetIsInTryCompile()) { - lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME); + lfc.FilePath = + converter.ConvertToRelativePath(lfc.FilePath, cmOutputConverter::HOME); } out << (lfc.Line ? " at " : " in ") << lfc; } @@ -427,7 +428,8 @@ void cmListFileBacktrace::PrintCallStack(std::ostream& out) const } cmListFileContext lfc = *i; if (!this->Bottom.GetState()->GetIsInTryCompile()) { - lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME); + lfc.FilePath = + converter.ConvertToRelativePath(lfc.FilePath, cmOutputConverter::HOME); } out << " " << lfc << "\n"; } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 20a1e21..2fa3f86 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -176,7 +176,7 @@ void cmLocalGenerator::GenerateTestFiles() // TODO: Use add_subdirectory instead? fout << "subdirs("; std::string outP = children[i].GetDirectory().GetCurrentBinary(); - fout << this->Convert(outP, START_OUTPUT); + fout << this->ConvertToRelativePath(outP, START_OUTPUT); fout << ")" << std::endl; } } @@ -2237,7 +2237,8 @@ std::string cmLocalGenerator::ConstructComment( for (std::vector::const_iterator o = ccg.GetOutputs().begin(); o != ccg.GetOutputs().end(); ++o) { comment += sep; - comment += this->Convert(*o, cmOutputConverter::START_OUTPUT); + comment += + this->ConvertToRelativePath(*o, cmOutputConverter::START_OUTPUT); sep = ", "; } return comment; @@ -2505,13 +2506,14 @@ std::string cmLocalGenerator::GetObjectFileNameWithoutTarget( const char* fullPath = source.GetFullPath().c_str(); // Try referencing the source relative to the source tree. - std::string relFromSource = this->Convert(fullPath, START); + std::string relFromSource = this->ConvertToRelativePath(fullPath, START); assert(!relFromSource.empty()); bool relSource = !cmSystemTools::FileIsFullPath(relFromSource.c_str()); bool subSource = relSource && relFromSource[0] != '.'; // Try referencing the source relative to the binary tree. - std::string relFromBinary = this->Convert(fullPath, START_OUTPUT); + std::string relFromBinary = + this->ConvertToRelativePath(fullPath, START_OUTPUT); assert(!relFromBinary.empty()); bool relBinary = !cmSystemTools::FileIsFullPath(relFromBinary.c_str()); bool subBinary = relBinary && relFromBinary[0] != '.'; diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 8c092e7..9e2c920 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -41,7 +41,7 @@ void cmLocalNinjaGenerator::Generate() { // Compute the path to use when referencing the current output // directory from the top output directory. - this->HomeRelativeOutputPath = this->Convert( + this->HomeRelativeOutputPath = this->ConvertToRelativePath( this->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT); if (this->HomeRelativeOutputPath == ".") { this->HomeRelativeOutputPath = ""; diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 33b0102..5b83b3d 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -140,7 +140,7 @@ void cmLocalUnixMakefileGenerator3::ComputeHomeRelativeOutputPath() { // Compute the path to use when referencing the current output // directory from the top output directory. - this->HomeRelativeOutputPath = this->Convert( + this->HomeRelativeOutputPath = this->ConvertToRelativePath( this->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT); if (this->HomeRelativeOutputPath == ".") { this->HomeRelativeOutputPath = ""; @@ -966,7 +966,8 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( // working directory will be the start-output directory. bool had_slash = cmd.find('/') != cmd.npos; if (workingDir.empty()) { - cmd = this->Convert(cmd, cmOutputConverter::START_OUTPUT); + cmd = + this->ConvertToRelativePath(cmd, cmOutputConverter::START_OUTPUT); } bool has_slash = cmd.find('/') != cmd.npos; if (had_slash && !has_slash) { @@ -1851,7 +1852,8 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( for (std::vector::iterator i = includes.begin(); i != includes.end(); ++i) { cmakefileStream << " \"" - << this->Convert(*i, cmOutputConverter::HOME_OUTPUT) + << this->ConvertToRelativePath( + *i, cmOutputConverter::HOME_OUTPUT) << "\"\n"; } cmakefileStream << " )\n"; @@ -1915,7 +1917,8 @@ std::string cmLocalUnixMakefileGenerator3::GetRecursiveMakeCall( // Add the target. if (!tgt.empty()) { // The make target is always relative to the top of the build tree. - std::string tgt2 = this->Convert(tgt, cmOutputConverter::HOME_OUTPUT); + std::string tgt2 = + this->ConvertToRelativePath(tgt, cmOutputConverter::HOME_OUTPUT); // The target may have been written with windows paths. cmSystemTools::ConvertToOutputSlashes(tgt2); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 2d53669..b34cd6e 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -312,8 +312,10 @@ void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()( output += "/"; output += cmSystemTools::GetFilenameName(input); this->Generator->CleanFiles.push_back( - this->Generator->Convert(output, cmOutputConverter::START_OUTPUT)); - output = this->Generator->Convert(output, cmOutputConverter::HOME_OUTPUT); + this->Generator->LocalGenerator->ConvertToRelativePath( + output, cmOutputConverter::START_OUTPUT)); + output = this->Generator->LocalGenerator->ConvertToRelativePath( + output, cmOutputConverter::HOME_OUTPUT); // Create a rule to copy the content into the bundle. std::vector depends; @@ -1171,7 +1173,8 @@ void cmMakefileTargetGenerator::WriteObjectsVariable( for (std::vector::const_iterator i = this->ExternalObjects.begin(); i != this->ExternalObjects.end(); ++i) { - object = this->Convert(*i, cmOutputConverter::START_OUTPUT); + object = this->LocalGenerator->ConvertToRelativePath( + *i, cmOutputConverter::START_OUTPUT); *this->BuildFileStream << " " << lineContinue << "\n" << this->Makefile->GetSafeDefinition( "CMAKE_OBJECT_NAME"); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index ed04d2f..d5274cd 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -602,7 +602,8 @@ void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const it != this->TLLCommands.end(); ++it) { if (it->first == sig) { cmListFileContext lfc = it->second; - lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME); + lfc.FilePath = + converter.ConvertToRelativePath(lfc.FilePath, cmOutputConverter::HOME); s << " * " << lfc << std::endl; } } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=08be47cf939c3adfe653809c46c7b23b7a912a39 commit 08be47cf939c3adfe653809c46c7b23b7a912a39 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:56 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:37 2016 +0200 Convert: Replace UNCHANGED conversions with new API call diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 756db2e..33b0102 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1076,8 +1076,8 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand( fout << "file(REMOVE_RECURSE\n"; for (std::vector::const_iterator f = files.begin(); f != files.end(); ++f) { - std::string fc = this->Convert(*f, cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + std::string fc = + this->ConvertToRelativePath(*f, cmOutputConverter::START_OUTPUT); fout << " " << cmOutputConverter::EscapeForCMake(fc) << "\n"; } fout << ")\n"; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 497defb..1beaa87 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -788,8 +788,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( target->GetProperty("Fortran_MODULE_DIRECTORY"); std::string modDir; if (target_mod_dir) { - modDir = this->Convert(target_mod_dir, cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + modDir = this->ConvertToRelativePath(target_mod_dir, + cmOutputConverter::START_OUTPUT); } else { modDir = "."; } @@ -1300,9 +1300,8 @@ void cmLocalVisualStudio7GeneratorInternals::OutputLibraries( cmLocalVisualStudio7Generator* lg = this->LocalGenerator; for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) { if (l->IsPath) { - std::string rel = - lg->Convert(l->Value.c_str(), cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + std::string rel = lg->ConvertToRelativePath( + l->Value.c_str(), cmOutputConverter::START_OUTPUT); fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " "; } else if (!l->Target || l->Target->GetType() != cmState::INTERFACE_LIBRARY) { @@ -1322,8 +1321,8 @@ void cmLocalVisualStudio7GeneratorInternals::OutputObjects( const char* sep = isep ? isep : ""; for (std::vector::const_iterator oi = objs.begin(); oi != objs.end(); ++oi) { - std::string rel = lg->Convert(oi->c_str(), cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + std::string rel = + lg->ConvertToRelativePath(oi->c_str(), cmOutputConverter::START_OUTPUT); fout << sep << lg->ConvertToXMLOutputPath(rel.c_str()); sep = " "; } @@ -1346,9 +1345,8 @@ void cmLocalVisualStudio7Generator::OutputLibraryDirectories( // Switch to a relative path specification if it is shorter. if (cmSystemTools::FileIsFullPath(dir.c_str())) { - std::string rel = - this->Convert(dir.c_str(), cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + std::string rel = this->ConvertToRelativePath( + dir.c_str(), cmOutputConverter::START_OUTPUT); if (rel.size() < dir.size()) { dir = rel; } diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index a14df79..66e1ca2 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -218,40 +218,34 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Construct a list of files associated with this executable that // may need to be cleaned. std::vector exeCleanFiles; - exeCleanFiles.push_back(this->Convert(targetFullPath, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPath, cmOutputConverter::START_OUTPUT)); #ifdef _WIN32 // There may be a manifest file for this target. Add it to the // clean set just in case. - exeCleanFiles.push_back(this->Convert((targetFullPath + ".manifest").c_str(), - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + (targetFullPath + ".manifest").c_str(), cmOutputConverter::START_OUTPUT)); #endif if (targetNameReal != targetName) { - exeCleanFiles.push_back(this->Convert(targetFullPathReal, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathReal, cmOutputConverter::START_OUTPUT)); } if (!targetNameImport.empty()) { - exeCleanFiles.push_back(this->Convert(targetFullPathImport, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathImport, cmOutputConverter::START_OUTPUT)); std::string implib; if (this->GeneratorTarget->GetImplibGNUtoMS(targetFullPathImport, implib)) { - exeCleanFiles.push_back(this->Convert(implib, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + implib, cmOutputConverter::START_OUTPUT)); } } // List the PDB for cleaning only when the whole target is // cleaned. We do not want to delete the .pdb file just before // linking the target. - this->CleanFiles.push_back(this->Convert(targetFullPathPDB, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + this->CleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathPDB, cmOutputConverter::START_OUTPUT)); // Add the pre-build and pre-link rules building but not when relinking. if (!relink) { diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index c8ee05f..c31c469 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -367,46 +367,40 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // Clean files associated with this library. std::vector libCleanFiles; - libCleanFiles.push_back(this->Convert(targetFullPath, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPath, cmOutputConverter::START_OUTPUT)); if (targetNameReal != targetName) { - libCleanFiles.push_back(this->Convert(targetFullPathReal, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathReal, cmOutputConverter::START_OUTPUT)); } if (targetNameSO != targetName && targetNameSO != targetNameReal) { - libCleanFiles.push_back(this->Convert(targetFullPathSO, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathSO, cmOutputConverter::START_OUTPUT)); } if (!targetNameImport.empty()) { - libCleanFiles.push_back(this->Convert(targetFullPathImport, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathImport, cmOutputConverter::START_OUTPUT)); std::string implib; if (this->GeneratorTarget->GetImplibGNUtoMS(targetFullPathImport, implib)) { - libCleanFiles.push_back(this->Convert(implib, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + implib, cmOutputConverter::START_OUTPUT)); } } // List the PDB for cleaning only when the whole target is // cleaned. We do not want to delete the .pdb file just before // linking the target. - this->CleanFiles.push_back(this->Convert(targetFullPathPDB, - cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + this->CleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + targetFullPathPDB, cmOutputConverter::START_OUTPUT)); #ifdef _WIN32 // There may be a manifest file for this target. Add it to the // clean set just in case. if (this->GeneratorTarget->GetType() != cmState::STATIC_LIBRARY) { - libCleanFiles.push_back(this->Convert( - (targetFullPath + ".manifest").c_str(), cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED)); + libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + (targetFullPath + ".manifest").c_str(), + cmOutputConverter::START_OUTPUT)); } #endif diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index dd4333d..2d53669 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -172,8 +172,8 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() const std::vector& outputs = ccg.GetOutputs(); for (std::vector::const_iterator o = outputs.begin(); o != outputs.end(); ++o) { - this->CleanFiles.push_back(this->Convert( - *o, cmOutputConverter::START_OUTPUT, cmOutputConverter::UNCHANGED)); + this->CleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( + *o, cmOutputConverter::START_OUTPUT)); } } } @@ -1258,9 +1258,8 @@ void cmMakefileTargetGenerator::WriteTargetDriverRule( this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget); std::string buildTargetRuleName = dir; buildTargetRuleName += relink ? "/preinstall" : "/build"; - buildTargetRuleName = - this->Convert(buildTargetRuleName, cmOutputConverter::HOME_OUTPUT, - cmOutputConverter::UNCHANGED); + buildTargetRuleName = this->LocalGenerator->ConvertToRelativePath( + buildTargetRuleName, cmOutputConverter::HOME_OUTPUT); // Build the list of target outputs to drive. std::vector depends; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 1b1d04b..216de03 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2416,9 +2416,8 @@ void cmVisualStudio10TargetGenerator::AddLibraries( ItemVector libs = cli.GetItems(); for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) { if (l->IsPath) { - std::string path = this->LocalGenerator->Convert( - l->Value.c_str(), cmOutputConverter::START_OUTPUT, - cmOutputConverter::UNCHANGED); + std::string path = this->LocalGenerator->ConvertToRelativePath( + l->Value.c_str(), cmOutputConverter::START_OUTPUT); this->ConvertToWindowsSlash(path); libVec.push_back(path); } else if (!l->Target || https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=564d3a1dc8e19f16db6ddccca38e21d89634c1b4 commit 564d3a1dc8e19f16db6ddccca38e21d89634c1b4 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:56 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:37 2016 +0200 Convert: Extract ConvertToRelativePath from Convert() Convert() does some kind of relative conversion, followed by a conversion to 'output format'. Make it possible to do the former without the latter. diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 80fa4bf..176c9a0 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -46,11 +46,9 @@ std::string cmOutputConverter::ConvertToOutputForExisting( return this->ConvertToOutputFormat(remote, format); } -std::string cmOutputConverter::Convert(const std::string& source, - RelativeRoot relative, - OutputFormat output) const +std::string cmOutputConverter::ConvertToRelativePath( + const std::string& source, RelativeRoot relative) const { - // Convert the path to a relative path. std::string result = source; switch (relative) { @@ -76,6 +74,15 @@ std::string cmOutputConverter::Convert(const std::string& source, result = cmSystemTools::CollapseFullPath(result); break; } + return result; +} + +std::string cmOutputConverter::Convert(const std::string& source, + RelativeRoot relative, + OutputFormat output) const +{ + // Convert the path to a relative path. + std::string result = this->ConvertToRelativePath(source, relative); return this->ConvertToOutputFormat(result, output); } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 0f4884e..71bb086 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -56,6 +56,8 @@ public: OutputFormat output) const; std::string Convert(const std::string& remote, RelativeRoot local, OutputFormat output = UNCHANGED) const; + std::string ConvertToRelativePath(const std::string& remote, + RelativeRoot local) const; std::string ConvertDirectorySeparatorsForShell( const std::string& source) const; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=95a659f1801701b02528c22f0287bb57056dc627 commit 95a659f1801701b02528c22f0287bb57056dc627 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:55 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:37 2016 +0200 Convert: Replace FULL conversions with equivalent diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 2e08417..756db2e 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1067,8 +1067,7 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand( cleanfile += filename; } cleanfile += ".cmake"; - std::string cleanfilePath = - this->Convert(cleanfile, cmOutputConverter::FULL); + std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile); cmsys::ofstream fout(cleanfilePath.c_str()); if (!fout) { cmSystemTools::Error("Could not create ", cleanfilePath.c_str()); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 7747aa7..dd4333d 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -393,9 +393,9 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( std::string objFullPath = this->LocalGenerator->GetCurrentBinaryDirectory(); objFullPath += "/"; objFullPath += obj; - objFullPath = this->Convert(objFullPath, cmOutputConverter::FULL); + objFullPath = cmSystemTools::CollapseFullPath(objFullPath); std::string srcFullPath = - this->Convert(source.GetFullPath(), cmOutputConverter::FULL); + cmSystemTools::CollapseFullPath(source.GetFullPath()); this->LocalGenerator->AddImplicitDepends( this->GeneratorTarget, lang, objFullPath.c_str(), srcFullPath.c_str()); } @@ -584,9 +584,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( lang_can_export_cmds && compileCommands.size() == 1) { std::string compileCommand = compileCommands[0]; this->LocalGenerator->ExpandRuleVariables(compileCommand, vars); - std::string workingDirectory = this->LocalGenerator->Convert( - this->LocalGenerator->GetCurrentBinaryDirectory(), - cmOutputConverter::FULL); + std::string workingDirectory = cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetCurrentBinaryDirectory()); compileCommand.replace(compileCommand.find(langFlags), langFlags.size(), this->GetFlags(lang)); std::string langDefines = std::string("$(") + lang + "_DEFINES)"; @@ -1115,10 +1114,8 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile( for (cmCustomCommand::ImplicitDependsList::const_iterator idi = ccg.GetCC().GetImplicitDepends().begin(); idi != ccg.GetCC().GetImplicitDepends().end(); ++idi) { - std::string objFullPath = - this->Convert(outputs[0], cmOutputConverter::FULL); - std::string srcFullPath = - this->Convert(idi->second, cmOutputConverter::FULL); + std::string objFullPath = cmSystemTools::CollapseFullPath(outputs[0]); + std::string srcFullPath = cmSystemTools::CollapseFullPath(idi->second); this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, idi->first, objFullPath.c_str(), srcFullPath.c_str()); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a8c7ccb1839d912edc972384de6641f3c17ad8ff commit a8c7ccb1839d912edc972384de6641f3c17ad8ff Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:55 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:37 2016 +0200 VS: Replace FULL/UNCHANGED conversion with equivalent diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index e72abe9..497defb 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -278,8 +278,8 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() cmCustomCommandLines commandLines; commandLines.push_back(commandLine); const char* no_working_directory = 0; - std::string fullpathStampName = this->Convert( - stampName.c_str(), cmOutputConverter::FULL, cmOutputConverter::UNCHANGED); + std::string fullpathStampName = + cmSystemTools::CollapseFullPath(stampName.c_str()); this->Makefile->AddCustomCommandToOutput( fullpathStampName.c_str(), listFiles, makefileIn.c_str(), commandLines, comment.c_str(), no_working_directory, true); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5ad25ef4b690252a4251e8824e00b053ea61d000 commit 5ad25ef4b690252a4251e8824e00b053ea61d000 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:55 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:37 2016 +0200 Convert: Remove NONE conversion It is no longer used. diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 98872d6..80fa4bf 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -75,8 +75,6 @@ std::string cmOutputConverter::Convert(const std::string& source, case FULL: result = cmSystemTools::CollapseFullPath(result); break; - case NONE: - break; } return this->ConvertToOutputFormat(result, output); } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index ff06ab6..0f4884e 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -38,7 +38,6 @@ public: */ enum RelativeRoot { - NONE, FULL, HOME, START, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ac46384171c54a0fb9c47c32642fbca4ff1e925b commit ac46384171c54a0fb9c47c32642fbca4ff1e925b Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:55 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:26:36 2016 +0200 Convert: Replace uses of Convert(NONE) These are equivalent to ConvertToOutputFormat. diff --git a/Source/cmLocalCommonGenerator.cxx b/Source/cmLocalCommonGenerator.cxx index 5502296..1383421 100644 --- a/Source/cmLocalCommonGenerator.cxx +++ b/Source/cmLocalCommonGenerator.cxx @@ -74,8 +74,7 @@ std::string cmLocalCommonGenerator::GetTargetFortranFlags( for (std::vector::const_iterator idi = includes.begin(); idi != includes.end(); ++idi) { std::string flg = modpath_flag; - flg += - this->Convert(*idi, cmOutputConverter::NONE, cmOutputConverter::SHELL); + flg += this->ConvertToOutputFormat(*idi, cmOutputConverter::SHELL); this->AppendFlags(flags, flg); } } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index d8f6bdf..20a1e21 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1393,7 +1393,7 @@ std::string cmLocalGenerator::ConvertToLinkReference(std::string const& lib, sp += lib.substr(pos); // Convert to an output path. - return this->Convert(sp.c_str(), NONE, format); + return this->ConvertToOutputFormat(sp.c_str(), format); } } } @@ -1489,7 +1489,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, for (std::vector::const_iterator fdi = fwDirs.begin(); fdi != fwDirs.end(); ++fdi) { frameworkPath += fwSearchFlag; - frameworkPath += this->Convert(*fdi, NONE, shellFormat); + frameworkPath += this->ConvertToOutputFormat(*fdi, shellFormat); frameworkPath += " "; } } @@ -1535,7 +1535,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, for (std::vector::iterator ri = runtimeDirs.begin(); ri != runtimeDirs.end(); ++ri) { rpath += cli.GetRuntimeFlag(); - rpath += this->Convert(*ri, NONE, shellFormat); + rpath += this->ConvertToOutputFormat(*ri, shellFormat); rpath += " "; } fout << rpath; @@ -1605,7 +1605,7 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags, flags += " "; flags += sysrootFlag; flags += " "; - flags += this->Convert(sysroot, NONE, SHELL); + flags += this->ConvertToOutputFormat(sysroot, SHELL); } if (deploymentTargetFlag && *deploymentTargetFlag && deploymentTarget && diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 58c336d..8c092e7 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -490,8 +490,8 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher( output = this->Convert(outputs[0], cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); } else { - output = this->Convert(outputs[0], cmOutputConverter::NONE, - cmOutputConverter::SHELL); + output = + this->ConvertToOutputFormat(outputs[0], cmOutputConverter::SHELL); } } vars.Output = output.c_str(); diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 917d8d5..2e08417 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -602,8 +602,7 @@ std::string cmLocalUnixMakefileGenerator3::MaybeConvertWatcomShellCommand( // lines with shell redirection operators. std::string scmd; if (cmSystemTools::GetShortPath(cmd, scmd)) { - return this->Convert(scmd, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + return this->ConvertToOutputFormat(scmd, cmOutputConverter::SHELL); } } return std::string(); @@ -790,8 +789,8 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom( std::string runRule = "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; runRule += " --check-build-system "; - runRule += this->Convert(cmakefileName, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + runRule += + this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); runRule += " 0"; std::vector no_depends; @@ -995,8 +994,8 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( cmOutputConverter::SHELL); } else { - output = this->Convert(outputs[0], cmOutputConverter::NONE, - cmOutputConverter::SHELL); + output = this->ConvertToOutputFormat(outputs[0], + cmOutputConverter::SHELL); } } vars.Output = output.c_str(); @@ -1009,8 +1008,8 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( std::string shellCommand = this->MaybeConvertWatcomShellCommand(cmd); if (shellCommand.empty()) { - shellCommand = this->Convert(cmd, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + shellCommand = + this->ConvertToOutputFormat(cmd, cmOutputConverter::SHELL); } cmd = launcher + shellCommand; @@ -1681,8 +1680,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( std::string runRule = "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; runRule += " --check-build-system "; - runRule += this->Convert(cmakefileName, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + runRule += + this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); runRule += " 1"; commands.push_back(runRule); this->CreateCDCommand(commands, this->GetBinaryDirectory(), @@ -1895,8 +1894,7 @@ std::string cmLocalUnixMakefileGenerator3::GetRecursiveMakeCall( // Call make on the given file. std::string cmd; cmd += "$(MAKE) -f "; - cmd += - this->Convert(makefile, cmOutputConverter::NONE, cmOutputConverter::SHELL); + cmd += this->ConvertToOutputFormat(makefile, cmOutputConverter::SHELL); cmd += " "; cmGlobalUnixMakefileGenerator3* gg = diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index ca006b7..d1cefe3 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -205,7 +205,7 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( if (workingDirectory.empty()) { script += this->Convert(cmd.c_str(), START_OUTPUT, SHELL); } else { - script += this->Convert(cmd.c_str(), NONE, SHELL); + script += this->ConvertToOutputFormat(cmd.c_str(), SHELL); } ccg.AppendArguments(c, script); diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 74bfedc..a14df79 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -135,8 +135,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) std::string targetFullPathReal = outpath + targetNameReal; std::string targetFullPathPDB = pdbOutputPath + targetNamePDB; std::string targetFullPathImport = outpathImp + targetNameImport; - std::string targetOutPathPDB = this->Convert( - targetFullPathPDB, cmOutputConverter::NONE, cmOutputConverter::SHELL); + std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( + targetFullPathPDB, cmOutputConverter::SHELL); // Convert to the output path to use in constructing commands. std::string targetOutPath = this->Convert( targetFullPath, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); @@ -357,9 +357,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) vars.Manifests = manifests.c_str(); if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE")) { - std::string cmakeCommand = - this->Convert(cmSystemTools::GetCMakeCommand(), cmLocalGenerator::NONE, - cmLocalGenerator::SHELL); + std::string cmakeCommand = this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); cmakeCommand += " -E __run_iwyu --lwyu="; cmakeCommand += targetOutPathReal; real_link_commands.push_back(cmakeCommand); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 6727bd0..c8ee05f 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -310,8 +310,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // Construct the output path version of the names for use in command // arguments. - std::string targetOutPathPDB = this->Convert( - targetFullPathPDB, cmOutputConverter::NONE, cmOutputConverter::SHELL); + std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( + targetFullPathPDB, cmOutputConverter::SHELL); std::string targetOutPath = this->Convert( targetFullPath, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); std::string targetOutPathSO = @@ -572,8 +572,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( vars.TargetInstallNameDir = ""; } else { // Convert to a path for the native build tool. - install_name_dir = this->LocalGenerator->Convert( - install_name_dir, cmOutputConverter::NONE, cmOutputConverter::SHELL); + install_name_dir = this->LocalGenerator->ConvertToOutputFormat( + install_name_dir, cmOutputConverter::SHELL); vars.TargetInstallNameDir = install_name_dir.c_str(); } } @@ -640,9 +640,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( cmSystemTools::ExpandListArgument(linkRule, real_link_commands); if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE") && (this->GeneratorTarget->GetType() == cmState::SHARED_LIBRARY)) { - std::string cmakeCommand = - this->Convert(cmSystemTools::GetCMakeCommand(), - cmLocalGenerator::NONE, cmLocalGenerator::SHELL); + std::string cmakeCommand = this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); cmakeCommand += " -E __run_iwyu --lwyu="; cmakeCommand += targetOutPathReal; real_link_commands.push_back(cmakeCommand); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 5bba29c..7747aa7 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -324,11 +324,11 @@ void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()( this->Generator->LocalGenerator->AppendEcho( commands, copyEcho, cmLocalUnixMakefileGenerator3::EchoBuild); std::string copyCommand = "$(CMAKE_COMMAND) -E copy "; - copyCommand += this->Generator->Convert(input, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + copyCommand += this->Generator->LocalGenerator->ConvertToOutputFormat( + input, cmOutputConverter::SHELL); copyCommand += " "; - copyCommand += this->Generator->Convert(output, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + copyCommand += this->Generator->LocalGenerator->ConvertToOutputFormat( + output, cmOutputConverter::SHELL); commands.push_back(copyCommand); this->Generator->LocalGenerator->WriteMakeRule( *this->Generator->BuildFileStream, CM_NULLPTR, output, depends, commands, @@ -464,8 +464,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( } // Get the output paths for source and object files. - std::string sourceFile = this->Convert( - source.GetFullPath(), cmOutputConverter::NONE, cmOutputConverter::SHELL); + std::string sourceFile = this->LocalGenerator->ConvertToOutputFormat( + source.GetFullPath(), cmOutputConverter::SHELL); // Construct the build message. std::vector no_commands; @@ -516,8 +516,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( targetOutPathReal = this->Convert(targetFullPathReal, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); - targetOutPathPDB = this->Convert( - targetFullPathPDB, cmOutputConverter::NONE, cmOutputConverter::SHELL); + targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( + targetFullPathPDB, cmOutputConverter::SHELL); targetOutPathCompilePDB = this->Convert(targetFullPathCompilePDB, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); @@ -539,7 +539,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( vars.TargetCompilePDB = targetOutPathCompilePDB.c_str(); vars.Source = sourceFile.c_str(); std::string shellObj = - this->Convert(obj, cmOutputConverter::NONE, cmOutputConverter::SHELL); + this->LocalGenerator->ConvertToOutputFormat(obj, cmOutputConverter::SHELL); vars.Object = shellObj.c_str(); std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); objectDir = this->Convert(objectDir, cmOutputConverter::START_OUTPUT, @@ -699,8 +699,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( std::vector preprocessCommands; cmSystemTools::ExpandListArgument(preprocessRule, preprocessCommands); - std::string shellObjI = this->Convert(objI, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + std::string shellObjI = this->LocalGenerator->ConvertToOutputFormat( + objI, cmOutputConverter::SHELL); vars.PreprocessedSource = shellObjI.c_str(); // Expand placeholders in the commands. @@ -746,8 +746,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( std::vector assemblyCommands; cmSystemTools::ExpandListArgument(assemblyRule, assemblyCommands); - std::string shellObjS = this->Convert(objS, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + std::string shellObjS = this->LocalGenerator->ConvertToOutputFormat( + objS, cmOutputConverter::SHELL); vars.AssemblySource = shellObjS.c_str(); // Expand placeholders in the commands. @@ -1576,8 +1576,8 @@ void cmMakefileTargetGenerator::CreateLinkLibs( // Reference the response file. linkLibs = responseFlag; - linkLibs += this->Convert(link_rsp, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + linkLibs += this->LocalGenerator->ConvertToOutputFormat( + link_rsp, cmOutputConverter::SHELL); } } @@ -1625,8 +1625,8 @@ void cmMakefileTargetGenerator::CreateObjectLists( // Reference the response file. buildObjs += responseFlag; - buildObjs += this->Convert(objects_rsp, cmOutputConverter::NONE, - cmOutputConverter::SHELL); + buildObjs += this->LocalGenerator->ConvertToOutputFormat( + objects_rsp, cmOutputConverter::SHELL); } } else if (useLinkScript) { if (!useArchiveRules) { @@ -1683,8 +1683,8 @@ void cmMakefileTargetGenerator::GenDefFile( name_of_def_file += std::string("/") + this->GeneratorTarget->GetName(); name_of_def_file += ".def"; std::string cmd = cmSystemTools::GetCMakeCommand(); - cmd = - this->Convert(cmd, cmOutputConverter::NONE, cmOutputConverter::SHELL); + cmd = this->LocalGenerator->ConvertToOutputFormat( + cmd, cmOutputConverter::SHELL); cmd += " -E __create_def "; cmd += this->Convert(name_of_def_file, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index d0db133..335b552 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -543,8 +543,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() std::string install_dir = this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName); if (!install_dir.empty()) { - vars["INSTALLNAME_DIR"] = localGen.Convert( - install_dir, cmOutputConverter::NONE, cmOutputConverter::SHELL); + vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat( + install_dir, cmOutputConverter::SHELL); } } } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=998d9ee967f6795c71ff23cf16601f7e974b21ba commit 998d9ee967f6795c71ff23cf16601f7e974b21ba Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:54 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:21:24 2016 +0200 VS: Replace variable with an if() diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index bdb1c2b..ca006b7 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -127,7 +127,6 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( { bool useLocal = this->CustomCommandUseLocal(); std::string workingDirectory = ccg.GetWorkingDirectory(); - RelativeRoot relativeRoot = workingDirectory.empty() ? START_OUTPUT : NONE; // Avoid leading or trailing newlines. std::string newline = ""; @@ -203,7 +202,11 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( } } - script += this->Convert(cmd.c_str(), relativeRoot, SHELL); + if (workingDirectory.empty()) { + script += this->Convert(cmd.c_str(), START_OUTPUT, SHELL); + } else { + script += this->Convert(cmd.c_str(), NONE, SHELL); + } ccg.AppendArguments(c, script); // After each custom command, check for an error result. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ee49f006cf657fa6f1c2d112f44d762441fd5cf1 commit ee49f006cf657fa6f1c2d112f44d762441fd5cf1 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:54 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:21:24 2016 +0200 Makefiles: Replace ternaries with if()s diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 46d7e18..58c336d 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -486,12 +486,13 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher( std::string output; const std::vector& outputs = ccg.GetOutputs(); if (!outputs.empty()) { - cmOutputConverter::RelativeRoot relative_root = - ccg.GetWorkingDirectory().empty() ? cmOutputConverter::START_OUTPUT - : cmOutputConverter::NONE; - - output = - this->Convert(outputs[0], relative_root, cmOutputConverter::SHELL); + if (ccg.GetWorkingDirectory().empty()) { + output = this->Convert(outputs[0], cmOutputConverter::START_OUTPUT, + cmOutputConverter::SHELL); + } else { + output = this->Convert(outputs[0], cmOutputConverter::NONE, + cmOutputConverter::SHELL); + } } vars.Output = output.c_str(); diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 53c9aa1..917d8d5 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -990,10 +990,14 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( std::string output; const std::vector& outputs = ccg.GetOutputs(); if (!outputs.empty()) { - output = this->Convert(outputs[0], workingDir.empty() - ? cmOutputConverter::START_OUTPUT - : cmOutputConverter::NONE, - cmOutputConverter::SHELL); + if (workingDir.empty()) { + output = this->Convert(outputs[0], cmOutputConverter::START_OUTPUT, + cmOutputConverter::SHELL); + + } else { + output = this->Convert(outputs[0], cmOutputConverter::NONE, + cmOutputConverter::SHELL); + } } vars.Output = output.c_str(); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=51f7dcb0a55874e71e4695f5154548a41c87ad56 commit 51f7dcb0a55874e71e4695f5154548a41c87ad56 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:54 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:21:24 2016 +0200 Makefiles: Inline MakeLauncher into only caller diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 53c2ff6..53c9aa1 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -976,9 +976,33 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( // without the current directory being in the search path. cmd = "./" + cmd; } - std::string launcher = this->MakeLauncher( - ccg, target, workingDir.empty() ? cmOutputConverter::START_OUTPUT - : cmOutputConverter::NONE); + + std::string launcher; + // Short-circuit if there is no launcher. + const char* prop = "RULE_LAUNCH_CUSTOM"; + const char* val = this->GetRuleLauncher(target, prop); + if (val && *val) { + // Expand rules in the empty string. It may insert the launcher and + // perform replacements. + RuleVariables vars; + vars.RuleLauncher = prop; + vars.CMTarget = target; + std::string output; + const std::vector& outputs = ccg.GetOutputs(); + if (!outputs.empty()) { + output = this->Convert(outputs[0], workingDir.empty() + ? cmOutputConverter::START_OUTPUT + : cmOutputConverter::NONE, + cmOutputConverter::SHELL); + } + vars.Output = output.c_str(); + + this->ExpandRuleVariables(launcher, vars); + if (!launcher.empty()) { + launcher += " "; + } + } + std::string shellCommand = this->MaybeConvertWatcomShellCommand(cmd); if (shellCommand.empty()) { shellCommand = this->Convert(cmd, cmOutputConverter::NONE, @@ -1027,35 +1051,6 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( commands.insert(commands.end(), commands1.begin(), commands1.end()); } -std::string cmLocalUnixMakefileGenerator3::MakeLauncher( - cmCustomCommandGenerator const& ccg, cmGeneratorTarget* target, - cmOutputConverter::RelativeRoot relative) -{ - std::string launcher; - // Short-circuit if there is no launcher. - const char* prop = "RULE_LAUNCH_CUSTOM"; - const char* val = this->GetRuleLauncher(target, prop); - if (val && *val) { - // Expand rules in the empty string. It may insert the launcher and - // perform replacements. - RuleVariables vars; - vars.RuleLauncher = prop; - vars.CMTarget = target; - std::string output; - const std::vector& outputs = ccg.GetOutputs(); - if (!outputs.empty()) { - output = this->Convert(outputs[0], relative, cmOutputConverter::SHELL); - } - vars.Output = output.c_str(); - - this->ExpandRuleVariables(launcher, vars); - if (!launcher.empty()) { - launcher += " "; - } - } - return launcher; -} - void cmLocalUnixMakefileGenerator3::AppendCleanCommand( std::vector& commands, const std::vector& files, cmGeneratorTarget* target, const char* filename) diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index ea98607..3e90055 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -251,9 +251,6 @@ protected: private: std::string MaybeConvertWatcomShellCommand(std::string const& cmd); - std::string MakeLauncher(cmCustomCommandGenerator const& ccg, - cmGeneratorTarget* target, - cmOutputConverter::RelativeRoot relative); void ComputeObjectFilenames( std::map& mapping, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ba4ba7c39de82b805652efbb7dc5e1659c53f36b commit ba4ba7c39de82b805652efbb7dc5e1659c53f36b Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:54 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:21:24 2016 +0200 Makefiles: Simplify MakeLauncher return value Bonus NRVO. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 47b891f..53c2ff6 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1031,6 +1031,7 @@ std::string cmLocalUnixMakefileGenerator3::MakeLauncher( cmCustomCommandGenerator const& ccg, cmGeneratorTarget* target, cmOutputConverter::RelativeRoot relative) { + std::string launcher; // Short-circuit if there is no launcher. const char* prop = "RULE_LAUNCH_CUSTOM"; const char* val = this->GetRuleLauncher(target, prop); @@ -1047,14 +1048,12 @@ std::string cmLocalUnixMakefileGenerator3::MakeLauncher( } vars.Output = output.c_str(); - std::string launcher; this->ExpandRuleVariables(launcher, vars); if (!launcher.empty()) { launcher += " "; } - return launcher; } - return ""; + return launcher; } void cmLocalUnixMakefileGenerator3::AppendCleanCommand( https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e804d410cd4e391cd81ff3d8981cfba1fae28742 commit e804d410cd4e391cd81ff3d8981cfba1fae28742 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:54 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:21:23 2016 +0200 Makefiles: Invert logic in MakeLauncher Make it easier to inline into the caller. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index e148887..47b891f 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1034,28 +1034,27 @@ std::string cmLocalUnixMakefileGenerator3::MakeLauncher( // Short-circuit if there is no launcher. const char* prop = "RULE_LAUNCH_CUSTOM"; const char* val = this->GetRuleLauncher(target, prop); - if (!(val && *val)) { - return ""; - } - - // Expand rules in the empty string. It may insert the launcher and - // perform replacements. - RuleVariables vars; - vars.RuleLauncher = prop; - vars.CMTarget = target; - std::string output; - const std::vector& outputs = ccg.GetOutputs(); - if (!outputs.empty()) { - output = this->Convert(outputs[0], relative, cmOutputConverter::SHELL); - } - vars.Output = output.c_str(); + if (val && *val) { + // Expand rules in the empty string. It may insert the launcher and + // perform replacements. + RuleVariables vars; + vars.RuleLauncher = prop; + vars.CMTarget = target; + std::string output; + const std::vector& outputs = ccg.GetOutputs(); + if (!outputs.empty()) { + output = this->Convert(outputs[0], relative, cmOutputConverter::SHELL); + } + vars.Output = output.c_str(); - std::string launcher; - this->ExpandRuleVariables(launcher, vars); - if (!launcher.empty()) { - launcher += " "; + std::string launcher; + this->ExpandRuleVariables(launcher, vars); + if (!launcher.empty()) { + launcher += " "; + } + return launcher; } - return launcher; + return ""; } void cmLocalUnixMakefileGenerator3::AppendCleanCommand( https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2722c4dcc55605b7946f3c9bfa4b2fe5ce4161cb commit 2722c4dcc55605b7946f3c9bfa4b2fe5ce4161cb Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:53 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:21:14 2016 +0200 Makefiles: Remove useless use of Convert Convert with NONE and UNCHANGED is a no-op. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index f026b12..e148887 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -835,8 +835,7 @@ std::string cmLocalUnixMakefileGenerator3::GetRelativeTargetDirectory( { std::string dir = this->HomeRelativeOutputPath; dir += this->GetTargetDirectory(target); - return this->Convert(dir, cmOutputConverter::NONE, - cmOutputConverter::UNCHANGED); + return dir; } void cmLocalUnixMakefileGenerator3::AppendFlags(std::string& flags, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=112c87b28afac71617bcbb552ae1f2027bb548b6 commit 112c87b28afac71617bcbb552ae1f2027bb548b6 Author: Stephen Kelly AuthorDate: Sat Aug 27 13:44:53 2016 +0200 Commit: Stephen Kelly CommitDate: Sat Aug 27 15:16:50 2016 +0200 Makefiles: Replace method with Wacom specific API The existing method uses RelativeRoot NONE and FULL values. In principle, those should be segregated interfaces. Mixing NONE and FULL into the RelativeRoot enum is a case of http://thedailywtf.com/articles/What_Is_Truth_0x3f_ diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index f2ef5c8..f026b12 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -592,8 +592,8 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule( } } -std::string cmLocalUnixMakefileGenerator3::ConvertShellCommand( - std::string const& cmd, cmOutputConverter::RelativeRoot root) +std::string cmLocalUnixMakefileGenerator3::MaybeConvertWatcomShellCommand( + std::string const& cmd) { if (this->IsWatcomWMake() && cmSystemTools::FileIsFullPath(cmd.c_str()) && cmd.find_first_of("( )") != cmd.npos) { @@ -606,7 +606,7 @@ std::string cmLocalUnixMakefileGenerator3::ConvertShellCommand( cmOutputConverter::SHELL); } } - return this->Convert(cmd, root, cmOutputConverter::SHELL); + return std::string(); } void cmLocalUnixMakefileGenerator3::WriteMakeVariables( @@ -638,8 +638,13 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( #endif } - std::string cmakeShellCommand = this->ConvertShellCommand( - cmSystemTools::GetCMakeCommand(), cmOutputConverter::FULL); + std::string cmakeShellCommand = + this->MaybeConvertWatcomShellCommand(cmSystemTools::GetCMakeCommand()); + if (cmakeShellCommand.empty()) { + cmakeShellCommand = + this->Convert(cmSystemTools::GetCMakeCommand(), cmOutputConverter::FULL, + cmOutputConverter::SHELL); + } /* clang-format off */ makefileStream @@ -975,7 +980,12 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( std::string launcher = this->MakeLauncher( ccg, target, workingDir.empty() ? cmOutputConverter::START_OUTPUT : cmOutputConverter::NONE); - cmd = launcher + this->ConvertShellCommand(cmd, cmOutputConverter::NONE); + std::string shellCommand = this->MaybeConvertWatcomShellCommand(cmd); + if (shellCommand.empty()) { + shellCommand = this->Convert(cmd, cmOutputConverter::NONE, + cmOutputConverter::SHELL); + } + cmd = launcher + shellCommand; ccg.AppendArguments(c, cmd); if (content) { diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index 243cc3d..ea98607 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -250,8 +250,7 @@ protected: void CheckMultipleOutputs(bool verbose); private: - std::string ConvertShellCommand(std::string const& cmd, - cmOutputConverter::RelativeRoot root); + std::string MaybeConvertWatcomShellCommand(std::string const& cmd); std::string MakeLauncher(cmCustomCommandGenerator const& ccg, cmGeneratorTarget* target, cmOutputConverter::RelativeRoot relative); ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 30 09:29:42 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 30 Aug 2016 09:29:42 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-754-g918cb5b Message-ID: <20160830132942.6D1E4F5945@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 918cb5b1f095cc05a8823fa218a59edf0e536384 (commit) via 048d1adb4ede50e49dce00873a5961e424e149f9 (commit) from 57d121fbb1f2e9e2ac0622dd4049dedc3968d894 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=918cb5b1f095cc05a8823fa218a59edf0e536384 commit 918cb5b1f095cc05a8823fa218a59edf0e536384 Merge: 57d121f 048d1ad Author: Brad King AuthorDate: Tue Aug 30 09:29:40 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 30 09:29:40 2016 -0400 Merge topic 'ninja-add_custom_command-depfile' 048d1adb add_custom_command: Add DEPFILE option for Ninja ----------------------------------------------------------------------- Summary of changes: Help/command/add_custom_command.rst | 7 +++++++ .../dev/ninja-add_custom_command-depfile.rst | 6 ++++++ Source/cmAddCustomCommandCommand.cxx | 19 ++++++++++++++++--- Source/cmCustomCommand.cxx | 10 ++++++++++ Source/cmCustomCommand.h | 5 +++++ Source/cmGlobalNinjaGenerator.cxx | 10 ++++++---- Source/cmGlobalNinjaGenerator.h | 3 ++- Source/cmLocalNinjaGenerator.cxx | 3 ++- Source/cmMakefile.cxx | 10 ++++++---- Source/cmMakefile.h | 18 ++++++++---------- Source/cmNinjaUtilityTargetGenerator.cxx | 2 +- .../CustomCommandDepfile-ERROR-result.txt} | 0 .../Make/CustomCommandDepfile-ERROR-stderr.txt | 5 +++++ .../CustomCommandDepfile-ERROR.cmake} | 7 +------ Tests/RunCMake/Make/RunCMakeTest.cmake | 2 ++ .../RunCMake/Ninja/CustomCommandDepfile-check.cmake | 5 +++++ ...ngDirectory.cmake => CustomCommandDepfile.cmake} | 4 +--- Tests/RunCMake/Ninja/RunCMakeTest.cmake | 2 ++ 18 files changed, 85 insertions(+), 33 deletions(-) create mode 100644 Help/release/dev/ninja-add_custom_command-depfile.rst copy Tests/RunCMake/{Android/BadSYSROOT-result.txt => Make/CustomCommandDepfile-ERROR-result.txt} (100%) create mode 100644 Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt copy Tests/RunCMake/{Ninja/CustomCommandWorkingDirectory.cmake => Make/CustomCommandDepfile-ERROR.cmake} (54%) create mode 100644 Tests/RunCMake/Ninja/CustomCommandDepfile-check.cmake copy Tests/RunCMake/Ninja/{CustomCommandWorkingDirectory.cmake => CustomCommandDepfile.cmake} (84%) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 30 09:29:45 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 30 Aug 2016 09:29:45 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-756-g388a409 Message-ID: <20160830132945.24439F57CE@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 388a40942bbe87206547bd9eb27273f80ef2aa9f (commit) via 38995d19b806e8cc1d43fab0422beefd4c23431f (commit) from 918cb5b1f095cc05a8823fa218a59edf0e536384 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=388a40942bbe87206547bd9eb27273f80ef2aa9f commit 388a40942bbe87206547bd9eb27273f80ef2aa9f Merge: 918cb5b 38995d1 Author: Brad King AuthorDate: Tue Aug 30 09:29:43 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 30 09:29:43 2016 -0400 Merge topic 'code-blocks-include-order' 38995d19 CodeBlocks: List C++ includes first ----------------------------------------------------------------------- Summary of changes: Source/cmExtraCodeBlocksGenerator.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 30 09:29:52 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 30 Aug 2016 09:29:52 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-758-gef58e97 Message-ID: <20160830132952.2EEEDF593A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via ef58e97362d10877780aed7b6806dd02ce2f4303 (commit) via 1f4aeb1739fb632ab5162a977764b51736728edc (commit) from 388a40942bbe87206547bd9eb27273f80ef2aa9f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ef58e97362d10877780aed7b6806dd02ce2f4303 commit ef58e97362d10877780aed7b6806dd02ce2f4303 Merge: 388a409 1f4aeb1 Author: Brad King AuthorDate: Tue Aug 30 09:29:49 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 30 09:29:49 2016 -0400 Merge topic 'vs-NsightTegra-empty-version' 1f4aeb17 VS: Fix out-of-bounds write on empty Nsight Tegra version ----------------------------------------------------------------------- Summary of changes: Source/cmVisualStudio10TargetGenerator.cxx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 30 09:29:55 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 30 Aug 2016 09:29:55 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-787-ge3a4c2e Message-ID: <20160830132955.AA9D7F57AC@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via e3a4c2e02ceacd302e8bc6a7dc1bc02b29ab2cfc (commit) via 4332131dcca03b262e0dd51352eb2e27522887c8 (commit) via 5aca066c5bbb7263624eb140378dd2f49e9d80ec (commit) via 146bf9267ca88831d7cff4d121f414a3a73e26de (commit) via 58ba87f892316b9f9cbb7851a940ec808527e36a (commit) via e80314d7a8208214ac85bf9b2e769a7e3b5aaa04 (commit) via 563ac22a1646f1287d1baac755e13cbe33c1fe7b (commit) via 08be47cf939c3adfe653809c46c7b23b7a912a39 (commit) via 564d3a1dc8e19f16db6ddccca38e21d89634c1b4 (commit) via 95a659f1801701b02528c22f0287bb57056dc627 (commit) via a8c7ccb1839d912edc972384de6641f3c17ad8ff (commit) via 5ad25ef4b690252a4251e8824e00b053ea61d000 (commit) via ac46384171c54a0fb9c47c32642fbca4ff1e925b (commit) via 998d9ee967f6795c71ff23cf16601f7e974b21ba (commit) via ee49f006cf657fa6f1c2d112f44d762441fd5cf1 (commit) via 51f7dcb0a55874e71e4695f5154548a41c87ad56 (commit) via ba4ba7c39de82b805652efbb7dc5e1659c53f36b (commit) via e804d410cd4e391cd81ff3d8981cfba1fae28742 (commit) via 2722c4dcc55605b7946f3c9bfa4b2fe5ce4161cb (commit) via 112c87b28afac71617bcbb552ae1f2027bb548b6 (commit) via cd351ef2c427284eea0ab494eba5d4f24bc0e050 (commit) via fbd83948675f4b1cb487d59390cfe1689f801fc0 (commit) via c341f4679ad00cb65c7660b474ddabd13d0ef498 (commit) via 6960516b6b053816313d2ff5ee4e9375a84829cb (commit) via e0fd2d0446101847dd40cfe4cc451667d04ddcd9 (commit) via ad70a236f4368c21c08bcd4ea4d28425176c4e17 (commit) via e3ca17e13b8d2aecc6d97ac800d65c6c35378a98 (commit) via 0bbdbd95c9515a4714ef1d57a17c7271bc4d1774 (commit) via 9440d5776bf48778d452e2d3a48d4e93d7b6f7a7 (commit) from ef58e97362d10877780aed7b6806dd02ce2f4303 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e3a4c2e02ceacd302e8bc6a7dc1bc02b29ab2cfc commit e3a4c2e02ceacd302e8bc6a7dc1bc02b29ab2cfc Merge: ef58e97 4332131 Author: Brad King AuthorDate: Tue Aug 30 09:29:53 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 30 09:29:53 2016 -0400 Merge topic 'cleanup-Convert' 4332131d Convert: Make variables a bit more clear 5aca066c Convert: Remove UNCHANGED enum value 146bf926 Convert: Remove 'FULL' conversion 58ba87f8 Convert: Replace Convert(FULL) with equivalent e80314d7 Ninja: Replace ternary with if() 563ac22a Convert: Replace trivial conversion with new method 08be47cf Convert: Replace UNCHANGED conversions with new API call 564d3a1d Convert: Extract ConvertToRelativePath from Convert() 95a659f1 Convert: Replace FULL conversions with equivalent a8c7ccb1 VS: Replace FULL/UNCHANGED conversion with equivalent 5ad25ef4 Convert: Remove NONE conversion ac463841 Convert: Replace uses of Convert(NONE) 998d9ee9 VS: Replace variable with an if() ee49f006 Makefiles: Replace ternaries with if()s 51f7dcb0 Makefiles: Inline MakeLauncher into only caller ba4ba7c3 Makefiles: Simplify MakeLauncher return value ... ----------------------------------------------------------------------- Summary of changes: Source/cmCommonTargetGenerator.h | 6 +- Source/cmDependsC.cxx | 4 +- Source/cmDependsFortran.cxx | 10 +- Source/cmExtraEclipseCDT4Generator.cxx | 4 +- Source/cmGlobalGenerator.cxx | 4 +- Source/cmGlobalNinjaGenerator.cxx | 6 +- Source/cmGlobalUnixMakefileGenerator3.cxx | 31 ++-- Source/cmGlobalVisualStudio7Generator.cxx | 3 +- Source/cmListFileCache.cxx | 6 +- Source/cmLocalCommonGenerator.cxx | 3 +- Source/cmLocalGenerator.cxx | 25 ++-- Source/cmLocalNinjaGenerator.cxx | 23 +-- Source/cmLocalUnixMakefileGenerator3.cxx | 191 ++++++++++++------------ Source/cmLocalUnixMakefileGenerator3.h | 28 ++-- Source/cmLocalVisualStudio7Generator.cxx | 26 ++-- Source/cmLocalVisualStudioGenerator.cxx | 10 +- Source/cmMakefileExecutableTargetGenerator.cxx | 49 +++--- Source/cmMakefileLibraryTargetGenerator.cxx | 63 ++++---- Source/cmMakefileTargetGenerator.cxx | 119 ++++++++------- Source/cmMakefileUtilityTargetGenerator.cxx | 4 +- Source/cmNinjaNormalTargetGenerator.cxx | 4 +- Source/cmOutputConverter.cxx | 81 ++-------- Source/cmOutputConverter.h | 19 +-- Source/cmTarget.cxx | 3 +- Source/cmVisualStudio10TargetGenerator.cxx | 5 +- 25 files changed, 343 insertions(+), 384 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 30 09:30:15 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 30 Aug 2016 09:30:15 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1604-g98c4931 Message-ID: <20160830133016.00FB5F5951@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 98c49311ea16241edfb240eced28628677cc18cb (commit) via e3a4c2e02ceacd302e8bc6a7dc1bc02b29ab2cfc (commit) via ef58e97362d10877780aed7b6806dd02ce2f4303 (commit) via 388a40942bbe87206547bd9eb27273f80ef2aa9f (commit) via 918cb5b1f095cc05a8823fa218a59edf0e536384 (commit) via 57d121fbb1f2e9e2ac0622dd4049dedc3968d894 (commit) via b38aa000334c35193140c6b544067b0b30d916c5 (commit) via 4ce52abc03e3fe5475a8dd22014b9a9eb00a184d (commit) via 897346032b33ebd033cda9bcb5d094f1c112f37d (commit) from 40b8e22e55c20d2ecf31fe51ebc22453ec28996f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=98c49311ea16241edfb240eced28628677cc18cb commit 98c49311ea16241edfb240eced28628677cc18cb Merge: 40b8e22 e3a4c2e Author: Brad King AuthorDate: Tue Aug 30 09:30:04 2016 -0400 Commit: Brad King CommitDate: Tue Aug 30 09:30:04 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 30 09:37:25 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 30 Aug 2016 09:37:25 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1608-gfdeb50d Message-ID: <20160830133725.599BCF5A33@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via fdeb50d6b51a8e189ebdb4da88b464cd981e0ad4 (commit) via a9cc3756b63bb064850b3d56e60edf755738fcaa (commit) via 7a64c3a1859fa90ee44909a412fafcbf7de6a6e7 (commit) via 38069fd6637b062806a812bbc490bd2ee3406913 (commit) from 98c49311ea16241edfb240eced28628677cc18cb (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=fdeb50d6b51a8e189ebdb4da88b464cd981e0ad4 commit fdeb50d6b51a8e189ebdb4da88b464cd981e0ad4 Merge: 98c4931 a9cc375 Author: Brad King AuthorDate: Tue Aug 30 09:37:24 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 30 09:37:24 2016 -0400 Merge topic 'import-libuv' into next a9cc3756 Revert "Do not build libuv on HP-UX" 7a64c3a1 Merge branch 'upstream-libuv' into import-libuv 38069fd6 libuv 2016-08-30 (897738b1) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a9cc3756b63bb064850b3d56e60edf755738fcaa commit a9cc3756b63bb064850b3d56e60edf755738fcaa Author: Brad King AuthorDate: Tue Aug 30 09:34:23 2016 -0400 Commit: Brad King CommitDate: Tue Aug 30 09:34:23 2016 -0400 Revert "Do not build libuv on HP-UX" This reverts commit f0a0e4559c17020101e3e0be18bac54e27a263cb. diff --git a/CMakeLists.txt b/CMakeLists.txt index aab8416..65876d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -484,9 +484,6 @@ int main(void) { return 0; } elseif(CYGWIN) # libuv does not support Cygwin set(CMAKE_USE_LIBUV 0) - elseif(CMAKE_SYSTEM_NAME STREQUAL "HP-UX") - # libuv does not support HP-UX - set(CMAKE_USE_LIBUV 0) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "sparc") # Disable until it can be ported. set(CMAKE_USE_LIBUV 0) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7a64c3a1859fa90ee44909a412fafcbf7de6a6e7 commit 7a64c3a1859fa90ee44909a412fafcbf7de6a6e7 Merge: 87ff791 38069fd Author: Brad King AuthorDate: Tue Aug 30 09:33:44 2016 -0400 Commit: Brad King CommitDate: Tue Aug 30 09:33:44 2016 -0400 Merge branch 'upstream-libuv' into import-libuv * upstream-libuv: libuv 2016-08-30 (897738b1) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=38069fd6637b062806a812bbc490bd2ee3406913 commit 38069fd6637b062806a812bbc490bd2ee3406913 Author: libuv upstream AuthorDate: Tue Aug 30 01:32:24 2016 -0400 Commit: Brad King CommitDate: Tue Aug 30 09:33:44 2016 -0400 libuv 2016-08-30 (897738b1) Code extracted from: https://github.com/libuv/libuv.git at commit 897738b160cd5950503a96c9fd5b1e9aab92b0ff (v1.x). diff --git a/include/pthread-barrier.h b/include/pthread-barrier.h index 68468ad..3e01705 100644 --- a/include/pthread-barrier.h +++ b/include/pthread-barrier.h @@ -39,7 +39,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 2 * sizeof(sem_t) + \ 2 * sizeof(unsigned int) - \ sizeof(void *) -#elif defined(__MVS__) +#else # define UV_BARRIER_STRUCT_PADDING 0 #endif diff --git a/src/unix/timer.c b/src/unix/timer.c index ca3ec3d..f46bdf4 100644 --- a/src/unix/timer.c +++ b/src/unix/timer.c @@ -31,8 +31,8 @@ static int timer_less_than(const struct heap_node* ha, const uv_timer_t* a; const uv_timer_t* b; - a = container_of(ha, const uv_timer_t, heap_node); - b = container_of(hb, const uv_timer_t, heap_node); + a = container_of(ha, uv_timer_t, heap_node); + b = container_of(hb, uv_timer_t, heap_node); if (a->timeout < b->timeout) return 1; @@ -135,7 +135,7 @@ int uv__next_timeout(const uv_loop_t* loop) { if (heap_node == NULL) return -1; /* block indefinitely */ - handle = container_of(heap_node, const uv_timer_t, heap_node); + handle = container_of(heap_node, uv_timer_t, heap_node); if (handle->timeout <= loop->time) return 0; diff --git a/src/win/tty.c b/src/win/tty.c index 9bb7879..0975b33 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -57,6 +57,9 @@ #define MAX_INPUT_BUFFER_LENGTH 8192 +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info); static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); @@ -121,6 +124,14 @@ static char uv_tty_default_fg_bright = 0; static char uv_tty_default_bg_bright = 0; static char uv_tty_default_inverse = 0; +typedef enum { + UV_SUPPORTED, + UV_UNCHECKED, + UV_UNSUPPORTED +} uv_vtermstate_t; +/* Determine whether or not ANSI support is enabled. */ +static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED; +static void uv__determine_vterm_state(HANDLE handle); void uv_console_init() { InitializeCriticalSection(&uv_tty_output_lock); @@ -163,6 +174,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { /* shared between all uv_tty_t handles. */ EnterCriticalSection(&uv_tty_output_lock); + if (uv__vterm_state == UV_UNCHECKED) + uv__determine_vterm_state(handle); + /* Store the global tty output handle. This handle is used by TTY read */ /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */ /* is received. */ @@ -1616,6 +1630,33 @@ static int uv_tty_write_bufs(uv_tty_t* handle, uv_buf_t buf = bufs[i]; unsigned int j; + if (uv__vterm_state == UV_SUPPORTED) { + utf16_buf_used = MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + NULL, + 0); + + if (utf16_buf_used == 0) { + *error = GetLastError(); + break; + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + utf16_buf, + utf16_buf_used)) { + *error = GetLastError(); + break; + } + + FLUSH_TEXT(); + continue; + } + for (j = 0; j < buf.len; j++) { unsigned char c = buf.base[j]; @@ -2173,3 +2214,24 @@ int uv_tty_reset_mode(void) { /* Not necessary to do anything. */ return 0; } + +/* Determine whether or not this version of windows supports + * proper ANSI color codes. Should be supported as of windows + * 10 version 1511, build number 10.0.10586. + */ +static void uv__determine_vterm_state(HANDLE handle) { + DWORD dwMode = 0; + + if (!GetConsoleMode(handle, &dwMode)) { + uv__vterm_state = UV_UNSUPPORTED; + return; + } + + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if (!SetConsoleMode(handle, dwMode)) { + uv__vterm_state = UV_UNSUPPORTED; + return; + } + + uv__vterm_state = UV_SUPPORTED; +} ----------------------------------------------------------------------- Summary of changes: CMakeLists.txt | 3 -- Utilities/cmlibuv/include/pthread-barrier.h | 2 +- Utilities/cmlibuv/src/unix/timer.c | 6 +-- Utilities/cmlibuv/src/win/tty.c | 62 +++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 7 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 30 09:51:07 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 30 Aug 2016 09:51:07 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1610-gef65af0 Message-ID: <20160830135107.B2718F3D13@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via ef65af0eeccf9a0137c258e5d5efa7e729cb2072 (commit) via b82d027b457db00b1a48ca225444d9c977cfc6f9 (commit) from fdeb50d6b51a8e189ebdb4da88b464cd981e0ad4 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ef65af0eeccf9a0137c258e5d5efa7e729cb2072 commit ef65af0eeccf9a0137c258e5d5efa7e729cb2072 Merge: fdeb50d b82d027 Author: Brad King AuthorDate: Tue Aug 30 09:51:06 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 30 09:51:06 2016 -0400 Merge topic 'drop-linux-i386-binary' into next b82d027b Utilities/Release: Drop Linux 32-bit binary https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b82d027b457db00b1a48ca225444d9c977cfc6f9 commit b82d027b457db00b1a48ca225444d9c977cfc6f9 Author: Brad King AuthorDate: Tue Aug 30 09:48:10 2016 -0400 Commit: Brad King CommitDate: Tue Aug 30 09:48:39 2016 -0400 Utilities/Release: Drop Linux 32-bit binary The Linux distro we've been using for this is so old that it limits our ability to import newer third-party software. Until a new machine can be configured to provide this binary we can simply drop it. Users will still be able to build from source or use a distro-provided version. diff --git a/Help/release/dev/drop-linux-i386-binary.rst b/Help/release/dev/drop-linux-i386-binary.rst new file mode 100644 index 0000000..60aa74e --- /dev/null +++ b/Help/release/dev/drop-linux-i386-binary.rst @@ -0,0 +1,5 @@ +drop-linux-i386-binary +---------------------- + +* We no longer provide Linux i386 binaries for download from ``cmake.org`` + for new versions of CMake. diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index c119cfd..4e9b062 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -676,8 +676,6 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release win64_release.cmake) ADD_NIGHTLY_BUILD_TEST(CMakeNightlyOSX osx_release.cmake) - ADD_NIGHTLY_BUILD_TEST(CMakeNightlyLinux32 - linux32_release.cmake) ADD_NIGHTLY_BUILD_TEST(CMakeNightlyLinux64 linux64_release.cmake) set_property(TEST CMakeNightlyWin64 PROPERTY DEPENDS CMakeNightlyWin32) diff --git a/Utilities/Release/create-cmake-release.cmake b/Utilities/Release/create-cmake-release.cmake index f8844e9..192549e 100644 --- a/Utilities/Release/create-cmake-release.cmake +++ b/Utilities/Release/create-cmake-release.cmake @@ -8,7 +8,6 @@ file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/logs) set(RELEASE_SCRIPTS_BATCH_1 win32_release.cmake # Windows x86 osx_release.cmake # OS X x86_64 - linux32_release.cmake # Linux x86 linux64_release.cmake # Linux x86_64 ) diff --git a/Utilities/Release/linux32_release.cmake b/Utilities/Release/linux32_release.cmake deleted file mode 100644 index 4ef513e..0000000 --- a/Utilities/Release/linux32_release.cmake +++ /dev/null @@ -1,25 +0,0 @@ -set(PROCESSORS 1) -set(BOOTSTRAP_ARGS "--docdir=doc/cmake") -set(HOST magrathea) -set(MAKE_PROGRAM "make") -set(CC gcc332s) -set(CXX c++332s) -set(CFLAGS -DDT_RUNPATH=29) -set(CXXFLAGS -DDT_RUNPATH=29) -set(INITIAL_CACHE " -CMAKE_BUILD_TYPE:STRING=Release -CURSES_LIBRARY:FILEPATH=/usr/i686-gcc-332s/lib/libncurses.a -CURSES_INCLUDE_PATH:PATH=/usr/i686-gcc-332s/include/ncurses -FORM_LIBRARY:FILEPATH=/usr/i686-gcc-332s/lib/libform.a -CMAKE_USE_OPENSSL:BOOL=ON -OPENSSL_CRYPTO_LIBRARY:FILEPATH=/home/kitware/openssl-1.0.2h/lib/libcrypto.a -OPENSSL_INCLUDE_DIR:PATH=/home/kitware/openssl-1.0.2h/include -OPENSSL_SSL_LIBRARY:FILEPATH=/home/kitware/openssl-1.0.2h/lib/libssl.a -CPACK_SYSTEM_NAME:STRING=Linux-i386 -BUILD_QtDialog:BOOL:=TRUE -CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL:STRING=2.1 -CMake_INSTALL_DEPENDENCIES:BOOL=ON -QT_QMAKE_EXECUTABLE:FILEPATH=/home/kitware/qt-4.43-install/bin/qmake -") -get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH) -include(${path}/release_cmake.cmake) ----------------------------------------------------------------------- Summary of changes: Help/release/dev/drop-linux-i386-binary.rst | 5 +++++ Tests/CMakeLists.txt | 2 -- Utilities/Release/create-cmake-release.cmake | 1 - Utilities/Release/linux32_release.cmake | 25 ------------------------- 4 files changed, 5 insertions(+), 28 deletions(-) create mode 100644 Help/release/dev/drop-linux-i386-binary.rst delete mode 100644 Utilities/Release/linux32_release.cmake hooks/post-receive -- CMake From raffi.enficiaud at mines-paris.org Tue Aug 30 10:04:07 2016 From: raffi.enficiaud at mines-paris.org (Raffi Enficiaud) Date: Tue, 30 Aug 2016 10:04:07 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1612-g94b028b Message-ID: <20160830140408.13791F4F1D@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 94b028b48a1d7f1fe753bd4e626f24d4240c7436 (commit) via bf09271b656bb8110c40cd2d456acfaa3b4e4741 (commit) from ef65af0eeccf9a0137c258e5d5efa7e729cb2072 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=94b028b48a1d7f1fe753bd4e626f24d4240c7436 commit 94b028b48a1d7f1fe753bd4e626f24d4240c7436 Merge: ef65af0 bf09271 Author: Raffi Enficiaud AuthorDate: Tue Aug 30 10:04:06 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 30 10:04:06 2016 -0400 Merge topic 'FindMatlab-additional-components' into next bf09271b FindMatlab: adding handling of component "MAT" https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bf09271b656bb8110c40cd2d456acfaa3b4e4741 commit bf09271b656bb8110c40cd2d456acfaa3b4e4741 Author: Raffi Enficiaud AuthorDate: Tue Aug 30 14:50:20 2016 +0200 Commit: Raffi Enficiaud CommitDate: Tue Aug 30 14:50:20 2016 +0200 FindMatlab: adding handling of component "MAT" - documentation - test - cosmetic changes diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake index 46285aa..9f96fe6 100644 --- a/Modules/FindMatlab.cmake +++ b/Modules/FindMatlab.cmake @@ -15,8 +15,8 @@ # # The module supports the following components: # -# * ``MX_LIBRARY`` and ``ENG_LIBRARY`` respectively the MX and ENG libraries of -# Matlab +# * ``MX_LIBRARY``, ``ENG_LIBRARY`` and ``MAT_LIBRARY``: respectively the MX, +# ENG and MAT libraries of Matlab # * ``MAIN_PROGRAM`` the Matlab binary program. # # .. note:: @@ -93,6 +93,9 @@ # ``Matlab_ENG_LIBRARY`` # Matlab engine library. Available only if the component ``ENG_LIBRARY`` # is requested. +# ``Matlab_MAT_LIBRARY`` +# Matlab matrix library. Available only if the component ``MAT_LIBRARY`` +# is requested. # ``Matlab_LIBRARIES`` # the whole set of libraries of Matlab # ``Matlab_MEX_COMPILER`` @@ -1213,6 +1216,7 @@ if(DEFINED Matlab_ROOT_DIR_LAST_CACHED) Matlab_MAIN_PROGRAM Matlab_MX_LIBRARY Matlab_ENG_LIBRARY + Matlab_MAT_LIBRARY Matlab_MEX_EXTENSION # internal @@ -1346,7 +1350,6 @@ _Matlab_find_library( NO_DEFAULT_PATH ) - list(APPEND _matlab_required_variables Matlab_MEX_LIBRARY) # the MEX extension is required @@ -1355,7 +1358,6 @@ list(APPEND _matlab_required_variables Matlab_MEX_EXTENSION) # the matlab root is required list(APPEND _matlab_required_variables Matlab_ROOT_DIR) - # component Mex Compiler list(FIND Matlab_FIND_COMPONENTS MEX_COMPILER _matlab_find_mex_compiler) if(_matlab_find_mex_compiler GREATER -1) @@ -1366,7 +1368,6 @@ if(_matlab_find_mex_compiler GREATER -1) DOC "Matlab MEX compiler" NO_DEFAULT_PATH ) - if(Matlab_MEX_COMPILER) set(Matlab_MEX_COMPILER_FOUND TRUE) endif() @@ -1376,7 +1377,6 @@ unset(_matlab_find_mex_compiler) # component Matlab program list(FIND Matlab_FIND_COMPONENTS MAIN_PROGRAM _matlab_find_matlab_program) if(_matlab_find_matlab_program GREATER -1) - find_program( Matlab_MAIN_PROGRAM matlab @@ -1384,11 +1384,9 @@ if(_matlab_find_matlab_program GREATER -1) DOC "Matlab main program" NO_DEFAULT_PATH ) - if(Matlab_MAIN_PROGRAM) set(Matlab_MAIN_PROGRAM_FOUND TRUE) endif() - endif() unset(_matlab_find_matlab_program) @@ -1402,14 +1400,12 @@ if(_matlab_find_mx GREATER -1) PATHS ${_matlab_lib_dir_for_search} NO_DEFAULT_PATH ) - if(Matlab_MX_LIBRARY) set(Matlab_MX_LIBRARY_FOUND TRUE) endif() endif() unset(_matlab_find_mx) - # Component ENG library list(FIND Matlab_FIND_COMPONENTS ENG_LIBRARY _matlab_find_eng) if(_matlab_find_eng GREATER -1) @@ -1426,15 +1422,26 @@ if(_matlab_find_eng GREATER -1) endif() unset(_matlab_find_eng) - - +# Component MAT library +list(FIND Matlab_FIND_COMPONENTS MAT_LIBRARY _matlab_find_mat) +if(_matlab_find_mat GREATER -1) + _Matlab_find_library( + ${_matlab_lib_prefix_for_search} + Matlab_MAT_LIBRARY + mat + PATHS ${_matlab_lib_dir_for_search} + NO_DEFAULT_PATH + ) + if(Matlab_MAT_LIBRARY) + set(Matlab_MAT_LIBRARY_FOUND TRUE) + endif() +endif() +unset(_matlab_find_mat) unset(_matlab_lib_dir_for_search) - -set(Matlab_LIBRARIES ${Matlab_MEX_LIBRARY} ${Matlab_MX_LIBRARY} ${Matlab_ENG_LIBRARY}) - +set(Matlab_LIBRARIES ${Matlab_MEX_LIBRARY} ${Matlab_MX_LIBRARY} ${Matlab_ENG_LIBRARY} ${Matlab_MAT_LIBRARY}) find_package_handle_standard_args( Matlab @@ -1453,18 +1460,14 @@ unset(_matlab_lib_prefix_for_search) if(Matlab_INCLUDE_DIRS AND Matlab_LIBRARIES) mark_as_advanced( - #Matlab_LIBRARIES Matlab_MEX_LIBRARY Matlab_MX_LIBRARY Matlab_ENG_LIBRARY + Matlab_MAT_LIBRARY Matlab_INCLUDE_DIRS Matlab_FOUND - #Matlab_ROOT_DIR - #Matlab_VERSION_STRING Matlab_MAIN_PROGRAM - #Matlab_MEX_EXTENSION Matlab_MEXEXTENSIONS_PROG Matlab_MEX_EXTENSION - #Matlab_BINARIES_DIR ) endif() diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index c119cfd..32e53d0 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1413,6 +1413,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release if(CMake_TEST_FindMatlab) ADD_TEST_MACRO(FindMatlab.basic_checks ${CMAKE_CTEST_COMMAND} -C $) ADD_TEST_MACRO(FindMatlab.versions_checks ${CMAKE_CTEST_COMMAND} -C $) + ADD_TEST_MACRO(FindMatlab.components_checks ${CMAKE_CTEST_COMMAND} -C $) endif() find_package(GTK2 QUIET) diff --git a/Tests/FindMatlab/components_checks/CMakeLists.txt b/Tests/FindMatlab/components_checks/CMakeLists.txt new file mode 100644 index 0000000..3dec093 --- /dev/null +++ b/Tests/FindMatlab/components_checks/CMakeLists.txt @@ -0,0 +1,23 @@ + +cmake_minimum_required (VERSION 2.8.12) +enable_testing() +project(component_checks) + +set(MATLAB_FIND_DEBUG TRUE) + +# the success of the following command is dependent on the current configuration: +# - on 32bits builds (cmake is building with 32 bits), it looks for 32 bits Matlab +# - on 64bits builds (cmake is building with 64 bits), it looks for 64 bits Matlab +find_package(Matlab REQUIRED COMPONENTS MX_LIBRARY ENG_LIBRARY MAT_LIBRARY MAIN_PROGRAM) + +message(STATUS "FindMatlab libraries: ${Matlab_LIBRARIES}") + +matlab_add_mex( + # target name + NAME cmake_matlab_test_wrapper1 + # output name + OUTPUT_NAME cmake_matlab_mex1 + SRC ${CMAKE_CURRENT_SOURCE_DIR}/../matlab_wrapper1.cpp + DOCUMENTATION ${CMAKE_CURRENT_SOURCE_DIR}/../help_text1.m.txt + LINK_TO ${Matlab_LIBRARIES} + ) ----------------------------------------------------------------------- Summary of changes: Modules/FindMatlab.cmake | 43 +++++++++++---------- Tests/CMakeLists.txt | 1 + Tests/FindMatlab/components_checks/CMakeLists.txt | 23 +++++++++++ 3 files changed, 47 insertions(+), 20 deletions(-) create mode 100644 Tests/FindMatlab/components_checks/CMakeLists.txt hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 30 10:38:13 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 30 Aug 2016 10:38:13 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1614-g9c041ea Message-ID: <20160830143815.2E94BF59B3@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 9c041eab42520c99c753b9e5be3c52943a834e21 (commit) via d6f96207c377e0492929592f9408a2fb3cafab93 (commit) from 94b028b48a1d7f1fe753bd4e626f24d4240c7436 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9c041eab42520c99c753b9e5be3c52943a834e21 commit 9c041eab42520c99c753b9e5be3c52943a834e21 Merge: 94b028b d6f9620 Author: Brad King AuthorDate: Tue Aug 30 10:38:12 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 30 10:38:12 2016 -0400 Merge topic 'fortran-macOS-sysroot' into next d6f96207 Fortran: Use -isysroot and -mmacosx-version-min= on macOS if available https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d6f96207c377e0492929592f9408a2fb3cafab93 commit d6f96207c377e0492929592f9408a2fb3cafab93 Author: Brad King AuthorDate: Tue Aug 30 10:36:05 2016 -0400 Commit: Brad King CommitDate: Tue Aug 30 10:37:21 2016 -0400 Fortran: Use -isysroot and -mmacosx-version-min= on macOS if available Closes: #16265 diff --git a/Modules/CMakeFortranCompiler.cmake.in b/Modules/CMakeFortranCompiler.cmake.in index 8e92f65..69800d7 100644 --- a/Modules/CMakeFortranCompiler.cmake.in +++ b/Modules/CMakeFortranCompiler.cmake.in @@ -55,6 +55,8 @@ if(CMAKE_Fortran_LIBRARY_ARCHITECTURE) endif() @CMAKE_Fortran_COMPILER_CUSTOM_CODE@ + at CMAKE_Fortran_SYSROOT_FLAG_CODE@ + at CMAKE_Fortran_OSX_DEPLOYMENT_TARGET_FLAG_CODE@ set(CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES "@CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES@") set(CMAKE_Fortran_IMPLICIT_LINK_DIRECTORIES "@CMAKE_Fortran_IMPLICIT_LINK_DIRECTORIES@") ----------------------------------------------------------------------- Summary of changes: Modules/CMakeFortranCompiler.cmake.in | 2 ++ 1 file changed, 2 insertions(+) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 30 10:52:12 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 30 Aug 2016 10:52:12 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1616-gf7e7afe Message-ID: <20160830145214.A3053F4B4A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via f7e7afe9d54fac4527c70e0b8a9c463aae3cc4de (commit) via ed1758f8eb58a4e52acf0f3885f82403814f5ffd (commit) from 9c041eab42520c99c753b9e5be3c52943a834e21 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f7e7afe9d54fac4527c70e0b8a9c463aae3cc4de commit f7e7afe9d54fac4527c70e0b8a9c463aae3cc4de Merge: 9c041ea ed1758f Author: Brad King AuthorDate: Tue Aug 30 10:52:10 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 30 10:52:10 2016 -0400 Merge topic 'FindOpenSSL-new-windows-names' into next ed1758f8 FindOpenSSL: Fix detection of OpenSSL 1.1 Win32/64 https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ed1758f8eb58a4e52acf0f3885f82403814f5ffd commit ed1758f8eb58a4e52acf0f3885f82403814f5ffd Author: Alexis Murzeau AuthorDate: Mon Aug 29 20:57:32 2016 +0000 Commit: Brad King CommitDate: Tue Aug 30 10:51:25 2016 -0400 FindOpenSSL: Fix detection of OpenSSL 1.1 Win32/64 Since OpenSSL 1.1.0, Windows binaries are libcrypto and libssl instead of the old names libeay32 and ssleay32. When using MSVC, FindOpenSSL was searching for the old lib names only so this add the new names to be able to find OpenSSL 1.1.0 libraries. For example, the files in lib directory of OpenSSL 1.1.0 Win64 : - libcrypto.lib - libssl.lib - VC/libcrypto64MD.lib - VC/libcrypto64MDd.lib - VC/libcrypto64MT.lib - VC/libcrypto64MTd.lib - VC/libssl64MD.lib - VC/libssl64MDd.lib - VC/libssl64MT.lib - VC/libssl64MTd.lib 32 bits OpenSSL has the same files with "32" instead of "64" for files in VC directory. MinGW still works and use lib/libcrypto.lib and lib/libssl.lib. This patch also add libssl and libcrypto for other windows compilers too (like Intel). diff --git a/Modules/FindOpenSSL.cmake b/Modules/FindOpenSSL.cmake index 10b62ff..7ddd783 100644 --- a/Modules/FindOpenSSL.cmake +++ b/Modules/FindOpenSSL.cmake @@ -133,6 +133,13 @@ if(WIN32 AND NOT CYGWIN) set(_OPENSSL_MSVC_RT_MODE "MD") endif () + # Since OpenSSL 1.1, lib names are like libcrypto32MTd.lib and libssl32MTd.lib + if( "${CMAKE_SIZEOF_VOID_P}" STREQUAL "8" ) + set(_OPENSSL_MSVC_ARCH_SUFFIX "64") + else() + set(_OPENSSL_MSVC_ARCH_SUFFIX "32") + endif() + if(OPENSSL_USE_STATIC_LIBS) set(_OPENSSL_PATH_SUFFIXES "lib" @@ -149,6 +156,8 @@ if(WIN32 AND NOT CYGWIN) find_library(LIB_EAY_DEBUG NAMES + libcrypto${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d + libcryptod libeay32${_OPENSSL_MSVC_RT_MODE}d libeay32d NAMES_PER_DIR @@ -159,6 +168,8 @@ if(WIN32 AND NOT CYGWIN) find_library(LIB_EAY_RELEASE NAMES + libcrypto${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE} + libcrypto libeay32${_OPENSSL_MSVC_RT_MODE} libeay32 NAMES_PER_DIR @@ -169,6 +180,8 @@ if(WIN32 AND NOT CYGWIN) find_library(SSL_EAY_DEBUG NAMES + libssl${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d + libssld ssleay32${_OPENSSL_MSVC_RT_MODE}d ssleay32d NAMES_PER_DIR @@ -179,6 +192,8 @@ if(WIN32 AND NOT CYGWIN) find_library(SSL_EAY_RELEASE NAMES + libssl${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE} + libssl ssleay32${_OPENSSL_MSVC_RT_MODE} ssleay32 ssl @@ -236,6 +251,7 @@ if(WIN32 AND NOT CYGWIN) # Not sure what to pick for -say- intel, let's use the toplevel ones and hope someone report issues: find_library(LIB_EAY NAMES + libcrypto libeay32 NAMES_PER_DIR ${_OPENSSL_ROOT_HINTS_AND_PATHS} @@ -247,6 +263,7 @@ if(WIN32 AND NOT CYGWIN) find_library(SSL_EAY NAMES + libssl ssleay32 NAMES_PER_DIR ${_OPENSSL_ROOT_HINTS_AND_PATHS} ----------------------------------------------------------------------- Summary of changes: Modules/FindOpenSSL.cmake | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) hooks/post-receive -- CMake From brad.king at kitware.com Tue Aug 30 13:53:54 2016 From: brad.king at kitware.com (Brad King) Date: Tue, 30 Aug 2016 13:53:54 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1618-g9470d1e Message-ID: <20160830175354.EA224F4B29@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 9470d1e8bbcdd258fae66165f9cfdb76b7175179 (commit) via 1dda2ec55a07f2a51d09f7b1604707e690e884b5 (commit) from f7e7afe9d54fac4527c70e0b8a9c463aae3cc4de (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9470d1e8bbcdd258fae66165f9cfdb76b7175179 commit 9470d1e8bbcdd258fae66165f9cfdb76b7175179 Merge: f7e7afe 1dda2ec Author: Brad King AuthorDate: Tue Aug 30 13:53:53 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 30 13:53:53 2016 -0400 Merge topic 'syntax-unexpected-eof' into next 1dda2ec5 Improve error message on unexpected end of file https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1dda2ec55a07f2a51d09f7b1604707e690e884b5 commit 1dda2ec55a07f2a51d09f7b1604707e690e884b5 Author: Brad King AuthorDate: Tue Aug 30 13:36:51 2016 -0400 Commit: Brad King CommitDate: Tue Aug 30 13:53:15 2016 -0400 Improve error message on unexpected end of file Suggested-by: Stephen Kelly diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 3c5e333..aad538c 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -163,8 +163,7 @@ bool cmListFileParser::ParseFunction(const char* name, long line) if (!token) { std::ostringstream error; /* clang-format off */ - error << "Error in cmake code at\n" << this->FileName << ":" - << cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n" + error << "Unexpected end of file.\n" << "Parse error. Function missing opening \"(\"."; /* clang-format on */ this->IssueError(error.str()); diff --git a/Tests/RunCMake/Syntax/CommandEOF-result.txt b/Tests/RunCMake/Syntax/CommandEOF-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/CommandEOF-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/CommandEOF-stderr.txt b/Tests/RunCMake/Syntax/CommandEOF-stderr.txt new file mode 100644 index 0000000..31cbc08 --- /dev/null +++ b/Tests/RunCMake/Syntax/CommandEOF-stderr.txt @@ -0,0 +1,6 @@ +^CMake Error in CommandEOF.cmake: + Unexpected end of file. + + Parse error. Function missing opening "\(". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/Syntax/CommandEOF.cmake b/Tests/RunCMake/Syntax/CommandEOF.cmake new file mode 100644 index 0000000..36ebb02 --- /dev/null +++ b/Tests/RunCMake/Syntax/CommandEOF.cmake @@ -0,0 +1 @@ +message \ No newline at end of file diff --git a/Tests/RunCMake/Syntax/RunCMakeTest.cmake b/Tests/RunCMake/Syntax/RunCMakeTest.cmake index fd012b9..d1fbb16 100644 --- a/Tests/RunCMake/Syntax/RunCMakeTest.cmake +++ b/Tests/RunCMake/Syntax/RunCMakeTest.cmake @@ -17,6 +17,7 @@ run_cmake(CommandSpaces) run_cmake(CommandTabs) run_cmake(CommandNewlines) run_cmake(CommandComments) +run_cmake(CommandEOF) run_cmake(CommandError0) run_cmake(CommandError1) run_cmake(CommandError2) ----------------------------------------------------------------------- Summary of changes: Source/cmListFileCache.cxx | 3 +-- .../BadSYSROOT-result.txt => Syntax/CommandEOF-result.txt} | 0 Tests/RunCMake/Syntax/CommandEOF-stderr.txt | 6 ++++++ Tests/RunCMake/Syntax/CommandEOF.cmake | 1 + Tests/RunCMake/Syntax/RunCMakeTest.cmake | 1 + 5 files changed, 9 insertions(+), 2 deletions(-) copy Tests/RunCMake/{Android/BadSYSROOT-result.txt => Syntax/CommandEOF-result.txt} (100%) create mode 100644 Tests/RunCMake/Syntax/CommandEOF-stderr.txt create mode 100644 Tests/RunCMake/Syntax/CommandEOF.cmake hooks/post-receive -- CMake From gjasny at googlemail.com Tue Aug 30 14:51:36 2016 From: gjasny at googlemail.com (Gregor Jasny) Date: Tue, 30 Aug 2016 14:51:36 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1621-g320f5bd Message-ID: <20160830185136.CA042F4B7E@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 320f5bdc1cce81292367b04ebcb733375ab81d61 (commit) via 819f23c6ce515c1b8faa390a9bc850bea3eb4072 (commit) via 8ccd6aab9a0b2f3df48abdc6ed5086dcca576224 (commit) from 9470d1e8bbcdd258fae66165f9cfdb76b7175179 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=320f5bdc1cce81292367b04ebcb733375ab81d61 commit 320f5bdc1cce81292367b04ebcb733375ab81d61 Merge: 9470d1e 819f23c Author: Gregor Jasny AuthorDate: Tue Aug 30 14:51:35 2016 -0400 Commit: CMake Topic Stage CommitDate: Tue Aug 30 14:51:35 2016 -0400 Merge topic '16101-xcode-fix-directory-exclude-from-all' into next 819f23c6 fixup! Xcode: Add targets marked as EXCLUDE_FROM_ALL to project (#16101) 8ccd6aab fixup! Xcode: Add targets marked as EXCLUDE_FROM_ALL to project (#16101) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=819f23c6ce515c1b8faa390a9bc850bea3eb4072 commit 819f23c6ce515c1b8faa390a9bc850bea3eb4072 Author: Gregor Jasny AuthorDate: Tue Aug 30 20:50:19 2016 +0200 Commit: Gregor Jasny CommitDate: Tue Aug 30 20:50:19 2016 +0200 fixup! Xcode: Add targets marked as EXCLUDE_FROM_ALL to project (#16101) diff --git a/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake index 6d9418b..88b9283 100644 --- a/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake +++ b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake @@ -4,7 +4,7 @@ run_cmake(DoesNotExist) run_cmake(Missing) run_cmake(Function) -set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ExcludeFromAll) +set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ExcludeFromAll-build) set(RunCMake_TEST_NO_CLEAN 1) file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8ccd6aab9a0b2f3df48abdc6ed5086dcca576224 commit 8ccd6aab9a0b2f3df48abdc6ed5086dcca576224 Author: Gregor Jasny AuthorDate: Tue Aug 30 20:36:53 2016 +0200 Commit: Gregor Jasny CommitDate: Tue Aug 30 20:36:53 2016 +0200 fixup! Xcode: Add targets marked as EXCLUDE_FROM_ALL to project (#16101) diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp index 2789e61..c9ad322 100644 --- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp @@ -1,3 +1,6 @@ #include "foo.h" -int foo() { return 42; } +int foo() +{ + return 42; +} diff --git a/Tests/RunCMake/add_subdirectory/main.cpp b/Tests/RunCMake/add_subdirectory/main.cpp index 8e69c08..1dc3906 100644 --- a/Tests/RunCMake/add_subdirectory/main.cpp +++ b/Tests/RunCMake/add_subdirectory/main.cpp @@ -2,5 +2,5 @@ int main(int, char**) { - return foo(); + return foo(); } ----------------------------------------------------------------------- Summary of changes: Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp | 5 ++++- Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake | 2 +- Tests/RunCMake/add_subdirectory/main.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) hooks/post-receive -- CMake From kwrobot at kitware.com Wed Aug 31 00:01:14 2016 From: kwrobot at kitware.com (Kitware Robot) Date: Wed, 31 Aug 2016 00:01:14 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-788-g9bbf1dc Message-ID: <20160831040114.A5240F5019@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 9bbf1dc06ebb891498747768736442b22058c49e (commit) from e3a4c2e02ceacd302e8bc6a7dc1bc02b29ab2cfc (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9bbf1dc06ebb891498747768736442b22058c49e commit 9bbf1dc06ebb891498747768736442b22058c49e Author: Kitware Robot AuthorDate: Wed Aug 31 00:01:04 2016 -0400 Commit: Kitware Robot CommitDate: Wed Aug 31 00:01:04 2016 -0400 CMake Nightly Date Stamp diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 52986e2..4e86949 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160830) +set(CMake_VERSION_PATCH 20160831) #set(CMake_VERSION_RC 1) ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 09:07:25 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 09:07:25 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1623-gf631705 Message-ID: <20160831130725.44F0AF5BA1@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via f631705425da0a343b6c27de77be88fcacff34e6 (commit) via 05979c39509615e10a3b2bd4a5b4224dfde4c3eb (commit) from 320f5bdc1cce81292367b04ebcb733375ab81d61 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f631705425da0a343b6c27de77be88fcacff34e6 commit f631705425da0a343b6c27de77be88fcacff34e6 Merge: 320f5bd 05979c3 Author: Brad King AuthorDate: Wed Aug 31 09:07:23 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 09:07:23 2016 -0400 Merge topic 'import-libuv' into next 05979c39 Revert "Revert "Do not build libuv on HP-UX"" https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=05979c39509615e10a3b2bd4a5b4224dfde4c3eb commit 05979c39509615e10a3b2bd4a5b4224dfde4c3eb Author: Brad King AuthorDate: Wed Aug 31 09:07:00 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:07:00 2016 -0400 Revert "Revert "Do not build libuv on HP-UX"" This reverts commit a9cc3756b63bb064850b3d56e60edf755738fcaa. diff --git a/CMakeLists.txt b/CMakeLists.txt index 65876d5..aab8416 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -484,6 +484,9 @@ int main(void) { return 0; } elseif(CYGWIN) # libuv does not support Cygwin set(CMAKE_USE_LIBUV 0) + elseif(CMAKE_SYSTEM_NAME STREQUAL "HP-UX") + # libuv does not support HP-UX + set(CMAKE_USE_LIBUV 0) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "sparc") # Disable until it can be ported. set(CMAKE_USE_LIBUV 0) ----------------------------------------------------------------------- Summary of changes: CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 09:10:11 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 09:10:11 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1625-g755bc1d Message-ID: <20160831131011.3C1B9B0EB7@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 755bc1d12bcfe2c4cac7fc488810d7064f774acf (commit) via 01ab6482024e10c64bf435b4e7bd58cc79a2213a (commit) from f631705425da0a343b6c27de77be88fcacff34e6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=755bc1d12bcfe2c4cac7fc488810d7064f774acf commit 755bc1d12bcfe2c4cac7fc488810d7064f774acf Merge: f631705 01ab648 Author: Brad King AuthorDate: Wed Aug 31 09:10:10 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 09:10:10 2016 -0400 Merge topic 'import-libuv' into next 01ab6482 Revise comment on libuv for HP-UX https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=01ab6482024e10c64bf435b4e7bd58cc79a2213a commit 01ab6482024e10c64bf435b4e7bd58cc79a2213a Author: Brad King AuthorDate: Wed Aug 31 09:09:02 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:09:02 2016 -0400 Revise comment on libuv for HP-UX diff --git a/CMakeLists.txt b/CMakeLists.txt index aab8416..4ef2ca2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -485,7 +485,7 @@ int main(void) { return 0; } # libuv does not support Cygwin set(CMAKE_USE_LIBUV 0) elseif(CMAKE_SYSTEM_NAME STREQUAL "HP-UX") - # libuv does not support HP-UX + # Disable until it can be ported. set(CMAKE_USE_LIBUV 0) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "sparc") # Disable until it can be ported. ----------------------------------------------------------------------- Summary of changes: CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 09:10:43 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 09:10:43 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1645-gda28ae1 Message-ID: <20160831131047.BADA6EF76A@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via da28ae1b3d79b91d94fa39aa7228b0717374f972 (commit) via 39ac889d636ee8ce083e00ab2c8351c6148150ef (commit) via 7cf369fe276e011d4c9322153ae7c77d5124ca7e (commit) via 075cae5147bdca011841a9ebaf166636ab3e410f (commit) via 9a53af4068fd7f7627f8af193f551c1f2b5d4ac4 (commit) via 219f741128bfe1f34a97d71fa3bcdf8588d3d890 (commit) via 8a5beef32e007e69a8b348afa8ed2bddd760199a (commit) via e56aa462976f80762712519a4cf653b8c45bf3db (commit) via 551d5aedbffc0020793c2b6b374f1fa2be3e91d8 (commit) via f4f8074bec408ba0cab0f08ce1c48ad312fc0b24 (commit) via a63aaaed051a51592f9ddc738febd58a4d99928a (commit) via 9130b53a5e949da07e10414e13b79d7abad2b4fa (commit) via b52afa4655737f442af6017bab8d44158bdd466d (commit) via 05dbc204cdb4c7d81f40f2e2174c51df7e3294b9 (commit) via 75139374f07cff43eeab6b4302d560a077440d76 (commit) via 95dcc4e474b8ad10fea47c68df88678a6ae10fac (commit) via 13b7e7587d50a52bb422852eb4d71a93eb8f18a6 (commit) via d96416fe482e17bc9f5a741d71d4a51a9b44f65e (commit) via 3a713eaaf7d289b130acf0007b197553a6528112 (commit) via 3800fc299fe7703c4a3976f9ba9028e1ebeb3d3e (commit) from 755bc1d12bcfe2c4cac7fc488810d7064f774acf (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=da28ae1b3d79b91d94fa39aa7228b0717374f972 commit da28ae1b3d79b91d94fa39aa7228b0717374f972 Merge: 755bc1d 39ac889 Author: Brad King AuthorDate: Wed Aug 31 09:10:36 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 09:10:36 2016 -0400 Merge topic 'import-libuv' into next 39ac889d cmake: Add trivial usage of libuv 7cf369fe Do not build libuv on HP-UX 075cae51 Do not build libuv on SPARC 9a53af40 Do not build libuv on Cygwin 219f7411 Do not build libuv on Mac OS X 10.4 and lower 8a5beef3 Add option to build CMake against a system libuv e56aa462 FindLibUV: Add module to find libuv package 551d5aed libuv: Fix unused variable warning in uv_loop_close f4f8074b libuv: Avoid including macOS CoreServices header globally a63aaaed libuv: Always include our own header first 9130b53a libuv: Conditionally declare Windows APIs for VS 2008 and below b52afa46 libuv: Fix anonymous union syntax 05dbc204 libuv: Fix Windows API function typedef syntax 75139374 libuv: Install LICENSE file with CMake documentation 95dcc4e4 libuv: Disable warnings to avoid changing 3rd party code 13b7e758 libuv: Build the library within CMake ... https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=39ac889d636ee8ce083e00ab2c8351c6148150ef commit 39ac889d636ee8ce083e00ab2c8351c6148150ef Author: Brad King AuthorDate: Thu Aug 25 14:12:42 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:09:23 2016 -0400 cmake: Add trivial usage of libuv This will serve to make sure cmake actually compiles and links against libuv. diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 1505d00..db6d51b 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -27,6 +27,10 @@ #include "cmcmd.h" #include +#ifdef CMAKE_USE_LIBUV +#include "cm_uv.h" +#endif + #ifdef CMAKE_BUILD_WITH_CMAKE static const char* cmDocumentationName[][2] = { { CM_NULLPTR, " cmake - Cross-Platform Makefile Generator." }, @@ -172,6 +176,9 @@ int main(int ac, char const* const* av) #ifdef CMAKE_BUILD_WITH_CMAKE cmDynamicLoader::FlushCache(); #endif +#ifdef CMAKE_USE_LIBUV + uv_loop_close(uv_default_loop()); +#endif return ret; } https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7cf369fe276e011d4c9322153ae7c77d5124ca7e commit 7cf369fe276e011d4c9322153ae7c77d5124ca7e Author: Brad King AuthorDate: Fri Aug 26 09:02:46 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:09:23 2016 -0400 Do not build libuv on HP-UX Some work may be needed to port to HP-UX. diff --git a/CMakeLists.txt b/CMakeLists.txt index 65876d5..4ef2ca2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -484,6 +484,9 @@ int main(void) { return 0; } elseif(CYGWIN) # libuv does not support Cygwin set(CMAKE_USE_LIBUV 0) + elseif(CMAKE_SYSTEM_NAME STREQUAL "HP-UX") + # Disable until it can be ported. + set(CMAKE_USE_LIBUV 0) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "sparc") # Disable until it can be ported. set(CMAKE_USE_LIBUV 0) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=075cae5147bdca011841a9ebaf166636ab3e410f commit 075cae5147bdca011841a9ebaf166636ab3e410f Author: Brad King AuthorDate: Fri Aug 26 08:57:40 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:05:15 2016 -0400 Do not build libuv on SPARC Some work may be needed to port to SPARC with Solaris and Linux. diff --git a/CMakeLists.txt b/CMakeLists.txt index 9176049..65876d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -484,6 +484,9 @@ int main(void) { return 0; } elseif(CYGWIN) # libuv does not support Cygwin set(CMAKE_USE_LIBUV 0) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "sparc") + # Disable until it can be ported. + set(CMAKE_USE_LIBUV 0) endif() endif() if(CMAKE_USE_LIBUV) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9a53af4068fd7f7627f8af193f551c1f2b5d4ac4 commit 9a53af4068fd7f7627f8af193f551c1f2b5d4ac4 Author: Brad King AuthorDate: Fri Aug 26 08:17:42 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:05:15 2016 -0400 Do not build libuv on Cygwin Currently libuv does not support Cygwin (see libuv issue 832) in part due to lack of pthread APIs: https://cygwin.com/cygwin-api/std-notimpl.html diff --git a/CMakeLists.txt b/CMakeLists.txt index b62f6a5..9176049 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -481,6 +481,9 @@ int main(void) { return 0; } if(NOT HAVE_CoreServices_OS_X_10_5) set(CMAKE_USE_LIBUV 0) endif() + elseif(CYGWIN) + # libuv does not support Cygwin + set(CMAKE_USE_LIBUV 0) endif() endif() if(CMAKE_USE_LIBUV) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=219f741128bfe1f34a97d71fa3bcdf8588d3d890 commit 219f741128bfe1f34a97d71fa3bcdf8588d3d890 Author: Brad King AuthorDate: Thu Aug 25 13:43:50 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:05:14 2016 -0400 Do not build libuv on Mac OS X 10.4 and lower It needs APIs that have been available only since 10.5. Also check that the CoreServices header can be included. diff --git a/CMakeLists.txt b/CMakeLists.txt index 13e2401..b62f6a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -468,6 +468,20 @@ macro (CMAKE_BUILD_UTILITIES) # Build libuv library. if(NOT DEFINED CMAKE_USE_LIBUV) set(CMAKE_USE_LIBUV 1) + if(APPLE) + include(CheckCSourceCompiles) + check_c_source_compiles(" +#include +#include +#ifndef MAC_OS_X_VERSION_10_5 +#error \"MAC_OS_X_VERSION_10_5 is not defined\" +#endif +int main(void) { return 0; } +" HAVE_CoreServices_OS_X_10_5) + if(NOT HAVE_CoreServices_OS_X_10_5) + set(CMAKE_USE_LIBUV 0) + endif() + endif() endif() if(CMAKE_USE_LIBUV) if(CMAKE_USE_SYSTEM_LIBUV) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8a5beef32e007e69a8b348afa8ed2bddd760199a commit 8a5beef32e007e69a8b348afa8ed2bddd760199a Author: Brad King AuthorDate: Tue Aug 16 17:01:23 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:05:14 2016 -0400 Add option to build CMake against a system libuv Create a CMAKE_USE_SYSTEM_LIBUV option. diff --git a/CMakeLists.txt b/CMakeLists.txt index 958beb6..13e2401 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,7 +112,7 @@ macro(CMAKE_HANDLE_SYSTEM_LIBRARIES) # Allow the user to enable/disable all system utility library options by # defining CMAKE_USE_SYSTEM_LIBRARIES or CMAKE_USE_SYSTEM_LIBRARY_${util}. - set(UTILITIES BZIP2 CURL EXPAT FORM JSONCPP LIBARCHIVE LIBLZMA ZLIB) + set(UTILITIES BZIP2 CURL EXPAT FORM JSONCPP LIBARCHIVE LIBLZMA LIBUV ZLIB) foreach(util ${UTILITIES}) if(NOT DEFINED CMAKE_USE_SYSTEM_LIBRARY_${util} AND DEFINED CMAKE_USE_SYSTEM_LIBRARIES) @@ -152,6 +152,7 @@ macro(CMAKE_HANDLE_SYSTEM_LIBRARIES) "${CMAKE_USE_SYSTEM_LIBRARY_LIBLZMA}" "NOT CMAKE_USE_SYSTEM_LIBARCHIVE" ON) option(CMAKE_USE_SYSTEM_FORM "Use system-installed libform" "${CMAKE_USE_SYSTEM_LIBRARY_FORM}") option(CMAKE_USE_SYSTEM_JSONCPP "Use system-installed jsoncpp" "${CMAKE_USE_SYSTEM_LIBRARY_JSONCPP}") + option(CMAKE_USE_SYSTEM_LIBUV "Use system-installed libuv" "${CMAKE_USE_SYSTEM_LIBRARY_LIBUV}") # For now use system KWIML only if explicitly requested rather # than activating via the general system libs options. @@ -469,9 +470,22 @@ macro (CMAKE_BUILD_UTILITIES) set(CMAKE_USE_LIBUV 1) endif() if(CMAKE_USE_LIBUV) - set(CMAKE_LIBUV_LIBRARIES cmlibuv) - add_subdirectory(Utilities/cmlibuv) - CMAKE_SET_TARGET_FOLDER(cmlibuv "Utilities/3rdParty") + if(CMAKE_USE_SYSTEM_LIBUV) + if(NOT CMAKE_VERSION VERSION_LESS 3.0) + include(${CMake_SOURCE_DIR}/Source/Modules/FindLibUV.cmake) + else() + message(FATAL_ERROR "CMAKE_USE_SYSTEM_LIBUV requires CMake >= 3.0") + endif() + if(NOT LIBUV_FOUND) + message(FATAL_ERROR + "CMAKE_USE_SYSTEM_LIBUV is ON but a libuv is not found!") + endif() + set(CMAKE_LIBUV_LIBRARIES LibUV::LibUV) + else() + set(CMAKE_LIBUV_LIBRARIES cmlibuv) + add_subdirectory(Utilities/cmlibuv) + CMAKE_SET_TARGET_FOLDER(cmlibuv "Utilities/3rdParty") + endif() else() set(CMAKE_LIBUV_LIBRARIES) endif() diff --git a/Utilities/cmThirdParty.h.in b/Utilities/cmThirdParty.h.in index 4c1177c..cb8f0d5 100644 --- a/Utilities/cmThirdParty.h.in +++ b/Utilities/cmThirdParty.h.in @@ -22,6 +22,7 @@ #cmakedefine CMAKE_USE_SYSTEM_LIBLZMA #cmakedefine CMAKE_USE_SYSTEM_FORM #cmakedefine CMAKE_USE_SYSTEM_JSONCPP +#cmakedefine CMAKE_USE_SYSTEM_LIBUV #cmakedefine CTEST_USE_XMLRPC #endif diff --git a/Utilities/cm_uv.h b/Utilities/cm_uv.h index 63ff597..baa9bfc 100644 --- a/Utilities/cm_uv.h +++ b/Utilities/cm_uv.h @@ -12,6 +12,12 @@ #ifndef cm_uv_h #define cm_uv_h +/* Use the libuv library configured for CMake. */ +#include "cmThirdParty.h" +#ifdef CMAKE_USE_SYSTEM_LIBUV +#include +#else #include +#endif #endif https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e56aa462976f80762712519a4cf653b8c45bf3db commit e56aa462976f80762712519a4cf653b8c45bf3db Author: Brad King AuthorDate: Tue Aug 16 16:56:34 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:05:14 2016 -0400 FindLibUV: Add module to find libuv package Add it to a private source directory that is not installed so that we can use it for building CMake itself. This will allow it to mature before being distributed publicly. diff --git a/Source/Modules/FindLibUV.cmake b/Source/Modules/FindLibUV.cmake new file mode 100644 index 0000000..7391aa7 --- /dev/null +++ b/Source/Modules/FindLibUV.cmake @@ -0,0 +1,131 @@ +#[=======================================================================[.rst: +FindLibUV +--------- + +Find libuv includes and library. + +Imported Targets +^^^^^^^^^^^^^^^^ + +An :ref:`imported target ` named +``LibUV::LibUV`` is provided if libuv has been found. + +Result Variables +^^^^^^^^^^^^^^^^ + +This module defines the following variables: + +``LibUV_FOUND`` + True if libuv was found, false otherwise. +``LibUV_INCLUDE_DIRS`` + Include directories needed to include libuv headers. +``LibUV_LIBRARIES`` + Libraries needed to link to libuv. +``LibUV_VERSION`` + The version of libuv found. +``LibUV_VERSION_MAJOR`` + The major version of libuv. +``LibUV_VERSION_MINOR`` + The minor version of libuv. +``LibUV_VERSION_PATCH`` + The patch version of libuv. + +Cache Variables +^^^^^^^^^^^^^^^ + +This module uses the following cache variables: + +``LibUV_LIBRARY`` + The location of the libuv library file. +``LibUV_INCLUDE_DIR`` + The location of the libuv include directory containing ``uv.h``. + +The cache variables should not be used by project code. +They may be set by end users to point at libuv components. +#]=======================================================================] + +#============================================================================= +# Copyright 2014-2016 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +#----------------------------------------------------------------------------- +find_library(LibUV_LIBRARY + NAMES uv + ) +mark_as_advanced(LibUV_LIBRARY) + +find_path(LibUV_INCLUDE_DIR + NAMES uv.h + ) +mark_as_advanced(LibUV_INCLUDE_DIR) + +#----------------------------------------------------------------------------- +# Extract version number if possible. +set(_LibUV_H_REGEX "#[ \t]*define[ \t]+UV_VERSION_(MAJOR|MINOR|PATCH)[ \t]+[0-9]+") +if(LibUV_INCLUDE_DIR AND EXISTS "${LibUV_INCLUDE_DIR}/uv-version.h") + file(STRINGS "${LibUV_INCLUDE_DIR}/uv-version.h" _LibUV_H REGEX "${_LibUV_H_REGEX}") +elseif(LibUV_INCLUDE_DIR AND EXISTS "${LibUV_INCLUDE_DIR}/uv.h") + file(STRINGS "${LibUV_INCLUDE_DIR}/uv.h" _LibUV_H REGEX "${_LibUV_H_REGEX}") +else() + set(_LibUV_H "") +endif() +foreach(c MAJOR MINOR PATCH) + if(_LibUV_H MATCHES "#[ \t]*define[ \t]+UV_VERSION_${c}[ \t]+([0-9]+)") + set(_LibUV_VERSION_${c} "${CMAKE_MATCH_1}") + else() + unset(_LibUV_VERSION_${c}) + endif() +endforeach() +if(DEFINED _LibUV_VERSION_MAJOR AND DEFINED _LibUV_VERSION_MINOR) + set(LibUV_VERSION_MAJOR "${_LibUV_VERSION_MAJOR}") + set(LibUV_VERSION_MINOR "${_LibUV_VERSION_MINOR}") + set(LibUV_VERSION "${LibUV_VERSION_MAJOR}.${LibUV_VERSION_MINOR}") + if(DEFINED _LibUV_VERSION_PATCH) + set(LibUV_VERSION_PATCH "${_LibUV_VERSION_PATCH}") + set(LibUV_VERSION "${LibUV_VERSION}.${LibUV_VERSION_PATCH}") + else() + unset(LibUV_VERSION_PATCH) + endif() +else() + set(LibUV_VERSION_MAJOR "") + set(LibUV_VERSION_MINOR "") + set(LibUV_VERSION_PATCH "") + set(LibUV_VERSION "") +endif() +unset(_LibUV_VERSION_MAJOR) +unset(_LibUV_VERSION_MINOR) +unset(_LibUV_VERSION_PATCH) +unset(_LibUV_H_REGEX) +unset(_LibUV_H) + +#----------------------------------------------------------------------------- +include(${CMAKE_CURRENT_LIST_DIR}/../../Modules/FindPackageHandleStandardArgs.cmake) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibUV + FOUND_VAR LibUV_FOUND + REQUIRED_VARS LibUV_LIBRARY LibUV_INCLUDE_DIR + VERSION_VAR LibUV_VERSION + ) +set(LIBUV_FOUND ${LibUV_FOUND}) + +#----------------------------------------------------------------------------- +# Provide documented result variables and targets. +if(LibUV_FOUND) + set(LibUV_INCLUDE_DIRS ${LibUV_INCLUDE_DIR}) + set(LibUV_LIBRARIES ${LibUV_LIBRARY}) + if(NOT TARGET LibUV::LibUV) + add_library(LibUV::LibUV UNKNOWN IMPORTED) + set_target_properties(LibUV::LibUV PROPERTIES + IMPORTED_LOCATION "${LibUV_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${LibUV_INCLUDE_DIRS}" + ) + endif() +endif() diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index c119cfd..6494650 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1375,6 +1375,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release add_subdirectory(FindJsonCpp) endif() + if(CMake_TEST_FindLibUV) + add_subdirectory(FindLibUV) + endif() + if(CMake_TEST_FindLTTngUST) add_subdirectory(FindLTTngUST) endif() diff --git a/Tests/FindLibUV/CMakeLists.txt b/Tests/FindLibUV/CMakeLists.txt new file mode 100644 index 0000000..08aa958 --- /dev/null +++ b/Tests/FindLibUV/CMakeLists.txt @@ -0,0 +1,10 @@ +add_test(NAME FindLibUV.Test COMMAND + ${CMAKE_CTEST_COMMAND} -C $ + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindLibUV/Test" + "${CMake_BINARY_DIR}/Tests/FindLibUV/Test" + ${build_generator_args} + --build-project TestFindLibUV + --build-options ${build_options} + --test-command ${CMAKE_CTEST_COMMAND} -V -C $ + ) diff --git a/Tests/FindLibUV/Test/CMakeLists.txt b/Tests/FindLibUV/Test/CMakeLists.txt new file mode 100644 index 0000000..257ddf3 --- /dev/null +++ b/Tests/FindLibUV/Test/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.6) +project(TestFindLibUV C) +include(CTest) + +# CMake does not actually provide FindLibUV publicly. +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../Source/Modules) + +find_package(LibUV REQUIRED) + +add_executable(test_libuv_tgt main.c) +target_link_libraries(test_libuv_tgt LibUV::LibUV) +add_test(NAME test_libuv_tgt COMMAND test_libuv_tgt) + +add_executable(test_libuv_var main.c) +target_include_directories(test_libuv_var PRIVATE ${LibUV_INCLUDE_DIRS}) +target_link_libraries(test_libuv_var PRIVATE ${LibUV_LIBRARIES}) +add_test(NAME test_libuv_var COMMAND test_libuv_var) diff --git a/Tests/FindLibUV/Test/main.c b/Tests/FindLibUV/Test/main.c new file mode 100644 index 0000000..cbd0db3 --- /dev/null +++ b/Tests/FindLibUV/Test/main.c @@ -0,0 +1,7 @@ +#include + +int main() +{ + uv_loop_close(uv_default_loop()); + return 0; +} https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=551d5aedbffc0020793c2b6b374f1fa2be3e91d8 commit 551d5aedbffc0020793c2b6b374f1fa2be3e91d8 Author: Brad King AuthorDate: Fri Aug 26 09:16:45 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:05:14 2016 -0400 libuv: Fix unused variable warning in uv_loop_close diff --git a/Utilities/cmlibuv/src/uv-common.c b/Utilities/cmlibuv/src/uv-common.c index 434a502..46d9546 100644 --- a/Utilities/cmlibuv/src/uv-common.c +++ b/Utilities/cmlibuv/src/uv-common.c @@ -613,7 +613,9 @@ uv_loop_t* uv_loop_new(void) { int uv_loop_close(uv_loop_t* loop) { QUEUE* q; uv_handle_t* h; +#ifndef NDEBUG void* saved_data; +#endif if (!QUEUE_EMPTY(&(loop)->active_reqs)) return UV_EBUSY; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f4f8074bec408ba0cab0f08ce1c48ad312fc0b24 commit f4f8074bec408ba0cab0f08ce1c48ad312fc0b24 Author: Brad King AuthorDate: Thu Aug 25 11:36:45 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:05:13 2016 -0400 libuv: Avoid including macOS CoreServices header globally We only need the availability macros in `unix/internal.h`. We already include CoreServices where needed in implementation files. diff --git a/Utilities/cmlibuv/src/unix/internal.h b/Utilities/cmlibuv/src/unix/internal.h index c7b6019..2570026 100644 --- a/Utilities/cmlibuv/src/unix/internal.h +++ b/Utilities/cmlibuv/src/unix/internal.h @@ -51,10 +51,6 @@ # include #endif /* _AIX */ -#if defined(__APPLE__) && !TARGET_OS_IPHONE -# include -#endif - #if defined(__ANDROID__) int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); # ifdef pthread_sigmask @@ -272,6 +268,7 @@ int uv__make_socketpair(int fds[2], int flags); int uv__make_pipe(int fds[2], int flags); #if defined(__APPLE__) +#include int uv__fsevents_init(uv_fs_event_t* handle); int uv__fsevents_close(uv_fs_event_t* handle); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a63aaaed051a51592f9ddc738febd58a4d99928a commit a63aaaed051a51592f9ddc738febd58a4d99928a Author: Brad King AuthorDate: Wed Aug 24 15:11:47 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:05:13 2016 -0400 libuv: Always include our own header first diff --git a/Utilities/cmlibuv/src/inet.c b/Utilities/cmlibuv/src/inet.c index da63a68..7c75e43 100644 --- a/Utilities/cmlibuv/src/inet.c +++ b/Utilities/cmlibuv/src/inet.c @@ -15,6 +15,9 @@ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "uv.h" +#include "uv-common.h" + #include #include @@ -24,9 +27,6 @@ # include #endif -#include "uv.h" -#include "uv-common.h" - #define UV__INET_ADDRSTRLEN 16 #define UV__INET6_ADDRSTRLEN 46 diff --git a/Utilities/cmlibuv/src/unix/getnameinfo.c b/Utilities/cmlibuv/src/unix/getnameinfo.c index daa798a..b2879d6 100644 --- a/Utilities/cmlibuv/src/unix/getnameinfo.c +++ b/Utilities/cmlibuv/src/unix/getnameinfo.c @@ -19,14 +19,14 @@ * IN THE SOFTWARE. */ +#include "uv.h" +#include "internal.h" + #include #include #include #include -#include "uv.h" -#include "internal.h" - static void uv__getnameinfo_work(struct uv__work* w) { uv_getnameinfo_t* req; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9130b53a5e949da07e10414e13b79d7abad2b4fa commit 9130b53a5e949da07e10414e13b79d7abad2b4fa Author: Brad King AuthorDate: Wed Aug 24 11:20:46 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:05:13 2016 -0400 libuv: Conditionally declare Windows APIs for VS 2008 and below diff --git a/Utilities/cmlibuv/include/uv-win.h b/Utilities/cmlibuv/include/uv-win.h index e8b9b15..89ee09a 100644 --- a/Utilities/cmlibuv/include/uv-win.h +++ b/Utilities/cmlibuv/include/uv-win.h @@ -99,23 +99,34 @@ typedef struct pollfd { # define WSAID_ACCEPTEX \ {0xb5367df1, 0xcbac, 0x11cf, \ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} +#endif +#ifndef WSAID_CONNECTEX # define WSAID_CONNECTEX \ {0x25a207b9, 0xddf3, 0x4660, \ {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}} +#endif +#ifndef WSAID_GETACCEPTEXSOCKADDRS # define WSAID_GETACCEPTEXSOCKADDRS \ {0xb5367df2, 0xcbac, 0x11cf, \ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} +#endif +#ifndef WSAID_DISCONNECTEX # define WSAID_DISCONNECTEX \ {0x7fda2e11, 0x8630, 0x436f, \ {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}} +#endif +#ifndef WSAID_TRANSMITFILE # define WSAID_TRANSMITFILE \ {0xb5367df0, 0xcbac, 0x11cf, \ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} +#endif +#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) \ + || (defined(_MSC_VER) && _MSC_VER < 1500) typedef BOOL (PASCAL *LPFN_ACCEPTEX) (SOCKET sListenSocket, SOCKET sAcceptSocket, diff --git a/Utilities/cmlibuv/src/win/winapi.h b/Utilities/cmlibuv/src/win/winapi.h index 341fcd0..597a93d 100644 --- a/Utilities/cmlibuv/src/win/winapi.h +++ b/Utilities/cmlibuv/src/win/winapi.h @@ -4118,6 +4118,14 @@ typedef const UNICODE_STRING *PCUNICODE_STRING; # define DEVICE_TYPE DWORD #endif +#ifndef VOLUME_NAME_DOS +# define VOLUME_NAME_DOS 0x0 +#endif + +#ifndef MAPVK_VK_TO_VSC +# define MAPVK_VK_TO_VSC (0) +#endif + /* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does * not. */ @@ -4583,7 +4591,8 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile) # define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 #endif -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) \ + || (defined(_MSC_VER) && _MSC_VER < 1500) typedef struct _OVERLAPPED_ENTRY { ULONG_PTR lpCompletionKey; LPOVERLAPPED lpOverlapped; diff --git a/Utilities/cmlibuv/src/win/winsock.h b/Utilities/cmlibuv/src/win/winsock.h index 7c007ab..3115fe3 100644 --- a/Utilities/cmlibuv/src/win/winsock.h +++ b/Utilities/cmlibuv/src/win/winsock.h @@ -146,7 +146,8 @@ typedef struct _AFD_RECV_INFO { #define IOCTL_AFD_POLL \ _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED) -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) \ + || (defined(_MSC_VER) && _MSC_VER < 1500) typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP { /* FIXME: __C89_NAMELESS was removed */ /* __C89_NAMELESS */ union { https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b52afa4655737f442af6017bab8d44158bdd466d commit b52afa4655737f442af6017bab8d44158bdd466d Author: Brad King AuthorDate: Wed Aug 24 11:18:25 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:05:13 2016 -0400 libuv: Fix anonymous union syntax diff --git a/Utilities/cmlibuv/src/win/winapi.h b/Utilities/cmlibuv/src/win/winapi.h index 16d9365..341fcd0 100644 --- a/Utilities/cmlibuv/src/win/winapi.h +++ b/Utilities/cmlibuv/src/win/winapi.h @@ -4145,7 +4145,7 @@ typedef const UNICODE_STRING *PCUNICODE_STRING; struct { UCHAR DataBuffer[1]; } GenericReparseBuffer; - } DUMMYUNIONNAME; + }; } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; #endif @@ -4153,7 +4153,7 @@ typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; PVOID Pointer; - } DUMMYUNIONNAME; + }; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=05dbc204cdb4c7d81f40f2e2174c51df7e3294b9 commit 05dbc204cdb4c7d81f40f2e2174c51df7e3294b9 Author: Brad King AuthorDate: Wed Aug 24 11:08:29 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:05:12 2016 -0400 libuv: Fix Windows API function typedef syntax diff --git a/Utilities/cmlibuv/include/uv-win.h b/Utilities/cmlibuv/include/uv-win.h index a75dba8..e8b9b15 100644 --- a/Utilities/cmlibuv/include/uv-win.h +++ b/Utilities/cmlibuv/include/uv-win.h @@ -116,7 +116,7 @@ typedef struct pollfd { {0xb5367df0, 0xcbac, 0x11cf, \ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} - typedef BOOL PASCAL (*LPFN_ACCEPTEX) + typedef BOOL (PASCAL *LPFN_ACCEPTEX) (SOCKET sListenSocket, SOCKET sAcceptSocket, PVOID lpOutputBuffer, @@ -126,7 +126,7 @@ typedef struct pollfd { LPDWORD lpdwBytesReceived, LPOVERLAPPED lpOverlapped); - typedef BOOL PASCAL (*LPFN_CONNECTEX) + typedef BOOL (PASCAL *LPFN_CONNECTEX) (SOCKET s, const struct sockaddr* name, int namelen, @@ -135,7 +135,7 @@ typedef struct pollfd { LPDWORD lpdwBytesSent, LPOVERLAPPED lpOverlapped); - typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS) + typedef void (PASCAL *LPFN_GETACCEPTEXSOCKADDRS) (PVOID lpOutputBuffer, DWORD dwReceiveDataLength, DWORD dwLocalAddressLength, @@ -145,13 +145,13 @@ typedef struct pollfd { LPSOCKADDR* RemoteSockaddr, LPINT RemoteSockaddrLength); - typedef BOOL PASCAL (*LPFN_DISCONNECTEX) + typedef BOOL (PASCAL *LPFN_DISCONNECTEX) (SOCKET hSocket, LPOVERLAPPED lpOverlapped, DWORD dwFlags, DWORD reserved); - typedef BOOL PASCAL (*LPFN_TRANSMITFILE) + typedef BOOL (PASCAL *LPFN_TRANSMITFILE) (SOCKET hSocket, HANDLE hFile, DWORD nNumberOfBytesToWrite, https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=75139374f07cff43eeab6b4302d560a077440d76 commit 75139374f07cff43eeab6b4302d560a077440d76 Author: Brad King AuthorDate: Wed Aug 24 14:48:37 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:05:12 2016 -0400 libuv: Install LICENSE file with CMake documentation When we install using the bundled libuv source, notify users of its license terms. diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt index f1faf18..e25ac82 100644 --- a/Utilities/cmlibuv/CMakeLists.txt +++ b/Utilities/cmlibuv/CMakeLists.txt @@ -223,3 +223,5 @@ include_directories( add_library(cmlibuv STATIC ${uv_sources}) target_link_libraries(cmlibuv ${uv_libraries}) set_property(TARGET cmlibuv PROPERTY COMPILE_DEFINITIONS ${uv_defines}) + +install(FILES LICENSE DESTINATION ${CMAKE_DOC_DIR}/cmlibuv) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=95dcc4e474b8ad10fea47c68df88678a6ae10fac commit 95dcc4e474b8ad10fea47c68df88678a6ae10fac Author: Brad King AuthorDate: Wed Aug 17 10:16:57 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:05:12 2016 -0400 libuv: Disable warnings to avoid changing 3rd party code Add '-w' or equivalent flag on compilers supporting it. Tell MSVC to use its lowest warning level inside libuv sources. diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt index 7f2d587..f1faf18 100644 --- a/Utilities/cmlibuv/CMakeLists.txt +++ b/Utilities/cmlibuv/CMakeLists.txt @@ -1,5 +1,13 @@ project(libuv C) +# Disable warnings to avoid changing 3rd party code. +if(CMAKE_C_COMPILER_ID MATCHES + "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w") +elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall") +endif() + find_package(Threads) set(uv_libraries ${CMAKE_THREAD_LIBS_INIT}) diff --git a/Utilities/cmlibuv/src/win/internal.h b/Utilities/cmlibuv/src/win/internal.h index b8cfde9..8a17e94 100644 --- a/Utilities/cmlibuv/src/win/internal.h +++ b/Utilities/cmlibuv/src/win/internal.h @@ -22,6 +22,10 @@ #ifndef UV_WIN_INTERNAL_H_ #define UV_WIN_INTERNAL_H_ +#if defined(_MSC_VER) +# pragma warning(push,1) +#endif + #include "uv.h" #include "../uv-common.h" https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=13b7e7587d50a52bb422852eb4d71a93eb8f18a6 commit 13b7e7587d50a52bb422852eb4d71a93eb8f18a6 Author: Brad King AuthorDate: Tue Aug 16 16:26:39 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:02:19 2016 -0400 libuv: Build the library within CMake Take logic from upstream `Makefile.am` and `configure.ac` to build libuv sources. Update `uv.h` to include KWSys Large File Support configuration so that consistent stream libraries are used (on AIX with XL). Add a `cm_uv.h` header to include the CMake-provided copy of the `uv.h` header from CMake sources. diff --git a/CMakeLists.txt b/CMakeLists.txt index 3aef619..958beb6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -464,6 +464,19 @@ macro (CMAKE_BUILD_UTILITIES) endif() #--------------------------------------------------------------------- + # Build libuv library. + if(NOT DEFINED CMAKE_USE_LIBUV) + set(CMAKE_USE_LIBUV 1) + endif() + if(CMAKE_USE_LIBUV) + set(CMAKE_LIBUV_LIBRARIES cmlibuv) + add_subdirectory(Utilities/cmlibuv) + CMAKE_SET_TARGET_FOLDER(cmlibuv "Utilities/3rdParty") + else() + set(CMAKE_LIBUV_LIBRARIES) + endif() + + #--------------------------------------------------------------------- # Build XMLRPC library for CMake and CTest. if(CTEST_USE_XMLRPC) find_package(XMLRPC QUIET REQUIRED libwww-client) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 3b94df7..8c74f60 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -582,6 +582,7 @@ target_link_libraries(CMakeLib cmsys ${CMAKE_TAR_LIBRARIES} ${CMAKE_COMPRESS_LIBRARIES} ${CMAKE_CURL_LIBRARIES} ${CMAKE_JSONCPP_LIBRARIES} + ${CMAKE_LIBUV_LIBRARIES} ${CMake_KWIML_LIBRARIES} ) diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in index 7e48b2d..cb671dd 100644 --- a/Source/cmConfigure.cmake.h.in +++ b/Source/cmConfigure.cmake.h.in @@ -28,6 +28,7 @@ #cmakedefine HAVE_UNSETENV #cmakedefine CMAKE_USE_ELF_PARSER #cmakedefine CMAKE_USE_MACH_PARSER +#cmakedefine CMAKE_USE_LIBUV #cmakedefine CMAKE_ENCODING_UTF8 #cmakedefine CMake_HAVE_CXX_NULLPTR #cmakedefine CMake_HAVE_CXX_OVERRIDE diff --git a/Utilities/cm_uv.h b/Utilities/cm_uv.h new file mode 100644 index 0000000..63ff597 --- /dev/null +++ b/Utilities/cm_uv.h @@ -0,0 +1,17 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2016 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cm_uv_h +#define cm_uv_h + +#include + +#endif diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt new file mode 100644 index 0000000..7f2d587 --- /dev/null +++ b/Utilities/cmlibuv/CMakeLists.txt @@ -0,0 +1,217 @@ +project(libuv C) + +find_package(Threads) + +set(uv_libraries ${CMAKE_THREAD_LIBS_INIT}) +set(uv_includes include src) +set(uv_headers + include/uv.h + include/uv-errno.h + include/uv-threadpool.h + include/uv-version.h + ) +set(uv_sources + src/fs-poll.c + src/heap-inl.h + src/inet.c + src/queue.h + src/threadpool.c + src/uv-common.c + src/uv-common.h + src/version.c + ) +if(WIN32) + list(APPEND uv_libraries + ws2_32 + psapi + iphlpapi + shell32 + userenv + ) + list(APPEND uv_includes + src/win + ) + list(APPEND uv_defines + WIN32_LEAN_AND_MEAN + _WIN32_WINNT=0x0600 + ) + list(APPEND uv_headers + include/uv-win.h + include/tree.h + ) + list(APPEND uv_sources + src/win/async.c + src/win/atomicops-inl.h + src/win/core.c + src/win/detect-wakeup.c + src/win/dl.c + src/win/error.c + src/win/fs-event.c + src/win/fs.c + src/win/getaddrinfo.c + src/win/getnameinfo.c + src/win/handle.c + src/win/handle-inl.h + src/win/internal.h + src/win/loop-watcher.c + src/win/pipe.c + src/win/poll.c + src/win/process-stdio.c + src/win/process.c + src/win/req.c + src/win/req-inl.h + src/win/signal.c + src/win/snprintf.c + src/win/stream.c + src/win/stream-inl.h + src/win/tcp.c + src/win/thread.c + src/win/timer.c + src/win/tty.c + src/win/udp.c + src/win/util.c + src/win/winapi.c + src/win/winapi.h + src/win/winsock.c + src/win/winsock.h + ) +else() + list(APPEND uv_includes + src/unix + ) + list(APPEND uv_headers + include/uv-unix.h + ) + list(APPEND uv_sources + src/unix/async.c + src/unix/atomic-ops.h + src/unix/core.c + src/unix/dl.c + src/unix/fs.c + src/unix/getaddrinfo.c + src/unix/getnameinfo.c + src/unix/internal.h + src/unix/loop-watcher.c + src/unix/loop.c + src/unix/pipe.c + src/unix/poll.c + src/unix/process.c + src/unix/signal.c + src/unix/spinlock.h + src/unix/stream.c + src/unix/tcp.c + src/unix/thread.c + src/unix/timer.c + src/unix/tty.c + src/unix/udp.c + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "AIX") + list(APPEND uv_libraries + perfstat + ) + list(APPEND uv_headers + include/uv-aix.h + ) + list(APPEND uv_defines + _ALL_SOURCE + _XOPEN_SOURCE=500 + _LINUX_SOURCE_COMPAT + _THREAD_SAFE + ) + list(APPEND uv_sources + src/unix/aix.c + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + list(APPEND uv_headers + include/uv-darwin.h + include/pthread-barrier.h + ) + list(APPEND uv_defines + _DARWIN_USE_64_BIT_INODE=1 + _DARWIN_UNLIMITED_SELECT=1 + ) + list(APPEND uv_sources + src/unix/darwin.c + src/unix/darwin-proctitle.c + src/unix/fsevents.c + src/unix/kqueue.c + src/unix/proctitle.c + src/unix/pthread-barrier.c + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + list(APPEND uv_libraries dl rt) + list(APPEND uv_headers + include/uv-linux.h + ) + list(APPEND uv_defines _GNU_SOURCE) + list(APPEND uv_sources + src/unix/linux-core.c + src/unix/linux-inotify.c + src/unix/linux-syscalls.c + src/unix/linux-syscalls.h + src/unix/proctitle.c + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + list(APPEND uv_headers + include/uv-bsd.h + ) + list(APPEND uv_sources + src/unix/freebsd.c + src/unix/kqueue.c + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") + list(APPEND uv_headers + include/uv-bsd.h + ) + list(APPEND uv_sources + src/unix/netbsd.c + src/unix/kqueue.c + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + list(APPEND uv_headers + include/uv-bsd.h + ) + list(APPEND uv_sources + src/unix/openbsd.c + src/unix/kqueue.c + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "SunOS") + list(APPEND uv_libraries + kstat + nsl + sendfile + socket + ) + list(APPEND uv_headers + include/uv-sunos.h + ) + list(APPEND uv_defines + __EXTENSIONS__ + _XOPEN_SOURCE=500 + ) + list(APPEND uv_sources + src/unix/sunos.c + ) +endif() + +include_directories( + ${uv_includes} + ${KWSYS_HEADER_ROOT} + ) +add_library(cmlibuv STATIC ${uv_sources}) +target_link_libraries(cmlibuv ${uv_libraries}) +set_property(TARGET cmlibuv PROPERTY COMPILE_DEFINITIONS ${uv_defines}) diff --git a/Utilities/cmlibuv/include/uv.h b/Utilities/cmlibuv/include/uv.h index baa0b28..e3e20dc 100644 --- a/Utilities/cmlibuv/include/uv.h +++ b/Utilities/cmlibuv/include/uv.h @@ -23,6 +23,10 @@ #ifndef UV_H #define UV_H + +/* Include KWSys Large File Support configuration. */ +#include + #ifdef __cplusplus extern "C" { #endif https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d96416fe482e17bc9f5a741d71d4a51a9b44f65e commit d96416fe482e17bc9f5a741d71d4a51a9b44f65e Merge: 3800fc2 3a713ea Author: Brad King AuthorDate: Wed Aug 31 09:01:07 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:01:07 2016 -0400 Merge branch 'upstream-libuv' into import-libuv * upstream-libuv: libuv 2016-08-30 (897738b1) diff --cc Utilities/cmlibuv/.gitattributes index 0000000,562b12e..562b12e mode 000000,100644..100644 --- a/Utilities/cmlibuv/.gitattributes +++ b/Utilities/cmlibuv/.gitattributes diff --cc Utilities/cmlibuv/LICENSE index 0000000,41ba44c..41ba44c mode 000000,100644..100644 --- a/Utilities/cmlibuv/LICENSE +++ b/Utilities/cmlibuv/LICENSE diff --cc Utilities/cmlibuv/include/android-ifaddrs.h index 0000000,9cd19fe..9cd19fe mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/android-ifaddrs.h +++ b/Utilities/cmlibuv/include/android-ifaddrs.h diff --cc Utilities/cmlibuv/include/pthread-barrier.h index 0000000,3e01705..3e01705 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/pthread-barrier.h +++ b/Utilities/cmlibuv/include/pthread-barrier.h diff --cc Utilities/cmlibuv/include/stdint-msvc2008.h index 0000000,d02608a..d02608a mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/stdint-msvc2008.h +++ b/Utilities/cmlibuv/include/stdint-msvc2008.h diff --cc Utilities/cmlibuv/include/tree.h index 0000000,f936416..f936416 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/tree.h +++ b/Utilities/cmlibuv/include/tree.h diff --cc Utilities/cmlibuv/include/uv-aix.h index 0000000,7dc992f..7dc992f mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-aix.h +++ b/Utilities/cmlibuv/include/uv-aix.h diff --cc Utilities/cmlibuv/include/uv-bsd.h index 0000000,2d72b3d..2d72b3d mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-bsd.h +++ b/Utilities/cmlibuv/include/uv-bsd.h diff --cc Utilities/cmlibuv/include/uv-darwin.h index 0000000,d226415..d226415 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-darwin.h +++ b/Utilities/cmlibuv/include/uv-darwin.h diff --cc Utilities/cmlibuv/include/uv-errno.h index 0000000,f137151..f137151 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-errno.h +++ b/Utilities/cmlibuv/include/uv-errno.h diff --cc Utilities/cmlibuv/include/uv-linux.h index 0000000,9b38405..9b38405 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-linux.h +++ b/Utilities/cmlibuv/include/uv-linux.h diff --cc Utilities/cmlibuv/include/uv-os390.h index 0000000,b0b068f..b0b068f mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-os390.h +++ b/Utilities/cmlibuv/include/uv-os390.h diff --cc Utilities/cmlibuv/include/uv-sunos.h index 0000000,0421664..0421664 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-sunos.h +++ b/Utilities/cmlibuv/include/uv-sunos.h diff --cc Utilities/cmlibuv/include/uv-threadpool.h index 0000000,9708ebd..9708ebd mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-threadpool.h +++ b/Utilities/cmlibuv/include/uv-threadpool.h diff --cc Utilities/cmlibuv/include/uv-unix.h index 0000000,bca2714..bca2714 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-unix.h +++ b/Utilities/cmlibuv/include/uv-unix.h diff --cc Utilities/cmlibuv/include/uv-version.h index 0000000,3cb9b5f..3cb9b5f mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-version.h +++ b/Utilities/cmlibuv/include/uv-version.h diff --cc Utilities/cmlibuv/include/uv-win.h index 0000000,a75dba8..a75dba8 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv-win.h +++ b/Utilities/cmlibuv/include/uv-win.h diff --cc Utilities/cmlibuv/include/uv.h index 0000000,baa0b28..baa0b28 mode 000000,100644..100644 --- a/Utilities/cmlibuv/include/uv.h +++ b/Utilities/cmlibuv/include/uv.h diff --cc Utilities/cmlibuv/src/fs-poll.c index 0000000,ee73d5a..ee73d5a mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/fs-poll.c +++ b/Utilities/cmlibuv/src/fs-poll.c diff --cc Utilities/cmlibuv/src/heap-inl.h index 0000000,1e2ed60..1e2ed60 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/heap-inl.h +++ b/Utilities/cmlibuv/src/heap-inl.h diff --cc Utilities/cmlibuv/src/inet.c index 0000000,da63a68..da63a68 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/inet.c +++ b/Utilities/cmlibuv/src/inet.c diff --cc Utilities/cmlibuv/src/queue.h index 0000000,ff3540a..ff3540a mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/queue.h +++ b/Utilities/cmlibuv/src/queue.h diff --cc Utilities/cmlibuv/src/threadpool.c index 0000000,2c5152b..2c5152b mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/threadpool.c +++ b/Utilities/cmlibuv/src/threadpool.c diff --cc Utilities/cmlibuv/src/unix/aix.c index 0000000,652cd98..652cd98 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/aix.c +++ b/Utilities/cmlibuv/src/unix/aix.c diff --cc Utilities/cmlibuv/src/unix/android-ifaddrs.c index 0000000,30f681b..30f681b mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/android-ifaddrs.c +++ b/Utilities/cmlibuv/src/unix/android-ifaddrs.c diff --cc Utilities/cmlibuv/src/unix/async.c index 0000000,393cdeb..393cdeb mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/async.c +++ b/Utilities/cmlibuv/src/unix/async.c diff --cc Utilities/cmlibuv/src/unix/atomic-ops.h index 0000000,815e355..815e355 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/atomic-ops.h +++ b/Utilities/cmlibuv/src/unix/atomic-ops.h diff --cc Utilities/cmlibuv/src/unix/core.c index 0000000,d88fc1d..d88fc1d mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/core.c +++ b/Utilities/cmlibuv/src/unix/core.c diff --cc Utilities/cmlibuv/src/unix/darwin-proctitle.c index 0000000,1142311..1142311 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/darwin-proctitle.c +++ b/Utilities/cmlibuv/src/unix/darwin-proctitle.c diff --cc Utilities/cmlibuv/src/unix/darwin.c index 0000000,cf95da2..cf95da2 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/darwin.c +++ b/Utilities/cmlibuv/src/unix/darwin.c diff --cc Utilities/cmlibuv/src/unix/dl.c index 0000000,fc1c052..fc1c052 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/dl.c +++ b/Utilities/cmlibuv/src/unix/dl.c diff --cc Utilities/cmlibuv/src/unix/freebsd.c index 0000000,cba44a3..cba44a3 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/freebsd.c +++ b/Utilities/cmlibuv/src/unix/freebsd.c diff --cc Utilities/cmlibuv/src/unix/fs.c index 0000000,216ef97..216ef97 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/fs.c +++ b/Utilities/cmlibuv/src/unix/fs.c diff --cc Utilities/cmlibuv/src/unix/fsevents.c index 0000000,d331a13..d331a13 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/fsevents.c +++ b/Utilities/cmlibuv/src/unix/fsevents.c diff --cc Utilities/cmlibuv/src/unix/getaddrinfo.c index 0000000,2049aea..2049aea mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/getaddrinfo.c +++ b/Utilities/cmlibuv/src/unix/getaddrinfo.c diff --cc Utilities/cmlibuv/src/unix/getnameinfo.c index 0000000,daa798a..daa798a mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/getnameinfo.c +++ b/Utilities/cmlibuv/src/unix/getnameinfo.c diff --cc Utilities/cmlibuv/src/unix/internal.h index 0000000,c7b6019..c7b6019 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/internal.h +++ b/Utilities/cmlibuv/src/unix/internal.h diff --cc Utilities/cmlibuv/src/unix/kqueue.c index 0000000,fffd462..fffd462 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/kqueue.c +++ b/Utilities/cmlibuv/src/unix/kqueue.c diff --cc Utilities/cmlibuv/src/unix/linux-core.c index 0000000,58dd813..58dd813 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/linux-core.c +++ b/Utilities/cmlibuv/src/unix/linux-core.c diff --cc Utilities/cmlibuv/src/unix/linux-inotify.c index 0000000,4708c05..4708c05 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/linux-inotify.c +++ b/Utilities/cmlibuv/src/unix/linux-inotify.c diff --cc Utilities/cmlibuv/src/unix/linux-syscalls.c index 0000000,89998de..89998de mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/linux-syscalls.c +++ b/Utilities/cmlibuv/src/unix/linux-syscalls.c diff --cc Utilities/cmlibuv/src/unix/linux-syscalls.h index 0000000,4c095e9..4c095e9 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/linux-syscalls.h +++ b/Utilities/cmlibuv/src/unix/linux-syscalls.h diff --cc Utilities/cmlibuv/src/unix/loop-watcher.c index 0000000,340bb0d..340bb0d mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/loop-watcher.c +++ b/Utilities/cmlibuv/src/unix/loop-watcher.c diff --cc Utilities/cmlibuv/src/unix/loop.c index 0000000,bd63c2f..bd63c2f mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/loop.c +++ b/Utilities/cmlibuv/src/unix/loop.c diff --cc Utilities/cmlibuv/src/unix/netbsd.c index 0000000,4a9e6cb..4a9e6cb mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/netbsd.c +++ b/Utilities/cmlibuv/src/unix/netbsd.c diff --cc Utilities/cmlibuv/src/unix/openbsd.c index 0000000,909288c..909288c mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/openbsd.c +++ b/Utilities/cmlibuv/src/unix/openbsd.c diff --cc Utilities/cmlibuv/src/unix/os390.c index 0000000,bcdbc4b..bcdbc4b mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/os390.c +++ b/Utilities/cmlibuv/src/unix/os390.c diff --cc Utilities/cmlibuv/src/unix/pipe.c index 0000000,b73994c..b73994c mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/pipe.c +++ b/Utilities/cmlibuv/src/unix/pipe.c diff --cc Utilities/cmlibuv/src/unix/poll.c index 0000000,4c0d478..4c0d478 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/poll.c +++ b/Utilities/cmlibuv/src/unix/poll.c diff --cc Utilities/cmlibuv/src/unix/process.c index 0000000,45f5b45..45f5b45 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/process.c +++ b/Utilities/cmlibuv/src/unix/process.c diff --cc Utilities/cmlibuv/src/unix/proctitle.c index 0000000,08d875f..08d875f mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/proctitle.c +++ b/Utilities/cmlibuv/src/unix/proctitle.c diff --cc Utilities/cmlibuv/src/unix/pthread-barrier.c index 0000000,f57bf25..f57bf25 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/pthread-barrier.c +++ b/Utilities/cmlibuv/src/unix/pthread-barrier.c diff --cc Utilities/cmlibuv/src/unix/pthread-fixes.c index 0000000,fb17995..fb17995 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/pthread-fixes.c +++ b/Utilities/cmlibuv/src/unix/pthread-fixes.c diff --cc Utilities/cmlibuv/src/unix/signal.c index 0000000,d82b9b7..d82b9b7 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/signal.c +++ b/Utilities/cmlibuv/src/unix/signal.c diff --cc Utilities/cmlibuv/src/unix/spinlock.h index 0000000,a20c83c..a20c83c mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/spinlock.h +++ b/Utilities/cmlibuv/src/unix/spinlock.h diff --cc Utilities/cmlibuv/src/unix/stream.c index 0000000,d20d0bc..d20d0bc mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/stream.c +++ b/Utilities/cmlibuv/src/unix/stream.c diff --cc Utilities/cmlibuv/src/unix/sunos.c index 0000000,3e7a759..3e7a759 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/sunos.c +++ b/Utilities/cmlibuv/src/unix/sunos.c diff --cc Utilities/cmlibuv/src/unix/tcp.c index 0000000,c423dcb..c423dcb mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/tcp.c +++ b/Utilities/cmlibuv/src/unix/tcp.c diff --cc Utilities/cmlibuv/src/unix/thread.c index 0000000,52989f7..52989f7 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/thread.c +++ b/Utilities/cmlibuv/src/unix/thread.c diff --cc Utilities/cmlibuv/src/unix/timer.c index 0000000,f46bdf4..f46bdf4 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/timer.c +++ b/Utilities/cmlibuv/src/unix/timer.c diff --cc Utilities/cmlibuv/src/unix/tty.c index 0000000,b2d37f4..b2d37f4 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/tty.c +++ b/Utilities/cmlibuv/src/unix/tty.c diff --cc Utilities/cmlibuv/src/unix/udp.c index 0000000,1cd4925..1cd4925 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/unix/udp.c +++ b/Utilities/cmlibuv/src/unix/udp.c diff --cc Utilities/cmlibuv/src/uv-common.c index 0000000,434a502..434a502 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/uv-common.c +++ b/Utilities/cmlibuv/src/uv-common.c diff --cc Utilities/cmlibuv/src/uv-common.h index 0000000,27902fd..27902fd mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/uv-common.h +++ b/Utilities/cmlibuv/src/uv-common.h diff --cc Utilities/cmlibuv/src/version.c index 0000000,686dedd..686dedd mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/version.c +++ b/Utilities/cmlibuv/src/version.c diff --cc Utilities/cmlibuv/src/win/async.c index 0000000,ad240ab..ad240ab mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/async.c +++ b/Utilities/cmlibuv/src/win/async.c diff --cc Utilities/cmlibuv/src/win/atomicops-inl.h index 0000000,61e0060..61e0060 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/atomicops-inl.h +++ b/Utilities/cmlibuv/src/win/atomicops-inl.h diff --cc Utilities/cmlibuv/src/win/core.c index 0000000,9d00afc..9d00afc mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/core.c +++ b/Utilities/cmlibuv/src/win/core.c diff --cc Utilities/cmlibuv/src/win/detect-wakeup.c index 0000000,a12179f..a12179f mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/detect-wakeup.c +++ b/Utilities/cmlibuv/src/win/detect-wakeup.c diff --cc Utilities/cmlibuv/src/win/dl.c index 0000000,39e400a..39e400a mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/dl.c +++ b/Utilities/cmlibuv/src/win/dl.c diff --cc Utilities/cmlibuv/src/win/error.c index 0000000,c512f35..c512f35 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/error.c +++ b/Utilities/cmlibuv/src/win/error.c diff --cc Utilities/cmlibuv/src/win/fs-event.c index 0000000,03e4adc..03e4adc mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/fs-event.c +++ b/Utilities/cmlibuv/src/win/fs-event.c diff --cc Utilities/cmlibuv/src/win/fs.c index 0000000,6a4157b..6a4157b mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/fs.c +++ b/Utilities/cmlibuv/src/win/fs.c diff --cc Utilities/cmlibuv/src/win/getaddrinfo.c index 0000000,744f8e0..744f8e0 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/getaddrinfo.c +++ b/Utilities/cmlibuv/src/win/getaddrinfo.c diff --cc Utilities/cmlibuv/src/win/getnameinfo.c index 0000000,66b64b8..66b64b8 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/getnameinfo.c +++ b/Utilities/cmlibuv/src/win/getnameinfo.c diff --cc Utilities/cmlibuv/src/win/handle-inl.h index 0000000,8d0334c..8d0334c mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/handle-inl.h +++ b/Utilities/cmlibuv/src/win/handle-inl.h diff --cc Utilities/cmlibuv/src/win/handle.c index 0000000,72b49d9..72b49d9 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/handle.c +++ b/Utilities/cmlibuv/src/win/handle.c diff --cc Utilities/cmlibuv/src/win/internal.h index 0000000,b8cfde9..b8cfde9 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/internal.h +++ b/Utilities/cmlibuv/src/win/internal.h diff --cc Utilities/cmlibuv/src/win/loop-watcher.c index 0000000,20e4509..20e4509 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/loop-watcher.c +++ b/Utilities/cmlibuv/src/win/loop-watcher.c diff --cc Utilities/cmlibuv/src/win/pipe.c index 0000000,2442be7..2442be7 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/pipe.c +++ b/Utilities/cmlibuv/src/win/pipe.c diff --cc Utilities/cmlibuv/src/win/poll.c index 0000000,d479e52..d479e52 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/poll.c +++ b/Utilities/cmlibuv/src/win/poll.c diff --cc Utilities/cmlibuv/src/win/process-stdio.c index 0000000,e3c06f5..e3c06f5 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/process-stdio.c +++ b/Utilities/cmlibuv/src/win/process-stdio.c diff --cc Utilities/cmlibuv/src/win/process.c index 0000000,855c374..855c374 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/process.c +++ b/Utilities/cmlibuv/src/win/process.c diff --cc Utilities/cmlibuv/src/win/req-inl.h index 0000000,b5e502e..b5e502e mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/req-inl.h +++ b/Utilities/cmlibuv/src/win/req-inl.h diff --cc Utilities/cmlibuv/src/win/req.c index 0000000,111cc5e..111cc5e mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/req.c +++ b/Utilities/cmlibuv/src/win/req.c diff --cc Utilities/cmlibuv/src/win/signal.c index 0000000,2c64a55..2c64a55 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/signal.c +++ b/Utilities/cmlibuv/src/win/signal.c diff --cc Utilities/cmlibuv/src/win/snprintf.c index 0000000,776c0e3..776c0e3 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/snprintf.c +++ b/Utilities/cmlibuv/src/win/snprintf.c diff --cc Utilities/cmlibuv/src/win/stream-inl.h index 0000000,b7a3c11..b7a3c11 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/stream-inl.h +++ b/Utilities/cmlibuv/src/win/stream-inl.h diff --cc Utilities/cmlibuv/src/win/stream.c index 0000000,a2466e5..a2466e5 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/stream.c +++ b/Utilities/cmlibuv/src/win/stream.c diff --cc Utilities/cmlibuv/src/win/tcp.c index 0000000,0709696..0709696 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/tcp.c +++ b/Utilities/cmlibuv/src/win/tcp.c diff --cc Utilities/cmlibuv/src/win/thread.c index 0000000,91684e9..91684e9 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/thread.c +++ b/Utilities/cmlibuv/src/win/thread.c diff --cc Utilities/cmlibuv/src/win/timer.c index 0000000,27ca771..27ca771 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/timer.c +++ b/Utilities/cmlibuv/src/win/timer.c diff --cc Utilities/cmlibuv/src/win/tty.c index 0000000,0975b33..0975b33 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/tty.c +++ b/Utilities/cmlibuv/src/win/tty.c diff --cc Utilities/cmlibuv/src/win/udp.c index 0000000,9bf1453..9bf1453 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/udp.c +++ b/Utilities/cmlibuv/src/win/udp.c diff --cc Utilities/cmlibuv/src/win/util.c index 0000000,4a2e501..4a2e501 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/util.c +++ b/Utilities/cmlibuv/src/win/util.c diff --cc Utilities/cmlibuv/src/win/winapi.c index 0000000,1fa179b..1fa179b mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/winapi.c +++ b/Utilities/cmlibuv/src/win/winapi.c diff --cc Utilities/cmlibuv/src/win/winapi.h index 0000000,16d9365..16d9365 mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/winapi.h +++ b/Utilities/cmlibuv/src/win/winapi.h diff --cc Utilities/cmlibuv/src/win/winsock.c index 0000000,d2e667e..d2e667e mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/winsock.c +++ b/Utilities/cmlibuv/src/win/winsock.c diff --cc Utilities/cmlibuv/src/win/winsock.h index 0000000,7c007ab..7c007ab mode 000000,100644..100644 --- a/Utilities/cmlibuv/src/win/winsock.h +++ b/Utilities/cmlibuv/src/win/winsock.h https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3a713eaaf7d289b130acf0007b197553a6528112 commit 3a713eaaf7d289b130acf0007b197553a6528112 Author: libuv upstream AuthorDate: Tue Aug 30 01:32:24 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 09:01:04 2016 -0400 libuv 2016-08-30 (897738b1) Code extracted from: https://github.com/libuv/libuv.git at commit 897738b160cd5950503a96c9fd5b1e9aab92b0ff (v1.x). diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..562b12e --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* -whitespace diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..41ba44c --- /dev/null +++ b/LICENSE @@ -0,0 +1,70 @@ +libuv is licensed for use as follows: + +==== +Copyright (c) 2015-present libuv project contributors. + +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. +==== + +This license applies to parts of libuv originating from the +https://github.com/joyent/libuv repository: + +==== + +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +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. + +==== + +This license applies to all parts of libuv that are not externally +maintained libraries. + +The externally maintained libraries used by libuv are: + + - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license. + + - inet_pton and inet_ntop implementations, contained in src/inet.c, are + copyright the Internet Systems Consortium, Inc., and licensed under the ISC + license. + + - stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three + clause BSD license. + + - pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile + Communications AB. Three clause BSD license. + + - android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design + Inc, Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement + n? 289016). Three clause BSD license. diff --git a/include/android-ifaddrs.h b/include/android-ifaddrs.h new file mode 100644 index 0000000..9cd19fe --- /dev/null +++ b/include/android-ifaddrs.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1995, 1999 + * Berkeley Software Design, 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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. + * + * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp + */ + +#ifndef _IFADDRS_H_ +#define _IFADDRS_H_ + +struct ifaddrs { + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + struct sockaddr *ifa_dstaddr; + void *ifa_data; +}; + +/* + * This may have been defined in . Note that if is + * to be included it must be included before this header file. + */ +#ifndef ifa_broadaddr +#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ +#endif + +#include + +__BEGIN_DECLS +extern int getifaddrs(struct ifaddrs **ifap); +extern void freeifaddrs(struct ifaddrs *ifa); +__END_DECLS + +#endif diff --git a/include/pthread-barrier.h b/include/pthread-barrier.h new file mode 100644 index 0000000..3e01705 --- /dev/null +++ b/include/pthread-barrier.h @@ -0,0 +1,66 @@ +/* +Copyright (c) 2016, Kari Tristan Helgason + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef _UV_PTHREAD_BARRIER_ +#define _UV_PTHREAD_BARRIER_ +#include +#include +#include /* sem_t */ + +#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 + +/* + * To maintain ABI compatibility with + * libuv v1.x struct is padded according + * to target platform + */ +#if defined(__ANDROID__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + sizeof(pthread_cond_t) + \ + sizeof(unsigned int) - \ + sizeof(void *) +#elif defined(__APPLE__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + 2 * sizeof(sem_t) + \ + 2 * sizeof(unsigned int) - \ + sizeof(void *) +#else +# define UV_BARRIER_STRUCT_PADDING 0 +#endif + +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; + unsigned threshold; + unsigned in; + unsigned out; +} _uv_barrier; + +typedef struct { + _uv_barrier* b; + char _pad[UV_BARRIER_STRUCT_PADDING]; +} pthread_barrier_t; + +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count); + +int pthread_barrier_wait(pthread_barrier_t* barrier); +int pthread_barrier_destroy(pthread_barrier_t *barrier); + +#endif /* _UV_PTHREAD_BARRIER_ */ diff --git a/include/stdint-msvc2008.h b/include/stdint-msvc2008.h new file mode 100644 index 0000000..d02608a --- /dev/null +++ b/include/stdint-msvc2008.h @@ -0,0 +1,247 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. 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. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] diff --git a/include/tree.h b/include/tree.h new file mode 100644 index 0000000..f936416 --- /dev/null +++ b/include/tree.h @@ -0,0 +1,768 @@ +/*- + * Copyright 2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef UV_TREE_H_ +#define UV_TREE_H_ + +#ifndef UV__UNUSED +# if __GNUC__ +# define UV__UNUSED __attribute__((unused)) +# else +# define UV__UNUSED +# endif +#endif + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type) \ +struct name { \ + struct type *sph_root; /* root of the tree */ \ +} + +#define SPLAY_INITIALIZER(root) \ + { NULL } + +#define SPLAY_INIT(root) do { \ + (root)->sph_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ENTRY(type) \ +struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ +} + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKLEFT(head, tmp, field) do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKRIGHT(head, tmp, field) do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ +void name##_SPLAY(struct name *, struct type *); \ +void name##_SPLAY_MINMAX(struct name *, int); \ +struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ +struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ +/* Finds the node with the same key as elm */ \ +static __inline struct type * \ +name##_SPLAY_FIND(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) \ + return(NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_NEXT(struct name *head, struct type *elm) \ +{ \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_MIN_MAX(struct name *head, int val) \ +{ \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ +} + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ +struct type * \ +name##_SPLAY_INSERT(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if(__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ +} \ + \ +struct type * \ +name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ +} \ + \ +void \ +name##_SPLAY(struct name *head, struct type *elm) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ + \ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \ + __left = __right = &__node; \ + \ + while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0){ \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} \ + \ +/* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ +void name##_SPLAY_MINMAX(struct name *head, int __comp) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + \ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \ + __left = __right = &__node; \ + \ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-black tree */ +#define RB_HEAD(name, type) \ +struct name { \ + struct type *rbh_root; /* root of the tree */ \ +} + +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#define RB_SET_BLACKRED(black, red, field) do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) do {} while (0) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) +#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp, UV__UNUSED static) +#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ +attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ +attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ +attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ +attr struct type *name##_RB_INSERT(struct name *, struct type *); \ +attr struct type *name##_RB_FIND(struct name *, struct type *); \ +attr struct type *name##_RB_NFIND(struct name *, struct type *); \ +attr struct type *name##_RB_NEXT(struct type *); \ +attr struct type *name##_RB_PREV(struct type *); \ +attr struct type *name##_RB_MINMAX(struct name *, int); \ + \ + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp,) +#define RB_GENERATE_STATIC(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp, UV__UNUSED static) +#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ +attr void \ +name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ +{ \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) != NULL && \ + RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field); \ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field); \ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field); \ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field); \ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ +} \ + \ +attr void \ +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, \ + struct type *elm) \ +{ \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field); \ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) { \ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)) \ + != NULL) \ + RB_COLOR(oleft, field) = RB_BLACK; \ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field); \ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field); \ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \ + RB_ROTATE_LEFT(head, parent, tmp, field); \ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field); \ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) { \ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)) \ + != NULL) \ + RB_COLOR(oright, field) = RB_BLACK; \ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field); \ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field); \ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \ + RB_ROTATE_RIGHT(head, parent, tmp, field); \ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ +} \ + \ +attr struct type * \ +name##_RB_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field)) != NULL) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old) \ + RB_LEFT(RB_PARENT(old, field), field) = elm; \ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm; \ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field)) != NULL); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ +color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ +} \ + \ +/* Inserts a node into the RB tree */ \ +attr struct type * \ +name##_RB_INSERT(struct name *head, struct type *elm) \ +{ \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = elm; \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ +} \ + \ +/* Finds the node with the same key as elm */ \ +attr struct type * \ +name##_RB_FIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ +} \ + \ +/* Finds the first node greater than or equal to the search key */ \ +attr struct type * \ +name##_RB_NFIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *res = NULL; \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) { \ + res = tmp; \ + tmp = RB_LEFT(tmp, field); \ + } \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (res); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_NEXT(struct type *elm) \ +{ \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_PREV(struct type *elm) \ +{ \ + if (RB_LEFT(elm, field)) { \ + elm = RB_LEFT(elm, field); \ + while (RB_RIGHT(elm, field)) \ + elm = RB_RIGHT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +attr struct type * \ +name##_RB_MINMAX(struct name *head, int val) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ +} + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_PREV(name, x, y) name##_RB_PREV(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) + +#define RB_FOREACH_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_SAFE(x, name, head, y) \ + for ((x) = RB_MIN(name, head); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE(x, name, head) \ + for ((x) = RB_MAX(name, head); \ + (x) != NULL; \ + (x) = name##_RB_PREV(x)) + +#define RB_FOREACH_REVERSE_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ + for ((x) = RB_MAX(name, head); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) + +#endif /* UV_TREE_H_ */ diff --git a/include/uv-aix.h b/include/uv-aix.h new file mode 100644 index 0000000..7dc992f --- /dev/null +++ b/include/uv-aix.h @@ -0,0 +1,32 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_AIX_H +#define UV_AIX_H + +#define UV_PLATFORM_LOOP_FIELDS \ + int fs_fd; \ + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + uv__io_t event_watcher; \ + char *dir_filename; \ + +#endif /* UV_AIX_H */ diff --git a/include/uv-bsd.h b/include/uv-bsd.h new file mode 100644 index 0000000..2d72b3d --- /dev/null +++ b/include/uv-bsd.h @@ -0,0 +1,34 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_BSD_H +#define UV_BSD_H + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + uv__io_t event_watcher; \ + +#define UV_IO_PRIVATE_PLATFORM_FIELDS \ + int rcount; \ + int wcount; \ + +#define UV_HAVE_KQUEUE 1 + +#endif /* UV_BSD_H */ diff --git a/include/uv-darwin.h b/include/uv-darwin.h new file mode 100644 index 0000000..d226415 --- /dev/null +++ b/include/uv-darwin.h @@ -0,0 +1,61 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_DARWIN_H +#define UV_DARWIN_H + +#if defined(__APPLE__) && defined(__MACH__) +# include +# include +# include +# include +# define UV_PLATFORM_SEM_T semaphore_t +#endif + +#define UV_IO_PRIVATE_PLATFORM_FIELDS \ + int rcount; \ + int wcount; \ + +#define UV_PLATFORM_LOOP_FIELDS \ + uv_thread_t cf_thread; \ + void* _cf_reserved; \ + void* cf_state; \ + uv_mutex_t cf_mutex; \ + uv_sem_t cf_sem; \ + void* cf_signals[2]; \ + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + uv__io_t event_watcher; \ + char* realpath; \ + int realpath_len; \ + int cf_flags; \ + uv_async_t* cf_cb; \ + void* cf_events[2]; \ + void* cf_member[2]; \ + int cf_error; \ + uv_mutex_t cf_mutex; \ + +#define UV_STREAM_PRIVATE_PLATFORM_FIELDS \ + void* select; \ + +#define UV_HAVE_KQUEUE 1 + +#endif /* UV_DARWIN_H */ diff --git a/include/uv-errno.h b/include/uv-errno.h new file mode 100644 index 0000000..f137151 --- /dev/null +++ b/include/uv-errno.h @@ -0,0 +1,419 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_ERRNO_H_ +#define UV_ERRNO_H_ + +#include + +#define UV__EOF (-4095) +#define UV__UNKNOWN (-4094) + +#define UV__EAI_ADDRFAMILY (-3000) +#define UV__EAI_AGAIN (-3001) +#define UV__EAI_BADFLAGS (-3002) +#define UV__EAI_CANCELED (-3003) +#define UV__EAI_FAIL (-3004) +#define UV__EAI_FAMILY (-3005) +#define UV__EAI_MEMORY (-3006) +#define UV__EAI_NODATA (-3007) +#define UV__EAI_NONAME (-3008) +#define UV__EAI_OVERFLOW (-3009) +#define UV__EAI_SERVICE (-3010) +#define UV__EAI_SOCKTYPE (-3011) +#define UV__EAI_BADHINTS (-3013) +#define UV__EAI_PROTOCOL (-3014) + +/* Only map to the system errno on non-Windows platforms. It's apparently + * a fairly common practice for Windows programmers to redefine errno codes. + */ +#if defined(E2BIG) && !defined(_WIN32) +# define UV__E2BIG (-E2BIG) +#else +# define UV__E2BIG (-4093) +#endif + +#if defined(EACCES) && !defined(_WIN32) +# define UV__EACCES (-EACCES) +#else +# define UV__EACCES (-4092) +#endif + +#if defined(EADDRINUSE) && !defined(_WIN32) +# define UV__EADDRINUSE (-EADDRINUSE) +#else +# define UV__EADDRINUSE (-4091) +#endif + +#if defined(EADDRNOTAVAIL) && !defined(_WIN32) +# define UV__EADDRNOTAVAIL (-EADDRNOTAVAIL) +#else +# define UV__EADDRNOTAVAIL (-4090) +#endif + +#if defined(EAFNOSUPPORT) && !defined(_WIN32) +# define UV__EAFNOSUPPORT (-EAFNOSUPPORT) +#else +# define UV__EAFNOSUPPORT (-4089) +#endif + +#if defined(EAGAIN) && !defined(_WIN32) +# define UV__EAGAIN (-EAGAIN) +#else +# define UV__EAGAIN (-4088) +#endif + +#if defined(EALREADY) && !defined(_WIN32) +# define UV__EALREADY (-EALREADY) +#else +# define UV__EALREADY (-4084) +#endif + +#if defined(EBADF) && !defined(_WIN32) +# define UV__EBADF (-EBADF) +#else +# define UV__EBADF (-4083) +#endif + +#if defined(EBUSY) && !defined(_WIN32) +# define UV__EBUSY (-EBUSY) +#else +# define UV__EBUSY (-4082) +#endif + +#if defined(ECANCELED) && !defined(_WIN32) +# define UV__ECANCELED (-ECANCELED) +#else +# define UV__ECANCELED (-4081) +#endif + +#if defined(ECHARSET) && !defined(_WIN32) +# define UV__ECHARSET (-ECHARSET) +#else +# define UV__ECHARSET (-4080) +#endif + +#if defined(ECONNABORTED) && !defined(_WIN32) +# define UV__ECONNABORTED (-ECONNABORTED) +#else +# define UV__ECONNABORTED (-4079) +#endif + +#if defined(ECONNREFUSED) && !defined(_WIN32) +# define UV__ECONNREFUSED (-ECONNREFUSED) +#else +# define UV__ECONNREFUSED (-4078) +#endif + +#if defined(ECONNRESET) && !defined(_WIN32) +# define UV__ECONNRESET (-ECONNRESET) +#else +# define UV__ECONNRESET (-4077) +#endif + +#if defined(EDESTADDRREQ) && !defined(_WIN32) +# define UV__EDESTADDRREQ (-EDESTADDRREQ) +#else +# define UV__EDESTADDRREQ (-4076) +#endif + +#if defined(EEXIST) && !defined(_WIN32) +# define UV__EEXIST (-EEXIST) +#else +# define UV__EEXIST (-4075) +#endif + +#if defined(EFAULT) && !defined(_WIN32) +# define UV__EFAULT (-EFAULT) +#else +# define UV__EFAULT (-4074) +#endif + +#if defined(EHOSTUNREACH) && !defined(_WIN32) +# define UV__EHOSTUNREACH (-EHOSTUNREACH) +#else +# define UV__EHOSTUNREACH (-4073) +#endif + +#if defined(EINTR) && !defined(_WIN32) +# define UV__EINTR (-EINTR) +#else +# define UV__EINTR (-4072) +#endif + +#if defined(EINVAL) && !defined(_WIN32) +# define UV__EINVAL (-EINVAL) +#else +# define UV__EINVAL (-4071) +#endif + +#if defined(EIO) && !defined(_WIN32) +# define UV__EIO (-EIO) +#else +# define UV__EIO (-4070) +#endif + +#if defined(EISCONN) && !defined(_WIN32) +# define UV__EISCONN (-EISCONN) +#else +# define UV__EISCONN (-4069) +#endif + +#if defined(EISDIR) && !defined(_WIN32) +# define UV__EISDIR (-EISDIR) +#else +# define UV__EISDIR (-4068) +#endif + +#if defined(ELOOP) && !defined(_WIN32) +# define UV__ELOOP (-ELOOP) +#else +# define UV__ELOOP (-4067) +#endif + +#if defined(EMFILE) && !defined(_WIN32) +# define UV__EMFILE (-EMFILE) +#else +# define UV__EMFILE (-4066) +#endif + +#if defined(EMSGSIZE) && !defined(_WIN32) +# define UV__EMSGSIZE (-EMSGSIZE) +#else +# define UV__EMSGSIZE (-4065) +#endif + +#if defined(ENAMETOOLONG) && !defined(_WIN32) +# define UV__ENAMETOOLONG (-ENAMETOOLONG) +#else +# define UV__ENAMETOOLONG (-4064) +#endif + +#if defined(ENETDOWN) && !defined(_WIN32) +# define UV__ENETDOWN (-ENETDOWN) +#else +# define UV__ENETDOWN (-4063) +#endif + +#if defined(ENETUNREACH) && !defined(_WIN32) +# define UV__ENETUNREACH (-ENETUNREACH) +#else +# define UV__ENETUNREACH (-4062) +#endif + +#if defined(ENFILE) && !defined(_WIN32) +# define UV__ENFILE (-ENFILE) +#else +# define UV__ENFILE (-4061) +#endif + +#if defined(ENOBUFS) && !defined(_WIN32) +# define UV__ENOBUFS (-ENOBUFS) +#else +# define UV__ENOBUFS (-4060) +#endif + +#if defined(ENODEV) && !defined(_WIN32) +# define UV__ENODEV (-ENODEV) +#else +# define UV__ENODEV (-4059) +#endif + +#if defined(ENOENT) && !defined(_WIN32) +# define UV__ENOENT (-ENOENT) +#else +# define UV__ENOENT (-4058) +#endif + +#if defined(ENOMEM) && !defined(_WIN32) +# define UV__ENOMEM (-ENOMEM) +#else +# define UV__ENOMEM (-4057) +#endif + +#if defined(ENONET) && !defined(_WIN32) +# define UV__ENONET (-ENONET) +#else +# define UV__ENONET (-4056) +#endif + +#if defined(ENOSPC) && !defined(_WIN32) +# define UV__ENOSPC (-ENOSPC) +#else +# define UV__ENOSPC (-4055) +#endif + +#if defined(ENOSYS) && !defined(_WIN32) +# define UV__ENOSYS (-ENOSYS) +#else +# define UV__ENOSYS (-4054) +#endif + +#if defined(ENOTCONN) && !defined(_WIN32) +# define UV__ENOTCONN (-ENOTCONN) +#else +# define UV__ENOTCONN (-4053) +#endif + +#if defined(ENOTDIR) && !defined(_WIN32) +# define UV__ENOTDIR (-ENOTDIR) +#else +# define UV__ENOTDIR (-4052) +#endif + +#if defined(ENOTEMPTY) && !defined(_WIN32) +# define UV__ENOTEMPTY (-ENOTEMPTY) +#else +# define UV__ENOTEMPTY (-4051) +#endif + +#if defined(ENOTSOCK) && !defined(_WIN32) +# define UV__ENOTSOCK (-ENOTSOCK) +#else +# define UV__ENOTSOCK (-4050) +#endif + +#if defined(ENOTSUP) && !defined(_WIN32) +# define UV__ENOTSUP (-ENOTSUP) +#else +# define UV__ENOTSUP (-4049) +#endif + +#if defined(EPERM) && !defined(_WIN32) +# define UV__EPERM (-EPERM) +#else +# define UV__EPERM (-4048) +#endif + +#if defined(EPIPE) && !defined(_WIN32) +# define UV__EPIPE (-EPIPE) +#else +# define UV__EPIPE (-4047) +#endif + +#if defined(EPROTO) && !defined(_WIN32) +# define UV__EPROTO (-EPROTO) +#else +# define UV__EPROTO (-4046) +#endif + +#if defined(EPROTONOSUPPORT) && !defined(_WIN32) +# define UV__EPROTONOSUPPORT (-EPROTONOSUPPORT) +#else +# define UV__EPROTONOSUPPORT (-4045) +#endif + +#if defined(EPROTOTYPE) && !defined(_WIN32) +# define UV__EPROTOTYPE (-EPROTOTYPE) +#else +# define UV__EPROTOTYPE (-4044) +#endif + +#if defined(EROFS) && !defined(_WIN32) +# define UV__EROFS (-EROFS) +#else +# define UV__EROFS (-4043) +#endif + +#if defined(ESHUTDOWN) && !defined(_WIN32) +# define UV__ESHUTDOWN (-ESHUTDOWN) +#else +# define UV__ESHUTDOWN (-4042) +#endif + +#if defined(ESPIPE) && !defined(_WIN32) +# define UV__ESPIPE (-ESPIPE) +#else +# define UV__ESPIPE (-4041) +#endif + +#if defined(ESRCH) && !defined(_WIN32) +# define UV__ESRCH (-ESRCH) +#else +# define UV__ESRCH (-4040) +#endif + +#if defined(ETIMEDOUT) && !defined(_WIN32) +# define UV__ETIMEDOUT (-ETIMEDOUT) +#else +# define UV__ETIMEDOUT (-4039) +#endif + +#if defined(ETXTBSY) && !defined(_WIN32) +# define UV__ETXTBSY (-ETXTBSY) +#else +# define UV__ETXTBSY (-4038) +#endif + +#if defined(EXDEV) && !defined(_WIN32) +# define UV__EXDEV (-EXDEV) +#else +# define UV__EXDEV (-4037) +#endif + +#if defined(EFBIG) && !defined(_WIN32) +# define UV__EFBIG (-EFBIG) +#else +# define UV__EFBIG (-4036) +#endif + +#if defined(ENOPROTOOPT) && !defined(_WIN32) +# define UV__ENOPROTOOPT (-ENOPROTOOPT) +#else +# define UV__ENOPROTOOPT (-4035) +#endif + +#if defined(ERANGE) && !defined(_WIN32) +# define UV__ERANGE (-ERANGE) +#else +# define UV__ERANGE (-4034) +#endif + +#if defined(ENXIO) && !defined(_WIN32) +# define UV__ENXIO (-ENXIO) +#else +# define UV__ENXIO (-4033) +#endif + +#if defined(EMLINK) && !defined(_WIN32) +# define UV__EMLINK (-EMLINK) +#else +# define UV__EMLINK (-4032) +#endif + +/* EHOSTDOWN is not visible on BSD-like systems when _POSIX_C_SOURCE is + * defined. Fortunately, its value is always 64 so it's possible albeit + * icky to hard-code it. + */ +#if defined(EHOSTDOWN) && !defined(_WIN32) +# define UV__EHOSTDOWN (-EHOSTDOWN) +#elif defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) +# define UV__EHOSTDOWN (-64) +#else +# define UV__EHOSTDOWN (-4031) +#endif + +#endif /* UV_ERRNO_H_ */ diff --git a/include/uv-linux.h b/include/uv-linux.h new file mode 100644 index 0000000..9b38405 --- /dev/null +++ b/include/uv-linux.h @@ -0,0 +1,34 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_LINUX_H +#define UV_LINUX_H + +#define UV_PLATFORM_LOOP_FIELDS \ + uv__io_t inotify_read_watcher; \ + void* inotify_watchers; \ + int inotify_fd; \ + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + void* watchers[2]; \ + int wd; \ + +#endif /* UV_LINUX_H */ diff --git a/include/uv-os390.h b/include/uv-os390.h new file mode 100644 index 0000000..b0b068f --- /dev/null +++ b/include/uv-os390.h @@ -0,0 +1,27 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * 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 UV_MVS_H +#define UV_MVS_H + +#define UV_PLATFORM_SEM_T int + +#endif /* UV_MVS_H */ diff --git a/include/uv-sunos.h b/include/uv-sunos.h new file mode 100644 index 0000000..0421664 --- /dev/null +++ b/include/uv-sunos.h @@ -0,0 +1,44 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_SUNOS_H +#define UV_SUNOS_H + +#include +#include + +/* For the sake of convenience and reduced #ifdef-ery in src/unix/sunos.c, + * add the fs_event fields even when this version of SunOS doesn't support + * file watching. + */ +#define UV_PLATFORM_LOOP_FIELDS \ + uv__io_t fs_event_watcher; \ + int fs_fd; \ + +#if defined(PORT_SOURCE_FILE) + +# define UV_PLATFORM_FS_EVENT_FIELDS \ + file_obj_t fo; \ + int fd; \ + +#endif /* defined(PORT_SOURCE_FILE) */ + +#endif /* UV_SUNOS_H */ diff --git a/include/uv-threadpool.h b/include/uv-threadpool.h new file mode 100644 index 0000000..9708ebd --- /dev/null +++ b/include/uv-threadpool.h @@ -0,0 +1,37 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +/* + * This file is private to libuv. It provides common functionality to both + * Windows and Unix backends. + */ + +#ifndef UV_THREADPOOL_H_ +#define UV_THREADPOOL_H_ + +struct uv__work { + void (*work)(struct uv__work *w); + void (*done)(struct uv__work *w, int status); + struct uv_loop_s* loop; + void* wq[2]; +}; + +#endif /* UV_THREADPOOL_H_ */ diff --git a/include/uv-unix.h b/include/uv-unix.h new file mode 100644 index 0000000..bca2714 --- /dev/null +++ b/include/uv-unix.h @@ -0,0 +1,371 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_UNIX_H +#define UV_UNIX_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "uv-threadpool.h" + +#if defined(__linux__) +# include "uv-linux.h" +#elif defined(_AIX) +# include "uv-aix.h" +#elif defined(__sun) +# include "uv-sunos.h" +#elif defined(__APPLE__) +# include "uv-darwin.h" +#elif defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# include "uv-bsd.h" +#endif + +#ifndef PTHREAD_BARRIER_SERIAL_THREAD +# include "pthread-barrier.h" +#endif + +#ifndef NI_MAXHOST +# define NI_MAXHOST 1025 +#endif + +#ifndef NI_MAXSERV +# define NI_MAXSERV 32 +#endif + +#ifndef UV_IO_PRIVATE_PLATFORM_FIELDS +# define UV_IO_PRIVATE_PLATFORM_FIELDS /* empty */ +#endif + +struct uv__io_s; +struct uv__async; +struct uv_loop_s; + +typedef void (*uv__io_cb)(struct uv_loop_s* loop, + struct uv__io_s* w, + unsigned int events); +typedef struct uv__io_s uv__io_t; + +struct uv__io_s { + uv__io_cb cb; + void* pending_queue[2]; + void* watcher_queue[2]; + unsigned int pevents; /* Pending event mask i.e. mask at next tick. */ + unsigned int events; /* Current event mask. */ + int fd; + UV_IO_PRIVATE_PLATFORM_FIELDS +}; + +typedef void (*uv__async_cb)(struct uv_loop_s* loop, + struct uv__async* w, + unsigned int nevents); + +struct uv__async { + uv__async_cb cb; + uv__io_t io_watcher; + int wfd; +}; + +#ifndef UV_PLATFORM_SEM_T +# define UV_PLATFORM_SEM_T sem_t +#endif + +#ifndef UV_PLATFORM_LOOP_FIELDS +# define UV_PLATFORM_LOOP_FIELDS /* empty */ +#endif + +#ifndef UV_PLATFORM_FS_EVENT_FIELDS +# define UV_PLATFORM_FS_EVENT_FIELDS /* empty */ +#endif + +#ifndef UV_STREAM_PRIVATE_PLATFORM_FIELDS +# define UV_STREAM_PRIVATE_PLATFORM_FIELDS /* empty */ +#endif + +/* Note: May be cast to struct iovec. See writev(2). */ +typedef struct uv_buf_t { + char* base; + size_t len; +} uv_buf_t; + +typedef int uv_file; +typedef int uv_os_sock_t; +typedef int uv_os_fd_t; + +#define UV_ONCE_INIT PTHREAD_ONCE_INIT + +typedef pthread_once_t uv_once_t; +typedef pthread_t uv_thread_t; +typedef pthread_mutex_t uv_mutex_t; +typedef pthread_rwlock_t uv_rwlock_t; +typedef UV_PLATFORM_SEM_T uv_sem_t; +typedef pthread_cond_t uv_cond_t; +typedef pthread_key_t uv_key_t; +typedef pthread_barrier_t uv_barrier_t; + + +/* Platform-specific definitions for uv_spawn support. */ +typedef gid_t uv_gid_t; +typedef uid_t uv_uid_t; + +typedef struct dirent uv__dirent_t; + +#if defined(DT_UNKNOWN) +# define HAVE_DIRENT_TYPES +# if defined(DT_REG) +# define UV__DT_FILE DT_REG +# else +# define UV__DT_FILE -1 +# endif +# if defined(DT_DIR) +# define UV__DT_DIR DT_DIR +# else +# define UV__DT_DIR -2 +# endif +# if defined(DT_LNK) +# define UV__DT_LINK DT_LNK +# else +# define UV__DT_LINK -3 +# endif +# if defined(DT_FIFO) +# define UV__DT_FIFO DT_FIFO +# else +# define UV__DT_FIFO -4 +# endif +# if defined(DT_SOCK) +# define UV__DT_SOCKET DT_SOCK +# else +# define UV__DT_SOCKET -5 +# endif +# if defined(DT_CHR) +# define UV__DT_CHAR DT_CHR +# else +# define UV__DT_CHAR -6 +# endif +# if defined(DT_BLK) +# define UV__DT_BLOCK DT_BLK +# else +# define UV__DT_BLOCK -7 +# endif +#endif + +/* Platform-specific definitions for uv_dlopen support. */ +#define UV_DYNAMIC /* empty */ + +typedef struct { + void* handle; + char* errmsg; +} uv_lib_t; + +#define UV_LOOP_PRIVATE_FIELDS \ + unsigned long flags; \ + int backend_fd; \ + void* pending_queue[2]; \ + void* watcher_queue[2]; \ + uv__io_t** watchers; \ + unsigned int nwatchers; \ + unsigned int nfds; \ + void* wq[2]; \ + uv_mutex_t wq_mutex; \ + uv_async_t wq_async; \ + uv_rwlock_t cloexec_lock; \ + uv_handle_t* closing_handles; \ + void* process_handles[2]; \ + void* prepare_handles[2]; \ + void* check_handles[2]; \ + void* idle_handles[2]; \ + void* async_handles[2]; \ + struct uv__async async_watcher; \ + struct { \ + void* min; \ + unsigned int nelts; \ + } timer_heap; \ + uint64_t timer_counter; \ + uint64_t time; \ + int signal_pipefd[2]; \ + uv__io_t signal_io_watcher; \ + uv_signal_t child_watcher; \ + int emfile_fd; \ + UV_PLATFORM_LOOP_FIELDS \ + +#define UV_REQ_TYPE_PRIVATE /* empty */ + +#define UV_REQ_PRIVATE_FIELDS /* empty */ + +#define UV_PRIVATE_REQ_TYPES /* empty */ + +#define UV_WRITE_PRIVATE_FIELDS \ + void* queue[2]; \ + unsigned int write_index; \ + uv_buf_t* bufs; \ + unsigned int nbufs; \ + int error; \ + uv_buf_t bufsml[4]; \ + +#define UV_CONNECT_PRIVATE_FIELDS \ + void* queue[2]; \ + +#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */ + +#define UV_UDP_SEND_PRIVATE_FIELDS \ + void* queue[2]; \ + struct sockaddr_storage addr; \ + unsigned int nbufs; \ + uv_buf_t* bufs; \ + ssize_t status; \ + uv_udp_send_cb send_cb; \ + uv_buf_t bufsml[4]; \ + +#define UV_HANDLE_PRIVATE_FIELDS \ + uv_handle_t* next_closing; \ + unsigned int flags; \ + +#define UV_STREAM_PRIVATE_FIELDS \ + uv_connect_t *connect_req; \ + uv_shutdown_t *shutdown_req; \ + uv__io_t io_watcher; \ + void* write_queue[2]; \ + void* write_completed_queue[2]; \ + uv_connection_cb connection_cb; \ + int delayed_error; \ + int accepted_fd; \ + void* queued_fds; \ + UV_STREAM_PRIVATE_PLATFORM_FIELDS \ + +#define UV_TCP_PRIVATE_FIELDS /* empty */ + +#define UV_UDP_PRIVATE_FIELDS \ + uv_alloc_cb alloc_cb; \ + uv_udp_recv_cb recv_cb; \ + uv__io_t io_watcher; \ + void* write_queue[2]; \ + void* write_completed_queue[2]; \ + +#define UV_PIPE_PRIVATE_FIELDS \ + const char* pipe_fname; /* strdup'ed */ + +#define UV_POLL_PRIVATE_FIELDS \ + uv__io_t io_watcher; + +#define UV_PREPARE_PRIVATE_FIELDS \ + uv_prepare_cb prepare_cb; \ + void* queue[2]; \ + +#define UV_CHECK_PRIVATE_FIELDS \ + uv_check_cb check_cb; \ + void* queue[2]; \ + +#define UV_IDLE_PRIVATE_FIELDS \ + uv_idle_cb idle_cb; \ + void* queue[2]; \ + +#define UV_ASYNC_PRIVATE_FIELDS \ + uv_async_cb async_cb; \ + void* queue[2]; \ + int pending; \ + +#define UV_TIMER_PRIVATE_FIELDS \ + uv_timer_cb timer_cb; \ + void* heap_node[3]; \ + uint64_t timeout; \ + uint64_t repeat; \ + uint64_t start_id; + +#define UV_GETADDRINFO_PRIVATE_FIELDS \ + struct uv__work work_req; \ + uv_getaddrinfo_cb cb; \ + struct addrinfo* hints; \ + char* hostname; \ + char* service; \ + struct addrinfo* addrinfo; \ + int retcode; + +#define UV_GETNAMEINFO_PRIVATE_FIELDS \ + struct uv__work work_req; \ + uv_getnameinfo_cb getnameinfo_cb; \ + struct sockaddr_storage storage; \ + int flags; \ + char host[NI_MAXHOST]; \ + char service[NI_MAXSERV]; \ + int retcode; + +#define UV_PROCESS_PRIVATE_FIELDS \ + void* queue[2]; \ + int status; \ + +#define UV_FS_PRIVATE_FIELDS \ + const char *new_path; \ + uv_file file; \ + int flags; \ + mode_t mode; \ + unsigned int nbufs; \ + uv_buf_t* bufs; \ + off_t off; \ + uv_uid_t uid; \ + uv_gid_t gid; \ + double atime; \ + double mtime; \ + struct uv__work work_req; \ + uv_buf_t bufsml[4]; \ + +#define UV_WORK_PRIVATE_FIELDS \ + struct uv__work work_req; + +#define UV_TTY_PRIVATE_FIELDS \ + struct termios orig_termios; \ + int mode; + +#define UV_SIGNAL_PRIVATE_FIELDS \ + /* RB_ENTRY(uv_signal_s) tree_entry; */ \ + struct { \ + struct uv_signal_s* rbe_left; \ + struct uv_signal_s* rbe_right; \ + struct uv_signal_s* rbe_parent; \ + int rbe_color; \ + } tree_entry; \ + /* Use two counters here so we don have to fiddle with atomics. */ \ + unsigned int caught_signals; \ + unsigned int dispatched_signals; + +#define UV_FS_EVENT_PRIVATE_FIELDS \ + uv_fs_event_cb cb; \ + UV_PLATFORM_FS_EVENT_FIELDS \ + +#endif /* UV_UNIX_H */ diff --git a/include/uv-version.h b/include/uv-version.h new file mode 100644 index 0000000..3cb9b5f --- /dev/null +++ b/include/uv-version.h @@ -0,0 +1,43 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_VERSION_H +#define UV_VERSION_H + + /* + * Versions with the same major number are ABI stable. API is allowed to + * evolve between minor releases, but only in a backwards compatible way. + * Make sure you update the -soname directives in configure.ac + * and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but + * not UV_VERSION_PATCH.) + */ + +#define UV_VERSION_MAJOR 1 +#define UV_VERSION_MINOR 9 +#define UV_VERSION_PATCH 2 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" + +#define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ + (UV_VERSION_MINOR << 8) | \ + (UV_VERSION_PATCH)) + +#endif /* UV_VERSION_H */ diff --git a/include/uv-win.h b/include/uv-win.h new file mode 100644 index 0000000..a75dba8 --- /dev/null +++ b/include/uv-win.h @@ -0,0 +1,649 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 _WIN32_WINNT +# define _WIN32_WINNT 0x0502 +#endif + +#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED) +typedef intptr_t ssize_t; +# define _SSIZE_T_ +# define _SSIZE_T_DEFINED +#endif + +#include + +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +typedef struct pollfd { + SOCKET fd; + short events; + short revents; +} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD; +#endif + +#ifndef LOCALE_INVARIANT +# define LOCALE_INVARIANT 0x007f +#endif + +#include +#include +#include + +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#include "tree.h" +#include "uv-threadpool.h" + +#define MAX_PIPENAME_LEN 256 + +#ifndef S_IFLNK +# define S_IFLNK 0xA000 +#endif + +/* Additional signals supported by uv_signal and or uv_kill. The CRT defines + * the following signals already: + * + * #define SIGINT 2 + * #define SIGILL 4 + * #define SIGABRT_COMPAT 6 + * #define SIGFPE 8 + * #define SIGSEGV 11 + * #define SIGTERM 15 + * #define SIGBREAK 21 + * #define SIGABRT 22 + * + * The additional signals have values that are common on other Unix + * variants (Linux and Darwin) + */ +#define SIGHUP 1 +#define SIGKILL 9 +#define SIGWINCH 28 + +/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many */ +/* unix-like platforms. However MinGW doesn't define it, so we do. */ +#ifndef SIGABRT_COMPAT +# define SIGABRT_COMPAT 6 +#endif + +/* + * Guids and typedefs for winsock extension functions + * Mingw32 doesn't have these :-( + */ +#ifndef WSAID_ACCEPTEX +# define WSAID_ACCEPTEX \ + {0xb5367df1, 0xcbac, 0x11cf, \ + {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} + +# define WSAID_CONNECTEX \ + {0x25a207b9, 0xddf3, 0x4660, \ + {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}} + +# define WSAID_GETACCEPTEXSOCKADDRS \ + {0xb5367df2, 0xcbac, 0x11cf, \ + {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} + +# define WSAID_DISCONNECTEX \ + {0x7fda2e11, 0x8630, 0x436f, \ + {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}} + +# define WSAID_TRANSMITFILE \ + {0xb5367df0, 0xcbac, 0x11cf, \ + {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} + + typedef BOOL PASCAL (*LPFN_ACCEPTEX) + (SOCKET sListenSocket, + SOCKET sAcceptSocket, + PVOID lpOutputBuffer, + DWORD dwReceiveDataLength, + DWORD dwLocalAddressLength, + DWORD dwRemoteAddressLength, + LPDWORD lpdwBytesReceived, + LPOVERLAPPED lpOverlapped); + + typedef BOOL PASCAL (*LPFN_CONNECTEX) + (SOCKET s, + const struct sockaddr* name, + int namelen, + PVOID lpSendBuffer, + DWORD dwSendDataLength, + LPDWORD lpdwBytesSent, + LPOVERLAPPED lpOverlapped); + + typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS) + (PVOID lpOutputBuffer, + DWORD dwReceiveDataLength, + DWORD dwLocalAddressLength, + DWORD dwRemoteAddressLength, + LPSOCKADDR* LocalSockaddr, + LPINT LocalSockaddrLength, + LPSOCKADDR* RemoteSockaddr, + LPINT RemoteSockaddrLength); + + typedef BOOL PASCAL (*LPFN_DISCONNECTEX) + (SOCKET hSocket, + LPOVERLAPPED lpOverlapped, + DWORD dwFlags, + DWORD reserved); + + typedef BOOL PASCAL (*LPFN_TRANSMITFILE) + (SOCKET hSocket, + HANDLE hFile, + DWORD nNumberOfBytesToWrite, + DWORD nNumberOfBytesPerSend, + LPOVERLAPPED lpOverlapped, + LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, + DWORD dwFlags); + + typedef PVOID RTL_SRWLOCK; + typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK; +#endif + +typedef int (WSAAPI* LPFN_WSARECV) + (SOCKET socket, + LPWSABUF buffers, + DWORD buffer_count, + LPDWORD bytes, + LPDWORD flags, + LPWSAOVERLAPPED overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); + +typedef int (WSAAPI* LPFN_WSARECVFROM) + (SOCKET socket, + LPWSABUF buffers, + DWORD buffer_count, + LPDWORD bytes, + LPDWORD flags, + struct sockaddr* addr, + LPINT addr_len, + LPWSAOVERLAPPED overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); + +#ifndef _NTDEF_ + typedef LONG NTSTATUS; + typedef NTSTATUS *PNTSTATUS; +#endif + +#ifndef RTL_CONDITION_VARIABLE_INIT + typedef PVOID CONDITION_VARIABLE, *PCONDITION_VARIABLE; +#endif + +typedef struct _AFD_POLL_HANDLE_INFO { + HANDLE Handle; + ULONG Events; + NTSTATUS Status; +} AFD_POLL_HANDLE_INFO, *PAFD_POLL_HANDLE_INFO; + +typedef struct _AFD_POLL_INFO { + LARGE_INTEGER Timeout; + ULONG NumberOfHandles; + ULONG Exclusive; + AFD_POLL_HANDLE_INFO Handles[1]; +} AFD_POLL_INFO, *PAFD_POLL_INFO; + +#define UV_MSAFD_PROVIDER_COUNT 3 + + +/** + * It should be possible to cast uv_buf_t[] to WSABUF[] + * see http://msdn.microsoft.com/en-us/library/ms741542(v=vs.85).aspx + */ +typedef struct uv_buf_t { + ULONG len; + char* base; +} uv_buf_t; + +typedef int uv_file; +typedef SOCKET uv_os_sock_t; +typedef HANDLE uv_os_fd_t; + +typedef HANDLE uv_thread_t; + +typedef HANDLE uv_sem_t; + +typedef CRITICAL_SECTION uv_mutex_t; + +/* This condition variable implementation is based on the SetEvent solution + * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html + * We could not use the SignalObjectAndWait solution (section 3.4) because + * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and + * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs. + */ + +typedef union { + CONDITION_VARIABLE cond_var; + struct { + unsigned int waiters_count; + CRITICAL_SECTION waiters_count_lock; + HANDLE signal_event; + HANDLE broadcast_event; + } fallback; +} uv_cond_t; + +typedef union { + struct { + unsigned int num_readers_; + CRITICAL_SECTION num_readers_lock_; + HANDLE write_semaphore_; + } state_; + /* TODO: remove me in v2.x. */ + struct { + SRWLOCK unused_; + } unused1_; + /* TODO: remove me in v2.x. */ + struct { + uv_mutex_t unused1_; + uv_mutex_t unused2_; + } unused2_; +} uv_rwlock_t; + +typedef struct { + unsigned int n; + unsigned int count; + uv_mutex_t mutex; + uv_sem_t turnstile1; + uv_sem_t turnstile2; +} uv_barrier_t; + +typedef struct { + DWORD tls_index; +} uv_key_t; + +#define UV_ONCE_INIT { 0, NULL } + +typedef struct uv_once_s { + unsigned char ran; + HANDLE event; +} uv_once_t; + +/* Platform-specific definitions for uv_spawn support. */ +typedef unsigned char uv_uid_t; +typedef unsigned char uv_gid_t; + +typedef struct uv__dirent_s { + int d_type; + char d_name[1]; +} uv__dirent_t; + +#define HAVE_DIRENT_TYPES +#define UV__DT_DIR UV_DIRENT_DIR +#define UV__DT_FILE UV_DIRENT_FILE +#define UV__DT_LINK UV_DIRENT_LINK +#define UV__DT_FIFO UV_DIRENT_FIFO +#define UV__DT_SOCKET UV_DIRENT_SOCKET +#define UV__DT_CHAR UV_DIRENT_CHAR +#define UV__DT_BLOCK UV_DIRENT_BLOCK + +/* Platform-specific definitions for uv_dlopen support. */ +#define UV_DYNAMIC FAR WINAPI +typedef struct { + HMODULE handle; + char* errmsg; +} uv_lib_t; + +RB_HEAD(uv_timer_tree_s, uv_timer_s); + +#define UV_LOOP_PRIVATE_FIELDS \ + /* The loop's I/O completion port */ \ + HANDLE iocp; \ + /* The current time according to the event loop. in msecs. */ \ + uint64_t time; \ + /* Tail of a single-linked circular queue of pending reqs. If the queue */ \ + /* is empty, tail_ is NULL. If there is only one item, */ \ + /* tail_->next_req == tail_ */ \ + uv_req_t* pending_reqs_tail; \ + /* Head of a single-linked list of closed handles */ \ + uv_handle_t* endgame_handles; \ + /* The head of the timers tree */ \ + struct uv_timer_tree_s timers; \ + /* Lists of active loop (prepare / check / idle) watchers */ \ + uv_prepare_t* prepare_handles; \ + uv_check_t* check_handles; \ + uv_idle_t* idle_handles; \ + /* This pointer will refer to the prepare/check/idle handle whose */ \ + /* callback is scheduled to be called next. This is needed to allow */ \ + /* safe removal from one of the lists above while that list being */ \ + /* iterated over. */ \ + uv_prepare_t* next_prepare_handle; \ + uv_check_t* next_check_handle; \ + uv_idle_t* next_idle_handle; \ + /* This handle holds the peer sockets for the fast variant of uv_poll_t */ \ + SOCKET poll_peer_sockets[UV_MSAFD_PROVIDER_COUNT]; \ + /* Counter to keep track of active tcp streams */ \ + unsigned int active_tcp_streams; \ + /* Counter to keep track of active udp streams */ \ + unsigned int active_udp_streams; \ + /* Counter to started timer */ \ + uint64_t timer_counter; \ + /* Threadpool */ \ + void* wq[2]; \ + uv_mutex_t wq_mutex; \ + uv_async_t wq_async; + +#define UV_REQ_TYPE_PRIVATE \ + /* TODO: remove the req suffix */ \ + UV_ACCEPT, \ + UV_FS_EVENT_REQ, \ + UV_POLL_REQ, \ + UV_PROCESS_EXIT, \ + UV_READ, \ + UV_UDP_RECV, \ + UV_WAKEUP, \ + UV_SIGNAL_REQ, + +#define UV_REQ_PRIVATE_FIELDS \ + union { \ + /* Used by I/O operations */ \ + struct { \ + OVERLAPPED overlapped; \ + size_t queued_bytes; \ + } io; \ + } u; \ + struct uv_req_s* next_req; + +#define UV_WRITE_PRIVATE_FIELDS \ + int ipc_header; \ + uv_buf_t write_buffer; \ + HANDLE event_handle; \ + HANDLE wait_handle; + +#define UV_CONNECT_PRIVATE_FIELDS \ + /* empty */ + +#define UV_SHUTDOWN_PRIVATE_FIELDS \ + /* empty */ + +#define UV_UDP_SEND_PRIVATE_FIELDS \ + /* empty */ + +#define UV_PRIVATE_REQ_TYPES \ + typedef struct uv_pipe_accept_s { \ + UV_REQ_FIELDS \ + HANDLE pipeHandle; \ + struct uv_pipe_accept_s* next_pending; \ + } uv_pipe_accept_t; \ + \ + typedef struct uv_tcp_accept_s { \ + UV_REQ_FIELDS \ + SOCKET accept_socket; \ + char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \ + HANDLE event_handle; \ + HANDLE wait_handle; \ + struct uv_tcp_accept_s* next_pending; \ + } uv_tcp_accept_t; \ + \ + typedef struct uv_read_s { \ + UV_REQ_FIELDS \ + HANDLE event_handle; \ + HANDLE wait_handle; \ + } uv_read_t; + +#define uv_stream_connection_fields \ + unsigned int write_reqs_pending; \ + uv_shutdown_t* shutdown_req; + +#define uv_stream_server_fields \ + uv_connection_cb connection_cb; + +#define UV_STREAM_PRIVATE_FIELDS \ + unsigned int reqs_pending; \ + int activecnt; \ + uv_read_t read_req; \ + union { \ + struct { uv_stream_connection_fields } conn; \ + struct { uv_stream_server_fields } serv; \ + } stream; + +#define uv_tcp_server_fields \ + uv_tcp_accept_t* accept_reqs; \ + unsigned int processed_accepts; \ + uv_tcp_accept_t* pending_accepts; \ + LPFN_ACCEPTEX func_acceptex; + +#define uv_tcp_connection_fields \ + uv_buf_t read_buffer; \ + LPFN_CONNECTEX func_connectex; + +#define UV_TCP_PRIVATE_FIELDS \ + SOCKET socket; \ + int delayed_error; \ + union { \ + struct { uv_tcp_server_fields } serv; \ + struct { uv_tcp_connection_fields } conn; \ + } tcp; + +#define UV_UDP_PRIVATE_FIELDS \ + SOCKET socket; \ + unsigned int reqs_pending; \ + int activecnt; \ + uv_req_t recv_req; \ + uv_buf_t recv_buffer; \ + struct sockaddr_storage recv_from; \ + int recv_from_len; \ + uv_udp_recv_cb recv_cb; \ + uv_alloc_cb alloc_cb; \ + LPFN_WSARECV func_wsarecv; \ + LPFN_WSARECVFROM func_wsarecvfrom; + +#define uv_pipe_server_fields \ + int pending_instances; \ + uv_pipe_accept_t* accept_reqs; \ + uv_pipe_accept_t* pending_accepts; + +#define uv_pipe_connection_fields \ + uv_timer_t* eof_timer; \ + uv_write_t ipc_header_write_req; \ + int ipc_pid; \ + uint64_t remaining_ipc_rawdata_bytes; \ + struct { \ + void* queue[2]; \ + int queue_len; \ + } pending_ipc_info; \ + uv_write_t* non_overlapped_writes_tail; \ + uv_mutex_t readfile_mutex; \ + volatile HANDLE readfile_thread; + +#define UV_PIPE_PRIVATE_FIELDS \ + HANDLE handle; \ + WCHAR* name; \ + union { \ + struct { uv_pipe_server_fields } serv; \ + struct { uv_pipe_connection_fields } conn; \ + } pipe; + +/* TODO: put the parser states in an union - TTY handles are always */ +/* half-duplex so read-state can safely overlap write-state. */ +#define UV_TTY_PRIVATE_FIELDS \ + HANDLE handle; \ + union { \ + struct { \ + /* Used for readable TTY handles */ \ + /* TODO: remove me in v2.x. */ \ + HANDLE unused_; \ + uv_buf_t read_line_buffer; \ + HANDLE read_raw_wait; \ + /* Fields used for translating win keystrokes into vt100 characters */ \ + char last_key[8]; \ + unsigned char last_key_offset; \ + unsigned char last_key_len; \ + WCHAR last_utf16_high_surrogate; \ + INPUT_RECORD last_input_record; \ + } rd; \ + struct { \ + /* Used for writable TTY handles */ \ + /* utf8-to-utf16 conversion state */ \ + unsigned int utf8_codepoint; \ + unsigned char utf8_bytes_left; \ + /* eol conversion state */ \ + unsigned char previous_eol; \ + /* ansi parser state */ \ + unsigned char ansi_parser_state; \ + unsigned char ansi_csi_argc; \ + unsigned short ansi_csi_argv[4]; \ + COORD saved_position; \ + WORD saved_attributes; \ + } wr; \ + } tty; + +#define UV_POLL_PRIVATE_FIELDS \ + SOCKET socket; \ + /* Used in fast mode */ \ + SOCKET peer_socket; \ + AFD_POLL_INFO afd_poll_info_1; \ + AFD_POLL_INFO afd_poll_info_2; \ + /* Used in fast and slow mode. */ \ + uv_req_t poll_req_1; \ + uv_req_t poll_req_2; \ + unsigned char submitted_events_1; \ + unsigned char submitted_events_2; \ + unsigned char mask_events_1; \ + unsigned char mask_events_2; \ + unsigned char events; + +#define UV_TIMER_PRIVATE_FIELDS \ + RB_ENTRY(uv_timer_s) tree_entry; \ + uint64_t due; \ + uint64_t repeat; \ + uint64_t start_id; \ + uv_timer_cb timer_cb; + +#define UV_ASYNC_PRIVATE_FIELDS \ + struct uv_req_s async_req; \ + uv_async_cb async_cb; \ + /* char to avoid alignment issues */ \ + char volatile async_sent; + +#define UV_PREPARE_PRIVATE_FIELDS \ + uv_prepare_t* prepare_prev; \ + uv_prepare_t* prepare_next; \ + uv_prepare_cb prepare_cb; + +#define UV_CHECK_PRIVATE_FIELDS \ + uv_check_t* check_prev; \ + uv_check_t* check_next; \ + uv_check_cb check_cb; + +#define UV_IDLE_PRIVATE_FIELDS \ + uv_idle_t* idle_prev; \ + uv_idle_t* idle_next; \ + uv_idle_cb idle_cb; + +#define UV_HANDLE_PRIVATE_FIELDS \ + uv_handle_t* endgame_next; \ + unsigned int flags; + +#define UV_GETADDRINFO_PRIVATE_FIELDS \ + struct uv__work work_req; \ + uv_getaddrinfo_cb getaddrinfo_cb; \ + void* alloc; \ + WCHAR* node; \ + WCHAR* service; \ + /* The addrinfoW field is used to store a pointer to the hints, and */ \ + /* later on to store the result of GetAddrInfoW. The final result will */ \ + /* be converted to struct addrinfo* and stored in the addrinfo field. */ \ + struct addrinfoW* addrinfow; \ + struct addrinfo* addrinfo; \ + int retcode; + +#define UV_GETNAMEINFO_PRIVATE_FIELDS \ + struct uv__work work_req; \ + uv_getnameinfo_cb getnameinfo_cb; \ + struct sockaddr_storage storage; \ + int flags; \ + char host[NI_MAXHOST]; \ + char service[NI_MAXSERV]; \ + int retcode; + +#define UV_PROCESS_PRIVATE_FIELDS \ + struct uv_process_exit_s { \ + UV_REQ_FIELDS \ + } exit_req; \ + BYTE* child_stdio_buffer; \ + int exit_signal; \ + HANDLE wait_handle; \ + HANDLE process_handle; \ + volatile char exit_cb_pending; + +#define UV_FS_PRIVATE_FIELDS \ + struct uv__work work_req; \ + int flags; \ + DWORD sys_errno_; \ + union { \ + /* TODO: remove me in 0.9. */ \ + WCHAR* pathw; \ + int fd; \ + } file; \ + union { \ + struct { \ + int mode; \ + WCHAR* new_pathw; \ + int file_flags; \ + int fd_out; \ + unsigned int nbufs; \ + uv_buf_t* bufs; \ + int64_t offset; \ + uv_buf_t bufsml[4]; \ + } info; \ + struct { \ + double atime; \ + double mtime; \ + } time; \ + } fs; + +#define UV_WORK_PRIVATE_FIELDS \ + struct uv__work work_req; + +#define UV_FS_EVENT_PRIVATE_FIELDS \ + struct uv_fs_event_req_s { \ + UV_REQ_FIELDS \ + } req; \ + HANDLE dir_handle; \ + int req_pending; \ + uv_fs_event_cb cb; \ + WCHAR* filew; \ + WCHAR* short_filew; \ + WCHAR* dirw; \ + char* buffer; + +#define UV_SIGNAL_PRIVATE_FIELDS \ + RB_ENTRY(uv_signal_s) tree_entry; \ + struct uv_req_s signal_req; \ + unsigned long pending_signum; + +#ifndef F_OK +#define F_OK 0 +#endif +#ifndef R_OK +#define R_OK 4 +#endif +#ifndef W_OK +#define W_OK 2 +#endif +#ifndef X_OK +#define X_OK 1 +#endif diff --git a/include/uv.h b/include/uv.h new file mode 100644 index 0000000..baa0b28 --- /dev/null +++ b/include/uv.h @@ -0,0 +1,1495 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +/* See https://github.com/libuv/libuv#documentation for documentation. */ + +#ifndef UV_H +#define UV_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 + /* Windows - set up dll import/export decorators. */ +# if defined(BUILDING_UV_SHARED) + /* Building shared library. */ +# define UV_EXTERN __declspec(dllexport) +# elif defined(USING_UV_SHARED) + /* Using shared library. */ +# define UV_EXTERN __declspec(dllimport) +# else + /* Building static library. */ +# define UV_EXTERN /* nothing */ +# endif +#elif __GNUC__ >= 4 +# define UV_EXTERN __attribute__((visibility("default"))) +#else +# define UV_EXTERN /* nothing */ +#endif + +#include "uv-errno.h" +#include "uv-version.h" +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#if defined(_WIN32) +# include "uv-win.h" +#else +# include "uv-unix.h" +#endif + +/* Expand this list if necessary. */ +#define UV_ERRNO_MAP(XX) \ + XX(E2BIG, "argument list too long") \ + XX(EACCES, "permission denied") \ + XX(EADDRINUSE, "address already in use") \ + XX(EADDRNOTAVAIL, "address not available") \ + XX(EAFNOSUPPORT, "address family not supported") \ + XX(EAGAIN, "resource temporarily unavailable") \ + XX(EAI_ADDRFAMILY, "address family not supported") \ + XX(EAI_AGAIN, "temporary failure") \ + XX(EAI_BADFLAGS, "bad ai_flags value") \ + XX(EAI_BADHINTS, "invalid value for hints") \ + XX(EAI_CANCELED, "request canceled") \ + XX(EAI_FAIL, "permanent failure") \ + XX(EAI_FAMILY, "ai_family not supported") \ + XX(EAI_MEMORY, "out of memory") \ + XX(EAI_NODATA, "no address") \ + XX(EAI_NONAME, "unknown node or service") \ + XX(EAI_OVERFLOW, "argument buffer overflow") \ + XX(EAI_PROTOCOL, "resolved protocol is unknown") \ + XX(EAI_SERVICE, "service not available for socket type") \ + XX(EAI_SOCKTYPE, "socket type not supported") \ + XX(EALREADY, "connection already in progress") \ + XX(EBADF, "bad file descriptor") \ + XX(EBUSY, "resource busy or locked") \ + XX(ECANCELED, "operation canceled") \ + XX(ECHARSET, "invalid Unicode character") \ + XX(ECONNABORTED, "software caused connection abort") \ + XX(ECONNREFUSED, "connection refused") \ + XX(ECONNRESET, "connection reset by peer") \ + XX(EDESTADDRREQ, "destination address required") \ + XX(EEXIST, "file already exists") \ + XX(EFAULT, "bad address in system call argument") \ + XX(EFBIG, "file too large") \ + XX(EHOSTUNREACH, "host is unreachable") \ + XX(EINTR, "interrupted system call") \ + XX(EINVAL, "invalid argument") \ + XX(EIO, "i/o error") \ + XX(EISCONN, "socket is already connected") \ + XX(EISDIR, "illegal operation on a directory") \ + XX(ELOOP, "too many symbolic links encountered") \ + XX(EMFILE, "too many open files") \ + XX(EMSGSIZE, "message too long") \ + XX(ENAMETOOLONG, "name too long") \ + XX(ENETDOWN, "network is down") \ + XX(ENETUNREACH, "network is unreachable") \ + XX(ENFILE, "file table overflow") \ + XX(ENOBUFS, "no buffer space available") \ + XX(ENODEV, "no such device") \ + XX(ENOENT, "no such file or directory") \ + XX(ENOMEM, "not enough memory") \ + XX(ENONET, "machine is not on the network") \ + XX(ENOPROTOOPT, "protocol not available") \ + XX(ENOSPC, "no space left on device") \ + XX(ENOSYS, "function not implemented") \ + XX(ENOTCONN, "socket is not connected") \ + XX(ENOTDIR, "not a directory") \ + XX(ENOTEMPTY, "directory not empty") \ + XX(ENOTSOCK, "socket operation on non-socket") \ + XX(ENOTSUP, "operation not supported on socket") \ + XX(EPERM, "operation not permitted") \ + XX(EPIPE, "broken pipe") \ + XX(EPROTO, "protocol error") \ + XX(EPROTONOSUPPORT, "protocol not supported") \ + XX(EPROTOTYPE, "protocol wrong type for socket") \ + XX(ERANGE, "result too large") \ + XX(EROFS, "read-only file system") \ + XX(ESHUTDOWN, "cannot send after transport endpoint shutdown") \ + XX(ESPIPE, "invalid seek") \ + XX(ESRCH, "no such process") \ + XX(ETIMEDOUT, "connection timed out") \ + XX(ETXTBSY, "text file is busy") \ + XX(EXDEV, "cross-device link not permitted") \ + XX(UNKNOWN, "unknown error") \ + XX(EOF, "end of file") \ + XX(ENXIO, "no such device or address") \ + XX(EMLINK, "too many links") \ + XX(EHOSTDOWN, "host is down") \ + +#define UV_HANDLE_TYPE_MAP(XX) \ + XX(ASYNC, async) \ + XX(CHECK, check) \ + XX(FS_EVENT, fs_event) \ + XX(FS_POLL, fs_poll) \ + XX(HANDLE, handle) \ + XX(IDLE, idle) \ + XX(NAMED_PIPE, pipe) \ + XX(POLL, poll) \ + XX(PREPARE, prepare) \ + XX(PROCESS, process) \ + XX(STREAM, stream) \ + XX(TCP, tcp) \ + XX(TIMER, timer) \ + XX(TTY, tty) \ + XX(UDP, udp) \ + XX(SIGNAL, signal) \ + +#define UV_REQ_TYPE_MAP(XX) \ + XX(REQ, req) \ + XX(CONNECT, connect) \ + XX(WRITE, write) \ + XX(SHUTDOWN, shutdown) \ + XX(UDP_SEND, udp_send) \ + XX(FS, fs) \ + XX(WORK, work) \ + XX(GETADDRINFO, getaddrinfo) \ + XX(GETNAMEINFO, getnameinfo) \ + +typedef enum { +#define XX(code, _) UV_ ## code = UV__ ## code, + UV_ERRNO_MAP(XX) +#undef XX + UV_ERRNO_MAX = UV__EOF - 1 +} uv_errno_t; + +typedef enum { + UV_UNKNOWN_HANDLE = 0, +#define XX(uc, lc) UV_##uc, + UV_HANDLE_TYPE_MAP(XX) +#undef XX + UV_FILE, + UV_HANDLE_TYPE_MAX +} uv_handle_type; + +typedef enum { + UV_UNKNOWN_REQ = 0, +#define XX(uc, lc) UV_##uc, + UV_REQ_TYPE_MAP(XX) +#undef XX + UV_REQ_TYPE_PRIVATE + UV_REQ_TYPE_MAX +} uv_req_type; + + +/* Handle types. */ +typedef struct uv_loop_s uv_loop_t; +typedef struct uv_handle_s uv_handle_t; +typedef struct uv_stream_s uv_stream_t; +typedef struct uv_tcp_s uv_tcp_t; +typedef struct uv_udp_s uv_udp_t; +typedef struct uv_pipe_s uv_pipe_t; +typedef struct uv_tty_s uv_tty_t; +typedef struct uv_poll_s uv_poll_t; +typedef struct uv_timer_s uv_timer_t; +typedef struct uv_prepare_s uv_prepare_t; +typedef struct uv_check_s uv_check_t; +typedef struct uv_idle_s uv_idle_t; +typedef struct uv_async_s uv_async_t; +typedef struct uv_process_s uv_process_t; +typedef struct uv_fs_event_s uv_fs_event_t; +typedef struct uv_fs_poll_s uv_fs_poll_t; +typedef struct uv_signal_s uv_signal_t; + +/* Request types. */ +typedef struct uv_req_s uv_req_t; +typedef struct uv_getaddrinfo_s uv_getaddrinfo_t; +typedef struct uv_getnameinfo_s uv_getnameinfo_t; +typedef struct uv_shutdown_s uv_shutdown_t; +typedef struct uv_write_s uv_write_t; +typedef struct uv_connect_s uv_connect_t; +typedef struct uv_udp_send_s uv_udp_send_t; +typedef struct uv_fs_s uv_fs_t; +typedef struct uv_work_s uv_work_t; + +/* None of the above. */ +typedef struct uv_cpu_info_s uv_cpu_info_t; +typedef struct uv_interface_address_s uv_interface_address_t; +typedef struct uv_dirent_s uv_dirent_t; +typedef struct uv_passwd_s uv_passwd_t; + +typedef enum { + UV_LOOP_BLOCK_SIGNAL +} uv_loop_option; + +typedef enum { + UV_RUN_DEFAULT = 0, + UV_RUN_ONCE, + UV_RUN_NOWAIT +} uv_run_mode; + + +UV_EXTERN unsigned int uv_version(void); +UV_EXTERN const char* uv_version_string(void); + +typedef void* (*uv_malloc_func)(size_t size); +typedef void* (*uv_realloc_func)(void* ptr, size_t size); +typedef void* (*uv_calloc_func)(size_t count, size_t size); +typedef void (*uv_free_func)(void* ptr); + +UV_EXTERN int uv_replace_allocator(uv_malloc_func malloc_func, + uv_realloc_func realloc_func, + uv_calloc_func calloc_func, + uv_free_func free_func); + +UV_EXTERN uv_loop_t* uv_default_loop(void); +UV_EXTERN int uv_loop_init(uv_loop_t* loop); +UV_EXTERN int uv_loop_close(uv_loop_t* loop); +/* + * NOTE: + * This function is DEPRECATED (to be removed after 0.12), users should + * allocate the loop manually and use uv_loop_init instead. + */ +UV_EXTERN uv_loop_t* uv_loop_new(void); +/* + * NOTE: + * This function is DEPRECATED (to be removed after 0.12). Users should use + * uv_loop_close and free the memory manually instead. + */ +UV_EXTERN void uv_loop_delete(uv_loop_t*); +UV_EXTERN size_t uv_loop_size(void); +UV_EXTERN int uv_loop_alive(const uv_loop_t* loop); +UV_EXTERN int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...); + +UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode); +UV_EXTERN void uv_stop(uv_loop_t*); + +UV_EXTERN void uv_ref(uv_handle_t*); +UV_EXTERN void uv_unref(uv_handle_t*); +UV_EXTERN int uv_has_ref(const uv_handle_t*); + +UV_EXTERN void uv_update_time(uv_loop_t*); +UV_EXTERN uint64_t uv_now(const uv_loop_t*); + +UV_EXTERN int uv_backend_fd(const uv_loop_t*); +UV_EXTERN int uv_backend_timeout(const uv_loop_t*); + +typedef void (*uv_alloc_cb)(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf); +typedef void (*uv_read_cb)(uv_stream_t* stream, + ssize_t nread, + const uv_buf_t* buf); +typedef void (*uv_write_cb)(uv_write_t* req, int status); +typedef void (*uv_connect_cb)(uv_connect_t* req, int status); +typedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status); +typedef void (*uv_connection_cb)(uv_stream_t* server, int status); +typedef void (*uv_close_cb)(uv_handle_t* handle); +typedef void (*uv_poll_cb)(uv_poll_t* handle, int status, int events); +typedef void (*uv_timer_cb)(uv_timer_t* handle); +typedef void (*uv_async_cb)(uv_async_t* handle); +typedef void (*uv_prepare_cb)(uv_prepare_t* handle); +typedef void (*uv_check_cb)(uv_check_t* handle); +typedef void (*uv_idle_cb)(uv_idle_t* handle); +typedef void (*uv_exit_cb)(uv_process_t*, int64_t exit_status, int term_signal); +typedef void (*uv_walk_cb)(uv_handle_t* handle, void* arg); +typedef void (*uv_fs_cb)(uv_fs_t* req); +typedef void (*uv_work_cb)(uv_work_t* req); +typedef void (*uv_after_work_cb)(uv_work_t* req, int status); +typedef void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req, + int status, + struct addrinfo* res); +typedef void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req, + int status, + const char* hostname, + const char* service); + +typedef struct { + long tv_sec; + long tv_nsec; +} uv_timespec_t; + + +typedef struct { + uint64_t st_dev; + uint64_t st_mode; + uint64_t st_nlink; + uint64_t st_uid; + uint64_t st_gid; + uint64_t st_rdev; + uint64_t st_ino; + uint64_t st_size; + uint64_t st_blksize; + uint64_t st_blocks; + uint64_t st_flags; + uint64_t st_gen; + uv_timespec_t st_atim; + uv_timespec_t st_mtim; + uv_timespec_t st_ctim; + uv_timespec_t st_birthtim; +} uv_stat_t; + + +typedef void (*uv_fs_event_cb)(uv_fs_event_t* handle, + const char* filename, + int events, + int status); + +typedef void (*uv_fs_poll_cb)(uv_fs_poll_t* handle, + int status, + const uv_stat_t* prev, + const uv_stat_t* curr); + +typedef void (*uv_signal_cb)(uv_signal_t* handle, int signum); + + +typedef enum { + UV_LEAVE_GROUP = 0, + UV_JOIN_GROUP +} uv_membership; + + +UV_EXTERN const char* uv_strerror(int err); +UV_EXTERN const char* uv_err_name(int err); + + +#define UV_REQ_FIELDS \ + /* public */ \ + void* data; \ + /* read-only */ \ + uv_req_type type; \ + /* private */ \ + void* active_queue[2]; \ + void* reserved[4]; \ + UV_REQ_PRIVATE_FIELDS \ + +/* Abstract base class of all requests. */ +struct uv_req_s { + UV_REQ_FIELDS +}; + + +/* Platform-specific request types. */ +UV_PRIVATE_REQ_TYPES + + +UV_EXTERN int uv_shutdown(uv_shutdown_t* req, + uv_stream_t* handle, + uv_shutdown_cb cb); + +struct uv_shutdown_s { + UV_REQ_FIELDS + uv_stream_t* handle; + uv_shutdown_cb cb; + UV_SHUTDOWN_PRIVATE_FIELDS +}; + + +#define UV_HANDLE_FIELDS \ + /* public */ \ + void* data; \ + /* read-only */ \ + uv_loop_t* loop; \ + uv_handle_type type; \ + /* private */ \ + uv_close_cb close_cb; \ + void* handle_queue[2]; \ + union { \ + int fd; \ + void* reserved[4]; \ + } u; \ + UV_HANDLE_PRIVATE_FIELDS \ + +/* The abstract base class of all handles. */ +struct uv_handle_s { + UV_HANDLE_FIELDS +}; + +UV_EXTERN size_t uv_handle_size(uv_handle_type type); +UV_EXTERN size_t uv_req_size(uv_req_type type); + +UV_EXTERN int uv_is_active(const uv_handle_t* handle); + +UV_EXTERN void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg); + +/* Helpers for ad hoc debugging, no API/ABI stability guaranteed. */ +UV_EXTERN void uv_print_all_handles(uv_loop_t* loop, FILE* stream); +UV_EXTERN void uv_print_active_handles(uv_loop_t* loop, FILE* stream); + +UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb); + +UV_EXTERN int uv_send_buffer_size(uv_handle_t* handle, int* value); +UV_EXTERN int uv_recv_buffer_size(uv_handle_t* handle, int* value); + +UV_EXTERN int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd); + +UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len); + + +#define UV_STREAM_FIELDS \ + /* number of bytes queued for writing */ \ + size_t write_queue_size; \ + uv_alloc_cb alloc_cb; \ + uv_read_cb read_cb; \ + /* private */ \ + UV_STREAM_PRIVATE_FIELDS + +/* + * uv_stream_t is a subclass of uv_handle_t. + * + * uv_stream is an abstract class. + * + * uv_stream_t is the parent class of uv_tcp_t, uv_pipe_t and uv_tty_t. + */ +struct uv_stream_s { + UV_HANDLE_FIELDS + UV_STREAM_FIELDS +}; + +UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb); +UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client); + +UV_EXTERN int uv_read_start(uv_stream_t*, + uv_alloc_cb alloc_cb, + uv_read_cb read_cb); +UV_EXTERN int uv_read_stop(uv_stream_t*); + +UV_EXTERN int uv_write(uv_write_t* req, + uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb); +UV_EXTERN int uv_write2(uv_write_t* req, + uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb); +UV_EXTERN int uv_try_write(uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs); + +/* uv_write_t is a subclass of uv_req_t. */ +struct uv_write_s { + UV_REQ_FIELDS + uv_write_cb cb; + uv_stream_t* send_handle; + uv_stream_t* handle; + UV_WRITE_PRIVATE_FIELDS +}; + + +UV_EXTERN int uv_is_readable(const uv_stream_t* handle); +UV_EXTERN int uv_is_writable(const uv_stream_t* handle); + +UV_EXTERN int uv_stream_set_blocking(uv_stream_t* handle, int blocking); + +UV_EXTERN int uv_is_closing(const uv_handle_t* handle); + + +/* + * uv_tcp_t is a subclass of uv_stream_t. + * + * Represents a TCP stream or TCP server. + */ +struct uv_tcp_s { + UV_HANDLE_FIELDS + UV_STREAM_FIELDS + UV_TCP_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle); +UV_EXTERN int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, unsigned int flags); +UV_EXTERN int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock); +UV_EXTERN int uv_tcp_nodelay(uv_tcp_t* handle, int enable); +UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle, + int enable, + unsigned int delay); +UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable); + +enum uv_tcp_flags { + /* Used with uv_tcp_bind, when an IPv6 address is used. */ + UV_TCP_IPV6ONLY = 1 +}; + +UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int flags); +UV_EXTERN int uv_tcp_getsockname(const uv_tcp_t* handle, + struct sockaddr* name, + int* namelen); +UV_EXTERN int uv_tcp_getpeername(const uv_tcp_t* handle, + struct sockaddr* name, + int* namelen); +UV_EXTERN int uv_tcp_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + uv_connect_cb cb); + +/* uv_connect_t is a subclass of uv_req_t. */ +struct uv_connect_s { + UV_REQ_FIELDS + uv_connect_cb cb; + uv_stream_t* handle; + UV_CONNECT_PRIVATE_FIELDS +}; + + +/* + * UDP support. + */ + +enum uv_udp_flags { + /* Disables dual stack mode. */ + UV_UDP_IPV6ONLY = 1, + /* + * Indicates message was truncated because read buffer was too small. The + * remainder was discarded by the OS. Used in uv_udp_recv_cb. + */ + UV_UDP_PARTIAL = 2, + /* + * Indicates if SO_REUSEADDR will be set when binding the handle. + * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other + * Unix platforms, it sets the SO_REUSEADDR flag. What that means is that + * multiple threads or processes can bind to the same address without error + * (provided they all set the flag) but only the last one to bind will receive + * any traffic, in effect "stealing" the port from the previous listener. + */ + UV_UDP_REUSEADDR = 4 +}; + +typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status); +typedef void (*uv_udp_recv_cb)(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags); + +/* uv_udp_t is a subclass of uv_handle_t. */ +struct uv_udp_s { + UV_HANDLE_FIELDS + /* read-only */ + /* + * Number of bytes queued for sending. This field strictly shows how much + * information is currently queued. + */ + size_t send_queue_size; + /* + * Number of send requests currently in the queue awaiting to be processed. + */ + size_t send_queue_count; + UV_UDP_PRIVATE_FIELDS +}; + +/* uv_udp_send_t is a subclass of uv_req_t. */ +struct uv_udp_send_s { + UV_REQ_FIELDS + uv_udp_t* handle; + uv_udp_send_cb cb; + UV_UDP_SEND_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_udp_init(uv_loop_t*, uv_udp_t* handle); +UV_EXTERN int uv_udp_init_ex(uv_loop_t*, uv_udp_t* handle, unsigned int flags); +UV_EXTERN int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock); +UV_EXTERN int uv_udp_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int flags); + +UV_EXTERN int uv_udp_getsockname(const uv_udp_t* handle, + struct sockaddr* name, + int* namelen); +UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle, + const char* multicast_addr, + const char* interface_addr, + uv_membership membership); +UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on); +UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl); +UV_EXTERN int uv_udp_set_multicast_interface(uv_udp_t* handle, + const char* interface_addr); +UV_EXTERN int uv_udp_set_broadcast(uv_udp_t* handle, int on); +UV_EXTERN int uv_udp_set_ttl(uv_udp_t* handle, int ttl); +UV_EXTERN int uv_udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + uv_udp_send_cb send_cb); +UV_EXTERN int uv_udp_try_send(uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr); +UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle, + uv_alloc_cb alloc_cb, + uv_udp_recv_cb recv_cb); +UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle); + + +/* + * uv_tty_t is a subclass of uv_stream_t. + * + * Representing a stream for the console. + */ +struct uv_tty_s { + UV_HANDLE_FIELDS + UV_STREAM_FIELDS + UV_TTY_PRIVATE_FIELDS +}; + +typedef enum { + /* Initial/normal terminal mode */ + UV_TTY_MODE_NORMAL, + /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */ + UV_TTY_MODE_RAW, + /* Binary-safe I/O mode for IPC (Unix-only) */ + UV_TTY_MODE_IO +} uv_tty_mode_t; + +UV_EXTERN int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable); +UV_EXTERN int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode); +UV_EXTERN int uv_tty_reset_mode(void); +UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height); + +#ifdef __cplusplus +extern "C++" { + +inline int uv_tty_set_mode(uv_tty_t* handle, int mode) { + return uv_tty_set_mode(handle, static_cast(mode)); +} + +} +#endif + +UV_EXTERN uv_handle_type uv_guess_handle(uv_file file); + +/* + * uv_pipe_t is a subclass of uv_stream_t. + * + * Representing a pipe stream or pipe server. On Windows this is a Named + * Pipe. On Unix this is a Unix domain socket. + */ +struct uv_pipe_s { + UV_HANDLE_FIELDS + UV_STREAM_FIELDS + int ipc; /* non-zero if this pipe is used for passing handles */ + UV_PIPE_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc); +UV_EXTERN int uv_pipe_open(uv_pipe_t*, uv_file file); +UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name); +UV_EXTERN void uv_pipe_connect(uv_connect_t* req, + uv_pipe_t* handle, + const char* name, + uv_connect_cb cb); +UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle, + char* buffer, + size_t* size); +UV_EXTERN int uv_pipe_getpeername(const uv_pipe_t* handle, + char* buffer, + size_t* size); +UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count); +UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle); +UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle); + + +struct uv_poll_s { + UV_HANDLE_FIELDS + uv_poll_cb poll_cb; + UV_POLL_PRIVATE_FIELDS +}; + +enum uv_poll_event { + UV_READABLE = 1, + UV_WRITABLE = 2, + UV_DISCONNECT = 4 +}; + +UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd); +UV_EXTERN int uv_poll_init_socket(uv_loop_t* loop, + uv_poll_t* handle, + uv_os_sock_t socket); +UV_EXTERN int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb); +UV_EXTERN int uv_poll_stop(uv_poll_t* handle); + + +struct uv_prepare_s { + UV_HANDLE_FIELDS + UV_PREPARE_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_prepare_init(uv_loop_t*, uv_prepare_t* prepare); +UV_EXTERN int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb); +UV_EXTERN int uv_prepare_stop(uv_prepare_t* prepare); + + +struct uv_check_s { + UV_HANDLE_FIELDS + UV_CHECK_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_check_init(uv_loop_t*, uv_check_t* check); +UV_EXTERN int uv_check_start(uv_check_t* check, uv_check_cb cb); +UV_EXTERN int uv_check_stop(uv_check_t* check); + + +struct uv_idle_s { + UV_HANDLE_FIELDS + UV_IDLE_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_idle_init(uv_loop_t*, uv_idle_t* idle); +UV_EXTERN int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb); +UV_EXTERN int uv_idle_stop(uv_idle_t* idle); + + +struct uv_async_s { + UV_HANDLE_FIELDS + UV_ASYNC_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_async_init(uv_loop_t*, + uv_async_t* async, + uv_async_cb async_cb); +UV_EXTERN int uv_async_send(uv_async_t* async); + + +/* + * uv_timer_t is a subclass of uv_handle_t. + * + * Used to get woken up at a specified time in the future. + */ +struct uv_timer_s { + UV_HANDLE_FIELDS + UV_TIMER_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_timer_init(uv_loop_t*, uv_timer_t* handle); +UV_EXTERN int uv_timer_start(uv_timer_t* handle, + uv_timer_cb cb, + uint64_t timeout, + uint64_t repeat); +UV_EXTERN int uv_timer_stop(uv_timer_t* handle); +UV_EXTERN int uv_timer_again(uv_timer_t* handle); +UV_EXTERN void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat); +UV_EXTERN uint64_t uv_timer_get_repeat(const uv_timer_t* handle); + + +/* + * uv_getaddrinfo_t is a subclass of uv_req_t. + * + * Request object for uv_getaddrinfo. + */ +struct uv_getaddrinfo_s { + UV_REQ_FIELDS + /* read-only */ + uv_loop_t* loop; + /* struct addrinfo* addrinfo is marked as private, but it really isn't. */ + UV_GETADDRINFO_PRIVATE_FIELDS +}; + + +UV_EXTERN int uv_getaddrinfo(uv_loop_t* loop, + uv_getaddrinfo_t* req, + uv_getaddrinfo_cb getaddrinfo_cb, + const char* node, + const char* service, + const struct addrinfo* hints); +UV_EXTERN void uv_freeaddrinfo(struct addrinfo* ai); + + +/* +* uv_getnameinfo_t is a subclass of uv_req_t. +* +* Request object for uv_getnameinfo. +*/ +struct uv_getnameinfo_s { + UV_REQ_FIELDS + /* read-only */ + uv_loop_t* loop; + /* host and service are marked as private, but they really aren't. */ + UV_GETNAMEINFO_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_getnameinfo(uv_loop_t* loop, + uv_getnameinfo_t* req, + uv_getnameinfo_cb getnameinfo_cb, + const struct sockaddr* addr, + int flags); + + +/* uv_spawn() options. */ +typedef enum { + UV_IGNORE = 0x00, + UV_CREATE_PIPE = 0x01, + UV_INHERIT_FD = 0x02, + UV_INHERIT_STREAM = 0x04, + + /* + * When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and UV_WRITABLE_PIPE + * determine the direction of flow, from the child process' perspective. Both + * flags may be specified to create a duplex data stream. + */ + UV_READABLE_PIPE = 0x10, + UV_WRITABLE_PIPE = 0x20 +} uv_stdio_flags; + +typedef struct uv_stdio_container_s { + uv_stdio_flags flags; + + union { + uv_stream_t* stream; + int fd; + } data; +} uv_stdio_container_t; + +typedef struct uv_process_options_s { + uv_exit_cb exit_cb; /* Called after the process exits. */ + const char* file; /* Path to program to execute. */ + /* + * Command line arguments. args[0] should be the path to the program. On + * Windows this uses CreateProcess which concatenates the arguments into a + * string this can cause some strange errors. See the note at + * windows_verbatim_arguments. + */ + char** args; + /* + * This will be set as the environ variable in the subprocess. If this is + * NULL then the parents environ will be used. + */ + char** env; + /* + * If non-null this represents a directory the subprocess should execute + * in. Stands for current working directory. + */ + const char* cwd; + /* + * Various flags that control how uv_spawn() behaves. See the definition of + * `enum uv_process_flags` below. + */ + unsigned int flags; + /* + * The `stdio` field points to an array of uv_stdio_container_t structs that + * describe the file descriptors that will be made available to the child + * process. The convention is that stdio[0] points to stdin, fd 1 is used for + * stdout, and fd 2 is stderr. + * + * Note that on windows file descriptors greater than 2 are available to the + * child process only if the child processes uses the MSVCRT runtime. + */ + int stdio_count; + uv_stdio_container_t* stdio; + /* + * Libuv can change the child process' user/group id. This happens only when + * the appropriate bits are set in the flags fields. This is not supported on + * windows; uv_spawn() will fail and set the error to UV_ENOTSUP. + */ + uv_uid_t uid; + uv_gid_t gid; +} uv_process_options_t; + +/* + * These are the flags that can be used for the uv_process_options.flags field. + */ +enum uv_process_flags { + /* + * Set the child process' user id. The user id is supplied in the `uid` field + * of the options struct. This does not work on windows; setting this flag + * will cause uv_spawn() to fail. + */ + UV_PROCESS_SETUID = (1 << 0), + /* + * Set the child process' group id. The user id is supplied in the `gid` + * field of the options struct. This does not work on windows; setting this + * flag will cause uv_spawn() to fail. + */ + UV_PROCESS_SETGID = (1 << 1), + /* + * Do not wrap any arguments in quotes, or perform any other escaping, when + * converting the argument list into a command line string. This option is + * only meaningful on Windows systems. On Unix it is silently ignored. + */ + UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2), + /* + * Spawn the child process in a detached state - this will make it a process + * group leader, and will effectively enable the child to keep running after + * the parent exits. Note that the child process will still keep the + * parent's event loop alive unless the parent process calls uv_unref() on + * the child's process handle. + */ + UV_PROCESS_DETACHED = (1 << 3), + /* + * Hide the subprocess console window that would normally be created. This + * option is only meaningful on Windows systems. On Unix it is silently + * ignored. + */ + UV_PROCESS_WINDOWS_HIDE = (1 << 4) +}; + +/* + * uv_process_t is a subclass of uv_handle_t. + */ +struct uv_process_s { + UV_HANDLE_FIELDS + uv_exit_cb exit_cb; + int pid; + UV_PROCESS_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_spawn(uv_loop_t* loop, + uv_process_t* handle, + const uv_process_options_t* options); +UV_EXTERN int uv_process_kill(uv_process_t*, int signum); +UV_EXTERN int uv_kill(int pid, int signum); + + +/* + * uv_work_t is a subclass of uv_req_t. + */ +struct uv_work_s { + UV_REQ_FIELDS + uv_loop_t* loop; + uv_work_cb work_cb; + uv_after_work_cb after_work_cb; + UV_WORK_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_queue_work(uv_loop_t* loop, + uv_work_t* req, + uv_work_cb work_cb, + uv_after_work_cb after_work_cb); + +UV_EXTERN int uv_cancel(uv_req_t* req); + + +struct uv_cpu_info_s { + char* model; + int speed; + struct uv_cpu_times_s { + uint64_t user; + uint64_t nice; + uint64_t sys; + uint64_t idle; + uint64_t irq; + } cpu_times; +}; + +struct uv_interface_address_s { + char* name; + char phys_addr[6]; + int is_internal; + union { + struct sockaddr_in address4; + struct sockaddr_in6 address6; + } address; + union { + struct sockaddr_in netmask4; + struct sockaddr_in6 netmask6; + } netmask; +}; + +struct uv_passwd_s { + char* username; + long uid; + long gid; + char* shell; + char* homedir; +}; + +typedef enum { + UV_DIRENT_UNKNOWN, + UV_DIRENT_FILE, + UV_DIRENT_DIR, + UV_DIRENT_LINK, + UV_DIRENT_FIFO, + UV_DIRENT_SOCKET, + UV_DIRENT_CHAR, + UV_DIRENT_BLOCK +} uv_dirent_type_t; + +struct uv_dirent_s { + const char* name; + uv_dirent_type_t type; +}; + +UV_EXTERN char** uv_setup_args(int argc, char** argv); +UV_EXTERN int uv_get_process_title(char* buffer, size_t size); +UV_EXTERN int uv_set_process_title(const char* title); +UV_EXTERN int uv_resident_set_memory(size_t* rss); +UV_EXTERN int uv_uptime(double* uptime); + +typedef struct { + long tv_sec; + long tv_usec; +} uv_timeval_t; + +typedef struct { + uv_timeval_t ru_utime; /* user CPU time used */ + uv_timeval_t ru_stime; /* system CPU time used */ + uint64_t ru_maxrss; /* maximum resident set size */ + uint64_t ru_ixrss; /* integral shared memory size */ + uint64_t ru_idrss; /* integral unshared data size */ + uint64_t ru_isrss; /* integral unshared stack size */ + uint64_t ru_minflt; /* page reclaims (soft page faults) */ + uint64_t ru_majflt; /* page faults (hard page faults) */ + uint64_t ru_nswap; /* swaps */ + uint64_t ru_inblock; /* block input operations */ + uint64_t ru_oublock; /* block output operations */ + uint64_t ru_msgsnd; /* IPC messages sent */ + uint64_t ru_msgrcv; /* IPC messages received */ + uint64_t ru_nsignals; /* signals received */ + uint64_t ru_nvcsw; /* voluntary context switches */ + uint64_t ru_nivcsw; /* involuntary context switches */ +} uv_rusage_t; + +UV_EXTERN int uv_getrusage(uv_rusage_t* rusage); + +UV_EXTERN int uv_os_homedir(char* buffer, size_t* size); +UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size); +UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd); +UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd); + +UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); +UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); + +UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses, + int* count); +UV_EXTERN void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count); + + +typedef enum { + UV_FS_UNKNOWN = -1, + UV_FS_CUSTOM, + UV_FS_OPEN, + UV_FS_CLOSE, + UV_FS_READ, + UV_FS_WRITE, + UV_FS_SENDFILE, + UV_FS_STAT, + UV_FS_LSTAT, + UV_FS_FSTAT, + UV_FS_FTRUNCATE, + UV_FS_UTIME, + UV_FS_FUTIME, + UV_FS_ACCESS, + UV_FS_CHMOD, + UV_FS_FCHMOD, + UV_FS_FSYNC, + UV_FS_FDATASYNC, + UV_FS_UNLINK, + UV_FS_RMDIR, + UV_FS_MKDIR, + UV_FS_MKDTEMP, + UV_FS_RENAME, + UV_FS_SCANDIR, + UV_FS_LINK, + UV_FS_SYMLINK, + UV_FS_READLINK, + UV_FS_CHOWN, + UV_FS_FCHOWN, + UV_FS_REALPATH +} uv_fs_type; + +/* uv_fs_t is a subclass of uv_req_t. */ +struct uv_fs_s { + UV_REQ_FIELDS + uv_fs_type fs_type; + uv_loop_t* loop; + uv_fs_cb cb; + ssize_t result; + void* ptr; + const char* path; + uv_stat_t statbuf; /* Stores the result of uv_fs_stat() and uv_fs_fstat(). */ + UV_FS_PRIVATE_FIELDS +}; + +UV_EXTERN void uv_fs_req_cleanup(uv_fs_t* req); +UV_EXTERN int uv_fs_close(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_fs_cb cb); +UV_EXTERN int uv_fs_open(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + int mode, + uv_fs_cb cb); +UV_EXTERN int uv_fs_read(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t offset, + uv_fs_cb cb); +UV_EXTERN int uv_fs_unlink(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_write(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t offset, + uv_fs_cb cb); +UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int mode, + uv_fs_cb cb); +UV_EXTERN int uv_fs_mkdtemp(uv_loop_t* loop, + uv_fs_t* req, + const char* tpl, + uv_fs_cb cb); +UV_EXTERN int uv_fs_rmdir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_scandir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + uv_fs_cb cb); +UV_EXTERN int uv_fs_scandir_next(uv_fs_t* req, + uv_dirent_t* ent); +UV_EXTERN int uv_fs_stat(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_fstat(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_fs_cb cb); +UV_EXTERN int uv_fs_rename(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_fsync(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_fs_cb cb); +UV_EXTERN int uv_fs_fdatasync(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_fs_cb cb); +UV_EXTERN int uv_fs_ftruncate(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + int64_t offset, + uv_fs_cb cb); +UV_EXTERN int uv_fs_sendfile(uv_loop_t* loop, + uv_fs_t* req, + uv_file out_fd, + uv_file in_fd, + int64_t in_offset, + size_t length, + uv_fs_cb cb); +UV_EXTERN int uv_fs_access(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int mode, + uv_fs_cb cb); +UV_EXTERN int uv_fs_chmod(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int mode, + uv_fs_cb cb); +UV_EXTERN int uv_fs_utime(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + double atime, + double mtime, + uv_fs_cb cb); +UV_EXTERN int uv_fs_futime(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + double atime, + double mtime, + uv_fs_cb cb); +UV_EXTERN int uv_fs_lstat(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_link(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + uv_fs_cb cb); + +/* + * This flag can be used with uv_fs_symlink() on Windows to specify whether + * path argument points to a directory. + */ +#define UV_FS_SYMLINK_DIR 0x0001 + +/* + * This flag can be used with uv_fs_symlink() on Windows to specify whether + * the symlink is to be created using junction points. + */ +#define UV_FS_SYMLINK_JUNCTION 0x0002 + +UV_EXTERN int uv_fs_symlink(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + int flags, + uv_fs_cb cb); +UV_EXTERN int uv_fs_readlink(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_realpath(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_fchmod(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + int mode, + uv_fs_cb cb); +UV_EXTERN int uv_fs_chown(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb); +UV_EXTERN int uv_fs_fchown(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb); + + +enum uv_fs_event { + UV_RENAME = 1, + UV_CHANGE = 2 +}; + + +struct uv_fs_event_s { + UV_HANDLE_FIELDS + /* private */ + char* path; + UV_FS_EVENT_PRIVATE_FIELDS +}; + + +/* + * uv_fs_stat() based polling file watcher. + */ +struct uv_fs_poll_s { + UV_HANDLE_FIELDS + /* Private, don't touch. */ + void* poll_ctx; +}; + +UV_EXTERN int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle); +UV_EXTERN int uv_fs_poll_start(uv_fs_poll_t* handle, + uv_fs_poll_cb poll_cb, + const char* path, + unsigned int interval); +UV_EXTERN int uv_fs_poll_stop(uv_fs_poll_t* handle); +UV_EXTERN int uv_fs_poll_getpath(uv_fs_poll_t* handle, + char* buffer, + size_t* size); + + +struct uv_signal_s { + UV_HANDLE_FIELDS + uv_signal_cb signal_cb; + int signum; + UV_SIGNAL_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle); +UV_EXTERN int uv_signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum); +UV_EXTERN int uv_signal_stop(uv_signal_t* handle); + +UV_EXTERN void uv_loadavg(double avg[3]); + + +/* + * Flags to be passed to uv_fs_event_start(). + */ +enum uv_fs_event_flags { + /* + * By default, if the fs event watcher is given a directory name, we will + * watch for all events in that directory. This flags overrides this behavior + * and makes fs_event report only changes to the directory entry itself. This + * flag does not affect individual files watched. + * This flag is currently not implemented yet on any backend. + */ + UV_FS_EVENT_WATCH_ENTRY = 1, + + /* + * By default uv_fs_event will try to use a kernel interface such as inotify + * or kqueue to detect events. This may not work on remote filesystems such + * as NFS mounts. This flag makes fs_event fall back to calling stat() on a + * regular interval. + * This flag is currently not implemented yet on any backend. + */ + UV_FS_EVENT_STAT = 2, + + /* + * By default, event watcher, when watching directory, is not registering + * (is ignoring) changes in it's subdirectories. + * This flag will override this behaviour on platforms that support it. + */ + UV_FS_EVENT_RECURSIVE = 4 +}; + + +UV_EXTERN int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle); +UV_EXTERN int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* path, + unsigned int flags); +UV_EXTERN int uv_fs_event_stop(uv_fs_event_t* handle); +UV_EXTERN int uv_fs_event_getpath(uv_fs_event_t* handle, + char* buffer, + size_t* size); + +UV_EXTERN int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr); +UV_EXTERN int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr); + +UV_EXTERN int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size); +UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size); + +UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size); +UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst); + +UV_EXTERN int uv_exepath(char* buffer, size_t* size); + +UV_EXTERN int uv_cwd(char* buffer, size_t* size); + +UV_EXTERN int uv_chdir(const char* dir); + +UV_EXTERN uint64_t uv_get_free_memory(void); +UV_EXTERN uint64_t uv_get_total_memory(void); + +UV_EXTERN uint64_t uv_hrtime(void); + +UV_EXTERN void uv_disable_stdio_inheritance(void); + +UV_EXTERN int uv_dlopen(const char* filename, uv_lib_t* lib); +UV_EXTERN void uv_dlclose(uv_lib_t* lib); +UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr); +UV_EXTERN const char* uv_dlerror(const uv_lib_t* lib); + +UV_EXTERN int uv_mutex_init(uv_mutex_t* handle); +UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle); +UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle); +UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle); +UV_EXTERN void uv_mutex_unlock(uv_mutex_t* handle); + +UV_EXTERN int uv_rwlock_init(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_destroy(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_rdlock(uv_rwlock_t* rwlock); +UV_EXTERN int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_rdunlock(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_wrlock(uv_rwlock_t* rwlock); +UV_EXTERN int uv_rwlock_trywrlock(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_wrunlock(uv_rwlock_t* rwlock); + +UV_EXTERN int uv_sem_init(uv_sem_t* sem, unsigned int value); +UV_EXTERN void uv_sem_destroy(uv_sem_t* sem); +UV_EXTERN void uv_sem_post(uv_sem_t* sem); +UV_EXTERN void uv_sem_wait(uv_sem_t* sem); +UV_EXTERN int uv_sem_trywait(uv_sem_t* sem); + +UV_EXTERN int uv_cond_init(uv_cond_t* cond); +UV_EXTERN void uv_cond_destroy(uv_cond_t* cond); +UV_EXTERN void uv_cond_signal(uv_cond_t* cond); +UV_EXTERN void uv_cond_broadcast(uv_cond_t* cond); + +UV_EXTERN int uv_barrier_init(uv_barrier_t* barrier, unsigned int count); +UV_EXTERN void uv_barrier_destroy(uv_barrier_t* barrier); +UV_EXTERN int uv_barrier_wait(uv_barrier_t* barrier); + +UV_EXTERN void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex); +UV_EXTERN int uv_cond_timedwait(uv_cond_t* cond, + uv_mutex_t* mutex, + uint64_t timeout); + +UV_EXTERN void uv_once(uv_once_t* guard, void (*callback)(void)); + +UV_EXTERN int uv_key_create(uv_key_t* key); +UV_EXTERN void uv_key_delete(uv_key_t* key); +UV_EXTERN void* uv_key_get(uv_key_t* key); +UV_EXTERN void uv_key_set(uv_key_t* key, void* value); + +typedef void (*uv_thread_cb)(void* arg); + +UV_EXTERN int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg); +UV_EXTERN uv_thread_t uv_thread_self(void); +UV_EXTERN int uv_thread_join(uv_thread_t *tid); +UV_EXTERN int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2); + +/* The presence of these unions force similar struct layout. */ +#define XX(_, name) uv_ ## name ## _t name; +union uv_any_handle { + UV_HANDLE_TYPE_MAP(XX) +}; + +union uv_any_req { + UV_REQ_TYPE_MAP(XX) +}; +#undef XX + + +struct uv_loop_s { + /* User data - use this for whatever. */ + void* data; + /* Loop reference counting. */ + unsigned int active_handles; + void* handle_queue[2]; + void* active_reqs[2]; + /* Internal flag to signal loop stop. */ + unsigned int stop_flag; + UV_LOOP_PRIVATE_FIELDS +}; + + +/* Don't export the private CPP symbols. */ +#undef UV_HANDLE_TYPE_PRIVATE +#undef UV_REQ_TYPE_PRIVATE +#undef UV_REQ_PRIVATE_FIELDS +#undef UV_STREAM_PRIVATE_FIELDS +#undef UV_TCP_PRIVATE_FIELDS +#undef UV_PREPARE_PRIVATE_FIELDS +#undef UV_CHECK_PRIVATE_FIELDS +#undef UV_IDLE_PRIVATE_FIELDS +#undef UV_ASYNC_PRIVATE_FIELDS +#undef UV_TIMER_PRIVATE_FIELDS +#undef UV_GETADDRINFO_PRIVATE_FIELDS +#undef UV_GETNAMEINFO_PRIVATE_FIELDS +#undef UV_FS_REQ_PRIVATE_FIELDS +#undef UV_WORK_PRIVATE_FIELDS +#undef UV_FS_EVENT_PRIVATE_FIELDS +#undef UV_SIGNAL_PRIVATE_FIELDS +#undef UV_LOOP_PRIVATE_FIELDS +#undef UV_LOOP_PRIVATE_PLATFORM_FIELDS + +#ifdef __cplusplus +} +#endif +#endif /* UV_H */ diff --git a/src/fs-poll.c b/src/fs-poll.c new file mode 100644 index 0000000..ee73d5a --- /dev/null +++ b/src/fs-poll.c @@ -0,0 +1,256 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "uv-common.h" + +#include +#include +#include + +struct poll_ctx { + uv_fs_poll_t* parent_handle; /* NULL if parent has been stopped or closed */ + int busy_polling; + unsigned int interval; + uint64_t start_time; + uv_loop_t* loop; + uv_fs_poll_cb poll_cb; + uv_timer_t timer_handle; + uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */ + uv_stat_t statbuf; + char path[1]; /* variable length */ +}; + +static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b); +static void poll_cb(uv_fs_t* req); +static void timer_cb(uv_timer_t* timer); +static void timer_close_cb(uv_handle_t* handle); + +static uv_stat_t zero_statbuf; + + +int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL); + return 0; +} + + +int uv_fs_poll_start(uv_fs_poll_t* handle, + uv_fs_poll_cb cb, + const char* path, + unsigned int interval) { + struct poll_ctx* ctx; + uv_loop_t* loop; + size_t len; + int err; + + if (uv__is_active(handle)) + return 0; + + loop = handle->loop; + len = strlen(path); + ctx = uv__calloc(1, sizeof(*ctx) + len); + + if (ctx == NULL) + return UV_ENOMEM; + + ctx->loop = loop; + ctx->poll_cb = cb; + ctx->interval = interval ? interval : 1; + ctx->start_time = uv_now(loop); + ctx->parent_handle = handle; + memcpy(ctx->path, path, len + 1); + + err = uv_timer_init(loop, &ctx->timer_handle); + if (err < 0) + goto error; + + ctx->timer_handle.flags |= UV__HANDLE_INTERNAL; + uv__handle_unref(&ctx->timer_handle); + + err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb); + if (err < 0) + goto error; + + handle->poll_ctx = ctx; + uv__handle_start(handle); + + return 0; + +error: + uv__free(ctx); + return err; +} + + +int uv_fs_poll_stop(uv_fs_poll_t* handle) { + struct poll_ctx* ctx; + + if (!uv__is_active(handle)) + return 0; + + ctx = handle->poll_ctx; + assert(ctx != NULL); + assert(ctx->parent_handle != NULL); + ctx->parent_handle = NULL; + handle->poll_ctx = NULL; + + /* Close the timer if it's active. If it's inactive, there's a stat request + * in progress and poll_cb will take care of the cleanup. + */ + if (uv__is_active(&ctx->timer_handle)) + uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); + + uv__handle_stop(handle); + + return 0; +} + + +int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) { + struct poll_ctx* ctx; + size_t required_len; + + if (!uv__is_active(handle)) { + *size = 0; + return UV_EINVAL; + } + + ctx = handle->poll_ctx; + assert(ctx != NULL); + + required_len = strlen(ctx->path); + if (required_len >= *size) { + *size = required_len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, ctx->path, required_len); + *size = required_len; + buffer[required_len] = '\0'; + + return 0; +} + + +void uv__fs_poll_close(uv_fs_poll_t* handle) { + uv_fs_poll_stop(handle); +} + + +static void timer_cb(uv_timer_t* timer) { + struct poll_ctx* ctx; + + ctx = container_of(timer, struct poll_ctx, timer_handle); + assert(ctx->parent_handle != NULL); + assert(ctx->parent_handle->poll_ctx == ctx); + ctx->start_time = uv_now(ctx->loop); + + if (uv_fs_stat(ctx->loop, &ctx->fs_req, ctx->path, poll_cb)) + abort(); +} + + +static void poll_cb(uv_fs_t* req) { + uv_stat_t* statbuf; + struct poll_ctx* ctx; + uint64_t interval; + + ctx = container_of(req, struct poll_ctx, fs_req); + + if (ctx->parent_handle == NULL) { /* handle has been stopped or closed */ + uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); + uv_fs_req_cleanup(req); + return; + } + + if (req->result != 0) { + if (ctx->busy_polling != req->result) { + ctx->poll_cb(ctx->parent_handle, + req->result, + &ctx->statbuf, + &zero_statbuf); + ctx->busy_polling = req->result; + } + goto out; + } + + statbuf = &req->statbuf; + + if (ctx->busy_polling != 0) + if (ctx->busy_polling < 0 || !statbuf_eq(&ctx->statbuf, statbuf)) + ctx->poll_cb(ctx->parent_handle, 0, &ctx->statbuf, statbuf); + + ctx->statbuf = *statbuf; + ctx->busy_polling = 1; + +out: + uv_fs_req_cleanup(req); + + if (ctx->parent_handle == NULL) { /* handle has been stopped by callback */ + uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); + return; + } + + /* Reschedule timer, subtract the delay from doing the stat(). */ + interval = ctx->interval; + interval -= (uv_now(ctx->loop) - ctx->start_time) % interval; + + if (uv_timer_start(&ctx->timer_handle, timer_cb, interval, 0)) + abort(); +} + + +static void timer_close_cb(uv_handle_t* handle) { + uv__free(container_of(handle, struct poll_ctx, timer_handle)); +} + + +static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) { + return a->st_ctim.tv_nsec == b->st_ctim.tv_nsec + && a->st_mtim.tv_nsec == b->st_mtim.tv_nsec + && a->st_birthtim.tv_nsec == b->st_birthtim.tv_nsec + && a->st_ctim.tv_sec == b->st_ctim.tv_sec + && a->st_mtim.tv_sec == b->st_mtim.tv_sec + && a->st_birthtim.tv_sec == b->st_birthtim.tv_sec + && a->st_size == b->st_size + && a->st_mode == b->st_mode + && a->st_uid == b->st_uid + && a->st_gid == b->st_gid + && a->st_ino == b->st_ino + && a->st_dev == b->st_dev + && a->st_flags == b->st_flags + && a->st_gen == b->st_gen; +} + + +#if defined(_WIN32) + +#include "win/internal.h" +#include "win/handle-inl.h" + +void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) { + assert(handle->flags & UV__HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); +} + +#endif /* _WIN32 */ diff --git a/src/heap-inl.h b/src/heap-inl.h new file mode 100644 index 0000000..1e2ed60 --- /dev/null +++ b/src/heap-inl.h @@ -0,0 +1,245 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef UV_SRC_HEAP_H_ +#define UV_SRC_HEAP_H_ + +#include /* NULL */ + +#if defined(__GNUC__) +# define HEAP_EXPORT(declaration) __attribute__((unused)) static declaration +#else +# define HEAP_EXPORT(declaration) static declaration +#endif + +struct heap_node { + struct heap_node* left; + struct heap_node* right; + struct heap_node* parent; +}; + +/* A binary min heap. The usual properties hold: the root is the lowest + * element in the set, the height of the tree is at most log2(nodes) and + * it's always a complete binary tree. + * + * The heap function try hard to detect corrupted tree nodes at the cost + * of a minor reduction in performance. Compile with -DNDEBUG to disable. + */ +struct heap { + struct heap_node* min; + unsigned int nelts; +}; + +/* Return non-zero if a < b. */ +typedef int (*heap_compare_fn)(const struct heap_node* a, + const struct heap_node* b); + +/* Public functions. */ +HEAP_EXPORT(void heap_init(struct heap* heap)); +HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap)); +HEAP_EXPORT(void heap_insert(struct heap* heap, + struct heap_node* newnode, + heap_compare_fn less_than)); +HEAP_EXPORT(void heap_remove(struct heap* heap, + struct heap_node* node, + heap_compare_fn less_than)); +HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)); + +/* Implementation follows. */ + +HEAP_EXPORT(void heap_init(struct heap* heap)) { + heap->min = NULL; + heap->nelts = 0; +} + +HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap)) { + return heap->min; +} + +/* Swap parent with child. Child moves closer to the root, parent moves away. */ +static void heap_node_swap(struct heap* heap, + struct heap_node* parent, + struct heap_node* child) { + struct heap_node* sibling; + struct heap_node t; + + t = *parent; + *parent = *child; + *child = t; + + parent->parent = child; + if (child->left == child) { + child->left = parent; + sibling = child->right; + } else { + child->right = parent; + sibling = child->left; + } + if (sibling != NULL) + sibling->parent = child; + + if (parent->left != NULL) + parent->left->parent = parent; + if (parent->right != NULL) + parent->right->parent = parent; + + if (child->parent == NULL) + heap->min = child; + else if (child->parent->left == parent) + child->parent->left = child; + else + child->parent->right = child; +} + +HEAP_EXPORT(void heap_insert(struct heap* heap, + struct heap_node* newnode, + heap_compare_fn less_than)) { + struct heap_node** parent; + struct heap_node** child; + unsigned int path; + unsigned int n; + unsigned int k; + + newnode->left = NULL; + newnode->right = NULL; + newnode->parent = NULL; + + /* Calculate the path from the root to the insertion point. This is a min + * heap so we always insert at the left-most free node of the bottom row. + */ + path = 0; + for (k = 0, n = 1 + heap->nelts; n >= 2; k += 1, n /= 2) + path = (path << 1) | (n & 1); + + /* Now traverse the heap using the path we calculated in the previous step. */ + parent = child = &heap->min; + while (k > 0) { + parent = child; + if (path & 1) + child = &(*child)->right; + else + child = &(*child)->left; + path >>= 1; + k -= 1; + } + + /* Insert the new node. */ + newnode->parent = *parent; + *child = newnode; + heap->nelts += 1; + + /* Walk up the tree and check at each node if the heap property holds. + * It's a min heap so parent < child must be true. + */ + while (newnode->parent != NULL && less_than(newnode, newnode->parent)) + heap_node_swap(heap, newnode->parent, newnode); +} + +HEAP_EXPORT(void heap_remove(struct heap* heap, + struct heap_node* node, + heap_compare_fn less_than)) { + struct heap_node* smallest; + struct heap_node** max; + struct heap_node* child; + unsigned int path; + unsigned int k; + unsigned int n; + + if (heap->nelts == 0) + return; + + /* Calculate the path from the min (the root) to the max, the left-most node + * of the bottom row. + */ + path = 0; + for (k = 0, n = heap->nelts; n >= 2; k += 1, n /= 2) + path = (path << 1) | (n & 1); + + /* Now traverse the heap using the path we calculated in the previous step. */ + max = &heap->min; + while (k > 0) { + if (path & 1) + max = &(*max)->right; + else + max = &(*max)->left; + path >>= 1; + k -= 1; + } + + heap->nelts -= 1; + + /* Unlink the max node. */ + child = *max; + *max = NULL; + + if (child == node) { + /* We're removing either the max or the last node in the tree. */ + if (child == heap->min) { + heap->min = NULL; + } + return; + } + + /* Replace the to be deleted node with the max node. */ + child->left = node->left; + child->right = node->right; + child->parent = node->parent; + + if (child->left != NULL) { + child->left->parent = child; + } + + if (child->right != NULL) { + child->right->parent = child; + } + + if (node->parent == NULL) { + heap->min = child; + } else if (node->parent->left == node) { + node->parent->left = child; + } else { + node->parent->right = child; + } + + /* Walk down the subtree and check at each node if the heap property holds. + * It's a min heap so parent < child must be true. If the parent is bigger, + * swap it with the smallest child. + */ + for (;;) { + smallest = child; + if (child->left != NULL && less_than(child->left, smallest)) + smallest = child->left; + if (child->right != NULL && less_than(child->right, smallest)) + smallest = child->right; + if (smallest == child) + break; + heap_node_swap(heap, child, smallest); + } + + /* Walk up the subtree and check that each parent is less than the node + * this is required, because `max` node is not guaranteed to be the + * actual maximum in tree + */ + while (child->parent != NULL && less_than(child, child->parent)) + heap_node_swap(heap, child->parent, child); +} + +HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)) { + heap_remove(heap, heap->min, less_than); +} + +#undef HEAP_EXPORT + +#endif /* UV_SRC_HEAP_H_ */ diff --git a/src/inet.c b/src/inet.c new file mode 100644 index 0000000..da63a68 --- /dev/null +++ b/src/inet.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#include "uv.h" +#include "uv-common.h" + +#define UV__INET_ADDRSTRLEN 16 +#define UV__INET6_ADDRSTRLEN 46 + + +static int inet_ntop4(const unsigned char *src, char *dst, size_t size); +static int inet_ntop6(const unsigned char *src, char *dst, size_t size); +static int inet_pton4(const char *src, unsigned char *dst); +static int inet_pton6(const char *src, unsigned char *dst); + + +int uv_inet_ntop(int af, const void* src, char* dst, size_t size) { + switch (af) { + case AF_INET: + return (inet_ntop4(src, dst, size)); + case AF_INET6: + return (inet_ntop6(src, dst, size)); + default: + return UV_EAFNOSUPPORT; + } + /* NOTREACHED */ +} + + +static int inet_ntop4(const unsigned char *src, char *dst, size_t size) { + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[UV__INET_ADDRSTRLEN]; + int l; + + l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); + if (l <= 0 || (size_t) l >= size) { + return UV_ENOSPC; + } + strncpy(dst, tmp, size); + dst[size - 1] = '\0'; + return 0; +} + + +static int inet_ntop6(const unsigned char *src, char *dst, size_t size) { + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[UV__INET6_ADDRSTRLEN], *tp; + struct { int base, len; } best, cur; + unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < (int) sizeof(struct in6_addr); i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + best.len = 0; + cur.base = -1; + cur.len = 0; + for (i = 0; i < (int) ARRAY_SIZE(words); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (int) ARRAY_SIZE(words); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && (best.len == 6 || + (best.len == 7 && words[7] != 0x0001) || + (best.len == 5 && words[5] == 0xffff))) { + int err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)); + if (err) + return err; + tp += strlen(tp); + break; + } + tp += sprintf(tp, "%x", words[i]); + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + return UV_ENOSPC; + } + strcpy(dst, tmp); + return 0; +} + + +int uv_inet_pton(int af, const char* src, void* dst) { + if (src == NULL || dst == NULL) + return UV_EINVAL; + + switch (af) { + case AF_INET: + return (inet_pton4(src, dst)); + case AF_INET6: { + int len; + char tmp[UV__INET6_ADDRSTRLEN], *s, *p; + s = (char*) src; + p = strchr(src, '%'); + if (p != NULL) { + s = tmp; + len = p - src; + if (len > UV__INET6_ADDRSTRLEN-1) + return UV_EINVAL; + memcpy(s, src, len); + s[len] = '\0'; + } + return inet_pton6(s, dst); + } + default: + return UV_EAFNOSUPPORT; + } + /* NOTREACHED */ +} + + +static int inet_pton4(const char *src, unsigned char *dst) { + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + unsigned char tmp[sizeof(struct in_addr)], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + unsigned int nw = *tp * 10 + (pch - digits); + + if (saw_digit && *tp == 0) + return UV_EINVAL; + if (nw > 255) + return UV_EINVAL; + *tp = nw; + if (!saw_digit) { + if (++octets > 4) + return UV_EINVAL; + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return UV_EINVAL; + *++tp = 0; + saw_digit = 0; + } else + return UV_EINVAL; + } + if (octets < 4) + return UV_EINVAL; + memcpy(dst, tmp, sizeof(struct in_addr)); + return 0; +} + + +static int inet_pton6(const char *src, unsigned char *dst) { + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[sizeof(struct in6_addr)], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, seen_xdigits; + unsigned int val; + + memset((tp = tmp), '\0', sizeof tmp); + endp = tp + sizeof tmp; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return UV_EINVAL; + curtok = src; + seen_xdigits = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (++seen_xdigits > 4) + return UV_EINVAL; + continue; + } + if (ch == ':') { + curtok = src; + if (!seen_xdigits) { + if (colonp) + return UV_EINVAL; + colonp = tp; + continue; + } else if (*src == '\0') { + return UV_EINVAL; + } + if (tp + sizeof(uint16_t) > endp) + return UV_EINVAL; + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + seen_xdigits = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) { + int err = inet_pton4(curtok, tp); + if (err == 0) { + tp += sizeof(struct in_addr); + seen_xdigits = 0; + break; /*%< '\\0' was seen by inet_pton4(). */ + } + } + return UV_EINVAL; + } + if (seen_xdigits) { + if (tp + sizeof(uint16_t) > endp) + return UV_EINVAL; + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + if (tp == endp) + return UV_EINVAL; + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return UV_EINVAL; + memcpy(dst, tmp, sizeof tmp); + return 0; +} diff --git a/src/queue.h b/src/queue.h new file mode 100644 index 0000000..ff3540a --- /dev/null +++ b/src/queue.h @@ -0,0 +1,108 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef QUEUE_H_ +#define QUEUE_H_ + +#include + +typedef void *QUEUE[2]; + +/* Private macros. */ +#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0])) +#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1])) +#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q))) +#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q))) + +/* Public macros. */ +#define QUEUE_DATA(ptr, type, field) \ + ((type *) ((char *) (ptr) - offsetof(type, field))) + +/* Important note: mutating the list while QUEUE_FOREACH is + * iterating over its elements results in undefined behavior. + */ +#define QUEUE_FOREACH(q, h) \ + for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q)) + +#define QUEUE_EMPTY(q) \ + ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q)) + +#define QUEUE_HEAD(q) \ + (QUEUE_NEXT(q)) + +#define QUEUE_INIT(q) \ + do { \ + QUEUE_NEXT(q) = (q); \ + QUEUE_PREV(q) = (q); \ + } \ + while (0) + +#define QUEUE_ADD(h, n) \ + do { \ + QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \ + QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \ + QUEUE_PREV(h) = QUEUE_PREV(n); \ + QUEUE_PREV_NEXT(h) = (h); \ + } \ + while (0) + +#define QUEUE_SPLIT(h, q, n) \ + do { \ + QUEUE_PREV(n) = QUEUE_PREV(h); \ + QUEUE_PREV_NEXT(n) = (n); \ + QUEUE_NEXT(n) = (q); \ + QUEUE_PREV(h) = QUEUE_PREV(q); \ + QUEUE_PREV_NEXT(h) = (h); \ + QUEUE_PREV(q) = (n); \ + } \ + while (0) + +#define QUEUE_MOVE(h, n) \ + do { \ + if (QUEUE_EMPTY(h)) \ + QUEUE_INIT(n); \ + else { \ + QUEUE* q = QUEUE_HEAD(h); \ + QUEUE_SPLIT(h, q, n); \ + } \ + } \ + while (0) + +#define QUEUE_INSERT_HEAD(h, q) \ + do { \ + QUEUE_NEXT(q) = QUEUE_NEXT(h); \ + QUEUE_PREV(q) = (h); \ + QUEUE_NEXT_PREV(q) = (q); \ + QUEUE_NEXT(h) = (q); \ + } \ + while (0) + +#define QUEUE_INSERT_TAIL(h, q) \ + do { \ + QUEUE_NEXT(q) = (h); \ + QUEUE_PREV(q) = QUEUE_PREV(h); \ + QUEUE_PREV_NEXT(q) = (q); \ + QUEUE_PREV(h) = (q); \ + } \ + while (0) + +#define QUEUE_REMOVE(q) \ + do { \ + QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \ + QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \ + } \ + while (0) + +#endif /* QUEUE_H_ */ diff --git a/src/threadpool.c b/src/threadpool.c new file mode 100644 index 0000000..2c5152b --- /dev/null +++ b/src/threadpool.c @@ -0,0 +1,303 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv-common.h" + +#if !defined(_WIN32) +# include "unix/internal.h" +#else +# include "win/req-inl.h" +/* TODO(saghul): unify internal req functions */ +static void uv__req_init(uv_loop_t* loop, + uv_req_t* req, + uv_req_type type) { + uv_req_init(loop, req); + req->type = type; + uv__req_register(loop, req); +} +# define uv__req_init(loop, req, type) \ + uv__req_init((loop), (uv_req_t*)(req), (type)) +#endif + +#include + +#define MAX_THREADPOOL_SIZE 128 + +static uv_once_t once = UV_ONCE_INIT; +static uv_cond_t cond; +static uv_mutex_t mutex; +static unsigned int idle_threads; +static unsigned int nthreads; +static uv_thread_t* threads; +static uv_thread_t default_threads[4]; +static QUEUE exit_message; +static QUEUE wq; +static volatile int initialized; + + +static void uv__cancelled(struct uv__work* w) { + abort(); +} + + +/* To avoid deadlock with uv_cancel() it's crucial that the worker + * never holds the global mutex and the loop-local mutex at the same time. + */ +static void worker(void* arg) { + struct uv__work* w; + QUEUE* q; + + (void) arg; + + for (;;) { + uv_mutex_lock(&mutex); + + while (QUEUE_EMPTY(&wq)) { + idle_threads += 1; + uv_cond_wait(&cond, &mutex); + idle_threads -= 1; + } + + q = QUEUE_HEAD(&wq); + + if (q == &exit_message) + uv_cond_signal(&cond); + else { + QUEUE_REMOVE(q); + QUEUE_INIT(q); /* Signal uv_cancel() that the work req is + executing. */ + } + + uv_mutex_unlock(&mutex); + + if (q == &exit_message) + break; + + w = QUEUE_DATA(q, struct uv__work, wq); + w->work(w); + + uv_mutex_lock(&w->loop->wq_mutex); + w->work = NULL; /* Signal uv_cancel() that the work req is done + executing. */ + QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq); + uv_async_send(&w->loop->wq_async); + uv_mutex_unlock(&w->loop->wq_mutex); + } +} + + +static void post(QUEUE* q) { + uv_mutex_lock(&mutex); + QUEUE_INSERT_TAIL(&wq, q); + if (idle_threads > 0) + uv_cond_signal(&cond); + uv_mutex_unlock(&mutex); +} + + +#ifndef _WIN32 +UV_DESTRUCTOR(static void cleanup(void)) { + unsigned int i; + + if (initialized == 0) + return; + + post(&exit_message); + + for (i = 0; i < nthreads; i++) + if (uv_thread_join(threads + i)) + abort(); + + if (threads != default_threads) + uv__free(threads); + + uv_mutex_destroy(&mutex); + uv_cond_destroy(&cond); + + threads = NULL; + nthreads = 0; + initialized = 0; +} +#endif + + +static void init_once(void) { + unsigned int i; + const char* val; + + nthreads = ARRAY_SIZE(default_threads); + val = getenv("UV_THREADPOOL_SIZE"); + if (val != NULL) + nthreads = atoi(val); + if (nthreads == 0) + nthreads = 1; + if (nthreads > MAX_THREADPOOL_SIZE) + nthreads = MAX_THREADPOOL_SIZE; + + threads = default_threads; + if (nthreads > ARRAY_SIZE(default_threads)) { + threads = uv__malloc(nthreads * sizeof(threads[0])); + if (threads == NULL) { + nthreads = ARRAY_SIZE(default_threads); + threads = default_threads; + } + } + + if (uv_cond_init(&cond)) + abort(); + + if (uv_mutex_init(&mutex)) + abort(); + + QUEUE_INIT(&wq); + + for (i = 0; i < nthreads; i++) + if (uv_thread_create(threads + i, worker, NULL)) + abort(); + + initialized = 1; +} + + +void uv__work_submit(uv_loop_t* loop, + struct uv__work* w, + void (*work)(struct uv__work* w), + void (*done)(struct uv__work* w, int status)) { + uv_once(&once, init_once); + w->loop = loop; + w->work = work; + w->done = done; + post(&w->wq); +} + + +static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) { + int cancelled; + + uv_mutex_lock(&mutex); + uv_mutex_lock(&w->loop->wq_mutex); + + cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL; + if (cancelled) + QUEUE_REMOVE(&w->wq); + + uv_mutex_unlock(&w->loop->wq_mutex); + uv_mutex_unlock(&mutex); + + if (!cancelled) + return UV_EBUSY; + + w->work = uv__cancelled; + uv_mutex_lock(&loop->wq_mutex); + QUEUE_INSERT_TAIL(&loop->wq, &w->wq); + uv_async_send(&loop->wq_async); + uv_mutex_unlock(&loop->wq_mutex); + + return 0; +} + + +void uv__work_done(uv_async_t* handle) { + struct uv__work* w; + uv_loop_t* loop; + QUEUE* q; + QUEUE wq; + int err; + + loop = container_of(handle, uv_loop_t, wq_async); + uv_mutex_lock(&loop->wq_mutex); + QUEUE_MOVE(&loop->wq, &wq); + uv_mutex_unlock(&loop->wq_mutex); + + while (!QUEUE_EMPTY(&wq)) { + q = QUEUE_HEAD(&wq); + QUEUE_REMOVE(q); + + w = container_of(q, struct uv__work, wq); + err = (w->work == uv__cancelled) ? UV_ECANCELED : 0; + w->done(w, err); + } +} + + +static void uv__queue_work(struct uv__work* w) { + uv_work_t* req = container_of(w, uv_work_t, work_req); + + req->work_cb(req); +} + + +static void uv__queue_done(struct uv__work* w, int err) { + uv_work_t* req; + + req = container_of(w, uv_work_t, work_req); + uv__req_unregister(req->loop, req); + + if (req->after_work_cb == NULL) + return; + + req->after_work_cb(req, err); +} + + +int uv_queue_work(uv_loop_t* loop, + uv_work_t* req, + uv_work_cb work_cb, + uv_after_work_cb after_work_cb) { + if (work_cb == NULL) + return UV_EINVAL; + + uv__req_init(loop, req, UV_WORK); + req->loop = loop; + req->work_cb = work_cb; + req->after_work_cb = after_work_cb; + uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done); + return 0; +} + + +int uv_cancel(uv_req_t* req) { + struct uv__work* wreq; + uv_loop_t* loop; + + switch (req->type) { + case UV_FS: + loop = ((uv_fs_t*) req)->loop; + wreq = &((uv_fs_t*) req)->work_req; + break; + case UV_GETADDRINFO: + loop = ((uv_getaddrinfo_t*) req)->loop; + wreq = &((uv_getaddrinfo_t*) req)->work_req; + break; + case UV_GETNAMEINFO: + loop = ((uv_getnameinfo_t*) req)->loop; + wreq = &((uv_getnameinfo_t*) req)->work_req; + break; + case UV_WORK: + loop = ((uv_work_t*) req)->loop; + wreq = &((uv_work_t*) req)->work_req; + break; + default: + return UV_EINVAL; + } + + return uv__work_cancel(loop, req, wreq); +} diff --git a/src/unix/aix.c b/src/unix/aix.c new file mode 100644 index 0000000..652cd98 --- /dev/null +++ b/src/unix/aix.c @@ -0,0 +1,1154 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#ifdef HAVE_SYS_AHAFS_EVPRODS_H +#include +#endif + +#include +#include +#include +#include +#include + +#define RDWR_BUF_SIZE 4096 +#define EQ(a,b) (strcmp(a,b) == 0) + +int uv__platform_loop_init(uv_loop_t* loop) { + loop->fs_fd = -1; + + /* Passing maxfd of -1 should mean the limit is determined + * by the user's ulimit or the global limit as per the doc */ + loop->backend_fd = pollset_create(-1); + + if (loop->backend_fd == -1) + return -1; + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->fs_fd != -1) { + uv__close(loop->fs_fd); + loop->fs_fd = -1; + } + + if (loop->backend_fd != -1) { + pollset_destroy(loop->backend_fd); + loop->backend_fd = -1; + } +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct poll_ctl pc; + + pc.events = POLLIN; + pc.cmd = PS_MOD; /* Equivalent to PS_ADD if the fd is not in the pollset. */ + pc.fd = fd; + + if (pollset_ctl(loop->backend_fd, &pc, 1)) + return -errno; + + pc.cmd = PS_DELETE; + if (pollset_ctl(loop->backend_fd, &pc, 1)) + abort(); + + return 0; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + struct pollfd events[1024]; + struct pollfd pqry; + struct pollfd* pe; + struct poll_ctl pc; + QUEUE* q; + uv__io_t* w; + uint64_t base; + uint64_t diff; + int have_signals; + int nevents; + int count; + int nfds; + int i; + int rc; + int add_failed; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + assert(w->fd >= 0); + assert(w->fd < (int) loop->nwatchers); + + pc.events = w->pevents; + pc.fd = w->fd; + + add_failed = 0; + if (w->events == 0) { + pc.cmd = PS_ADD; + if (pollset_ctl(loop->backend_fd, &pc, 1)) { + if (errno != EINVAL) { + assert(0 && "Failed to add file descriptor (pc.fd) to pollset"); + abort(); + } + /* Check if the fd is already in the pollset */ + pqry.fd = pc.fd; + rc = pollset_query(loop->backend_fd, &pqry); + switch (rc) { + case -1: + assert(0 && "Failed to query pollset for file descriptor"); + abort(); + case 0: + assert(0 && "Pollset does not contain file descriptor"); + abort(); + } + /* If we got here then the pollset already contained the file descriptor even though + * we didn't think it should. This probably shouldn't happen, but we can continue. */ + add_failed = 1; + } + } + if (w->events != 0 || add_failed) { + /* Modify, potentially removing events -- need to delete then add. + * Could maybe mod if we knew for sure no events are removed, but + * content of w->events is handled above as not reliable (falls back) + * so may require a pollset_query() which would have to be pretty cheap + * compared to a PS_DELETE to be worth optimizing. Alternatively, could + * lazily remove events, squelching them in the mean time. */ + pc.cmd = PS_DELETE; + if (pollset_ctl(loop->backend_fd, &pc, 1)) { + assert(0 && "Failed to delete file descriptor (pc.fd) from pollset"); + abort(); + } + pc.cmd = PS_ADD; + if (pollset_ctl(loop->backend_fd, &pc, 1)) { + assert(0 && "Failed to add file descriptor (pc.fd) to pollset"); + abort(); + } + } + + w->events = w->pevents; + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + + for (;;) { + nfds = pollset_poll(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout); + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (nfds == 0) { + assert(timeout != -1); + return; + } + + if (nfds == -1) { + if (errno != EINTR) { + abort(); + } + + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + have_signals = 0; + nevents = 0; + + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + + for (i = 0; i < nfds; i++) { + pe = events + i; + pc.cmd = PS_DELETE; + pc.fd = pe->fd; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (pc.fd == -1) + continue; + + assert(pc.fd >= 0); + assert((unsigned) pc.fd < loop->nwatchers); + + w = loop->watchers[pc.fd]; + + if (w == NULL) { + /* File descriptor that we've stopped watching, disarm it. + * + * Ignore all errors because we may be racing with another thread + * when the file descriptor is closed. + */ + pollset_ctl(loop->backend_fd, &pc, 1); + continue; + } + + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->revents); + + nevents++; + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + diff = loop->time - base; + if (diff >= (uint64_t) timeout) + return; + + timeout -= diff; + } +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + uint64_t G = 1000000000; + timebasestruct_t t; + read_wall_time(&t, TIMEBASE_SZ); + time_base_to_time(&t, TIMEBASE_SZ); + return (uint64_t) t.tb_high * G + t.tb_low; +} + + +/* + * We could use a static buffer for the path manipulations that we need outside + * of the function, but this function could be called by multiple consumers and + * we don't want to potentially create a race condition in the use of snprintf. + * There is no direct way of getting the exe path in AIX - either through /procfs + * or through some libc APIs. The below approach is to parse the argv[0]'s pattern + * and use it in conjunction with PATH environment variable to craft one. + */ +int uv_exepath(char* buffer, size_t* size) { + int res; + char args[PATH_MAX]; + char abspath[PATH_MAX]; + size_t abspath_size; + struct procsinfo pi; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + pi.pi_pid = getpid(); + res = getargs(&pi, sizeof(pi), args, sizeof(args)); + if (res < 0) + return -EINVAL; + + /* + * Possibilities for args: + * i) an absolute path such as: /home/user/myprojects/nodejs/node + * ii) a relative path such as: ./node or ../myprojects/nodejs/node + * iii) a bare filename such as "node", after exporting PATH variable + * to its location. + */ + + /* Case i) and ii) absolute or relative paths */ + if (strchr(args, '/') != NULL) { + if (realpath(args, abspath) != abspath) + return -errno; + + abspath_size = strlen(abspath); + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + return 0; + } else { + /* Case iii). Search PATH environment variable */ + char trypath[PATH_MAX]; + char *clonedpath = NULL; + char *token = NULL; + char *path = getenv("PATH"); + + if (path == NULL) + return -EINVAL; + + clonedpath = uv__strdup(path); + if (clonedpath == NULL) + return -ENOMEM; + + token = strtok(clonedpath, ":"); + while (token != NULL) { + snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args); + if (realpath(trypath, abspath) == abspath) { + /* Check the match is executable */ + if (access(abspath, X_OK) == 0) { + abspath_size = strlen(abspath); + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + uv__free(clonedpath); + return 0; + } + } + token = strtok(NULL, ":"); + } + uv__free(clonedpath); + + /* Out of tokens (path entries), and no match found */ + return -EINVAL; + } +} + + +uint64_t uv_get_free_memory(void) { + perfstat_memory_total_t mem_total; + int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1); + if (result == -1) { + return 0; + } + return mem_total.real_free * 4096; +} + + +uint64_t uv_get_total_memory(void) { + perfstat_memory_total_t mem_total; + int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1); + if (result == -1) { + return 0; + } + return mem_total.real_total * 4096; +} + + +void uv_loadavg(double avg[3]) { + perfstat_cpu_total_t ps_total; + int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1); + if (result == -1) { + avg[0] = 0.; avg[1] = 0.; avg[2] = 0.; + return; + } + avg[0] = ps_total.loadavg[0] / (double)(1 << SBITS); + avg[1] = ps_total.loadavg[1] / (double)(1 << SBITS); + avg[2] = ps_total.loadavg[2] / (double)(1 << SBITS); +} + + +#ifdef HAVE_SYS_AHAFS_EVPRODS_H +static char *uv__rawname(char *cp) { + static char rawbuf[FILENAME_MAX+1]; + char *dp = rindex(cp, '/'); + + if (dp == 0) + return 0; + + *dp = 0; + strcpy(rawbuf, cp); + *dp = '/'; + strcat(rawbuf, "/r"); + strcat(rawbuf, dp+1); + return rawbuf; +} + + +/* + * Determine whether given pathname is a directory + * Returns 0 if the path is a directory, -1 if not + * + * Note: Opportunity here for more detailed error information but + * that requires changing callers of this function as well + */ +static int uv__path_is_a_directory(char* filename) { + struct stat statbuf; + + if (stat(filename, &statbuf) < 0) + return -1; /* failed: not a directory, assume it is a file */ + + if (statbuf.st_type == VDIR) + return 0; + + return -1; +} + + +/* + * Check whether AHAFS is mounted. + * Returns 0 if AHAFS is mounted, or an error code < 0 on failure + */ +static int uv__is_ahafs_mounted(void){ + int rv, i = 2; + struct vmount *p; + int size_multiplier = 10; + size_t siz = sizeof(struct vmount)*size_multiplier; + struct vmount *vmt; + const char *dev = "/aha"; + char *obj, *stub; + + p = uv__malloc(siz); + if (p == NULL) + return -errno; + + /* Retrieve all mounted filesystems */ + rv = mntctl(MCTL_QUERY, siz, (char*)p); + if (rv < 0) + return -errno; + if (rv == 0) { + /* buffer was not large enough, reallocate to correct size */ + siz = *(int*)p; + uv__free(p); + p = uv__malloc(siz); + if (p == NULL) + return -errno; + rv = mntctl(MCTL_QUERY, siz, (char*)p); + if (rv < 0) + return -errno; + } + + /* Look for dev in filesystems mount info */ + for(vmt = p, i = 0; i < rv; i++) { + obj = vmt2dataptr(vmt, VMT_OBJECT); /* device */ + stub = vmt2dataptr(vmt, VMT_STUB); /* mount point */ + + if (EQ(obj, dev) || EQ(uv__rawname(obj), dev) || EQ(stub, dev)) { + uv__free(p); /* Found a match */ + return 0; + } + vmt = (struct vmount *) ((char *) vmt + vmt->vmt_length); + } + + /* /aha is required for monitoring filesystem changes */ + return -1; +} + +/* + * Recursive call to mkdir() to create intermediate folders, if any + * Returns code from mkdir call + */ +static int uv__makedir_p(const char *dir) { + char tmp[256]; + char *p = NULL; + size_t len; + int err; + + snprintf(tmp, sizeof(tmp),"%s",dir); + len = strlen(tmp); + if (tmp[len - 1] == '/') + tmp[len - 1] = 0; + for (p = tmp + 1; *p; p++) { + if (*p == '/') { + *p = 0; + err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (err != 0 && errno != EEXIST) + return err; + *p = '/'; + } + } + return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +} + +/* + * Creates necessary subdirectories in the AIX Event Infrastructure + * file system for monitoring the object specified. + * Returns code from mkdir call + */ +static int uv__make_subdirs_p(const char *filename) { + char cmd[2048]; + char *p; + int rc = 0; + + /* Strip off the monitor file name */ + p = strrchr(filename, '/'); + + if (p == NULL) + return 0; + + if (uv__path_is_a_directory((char*)filename) == 0) { + sprintf(cmd, "/aha/fs/modDir.monFactory"); + } else { + sprintf(cmd, "/aha/fs/modFile.monFactory"); + } + + strncat(cmd, filename, (p - filename)); + rc = uv__makedir_p(cmd); + + if (rc == -1 && errno != EEXIST){ + return -errno; + } + + return rc; +} + + +/* + * Checks if /aha is mounted, then proceeds to set up the monitoring + * objects for the specified file. + * Returns 0 on success, or an error code < 0 on failure + */ +static int uv__setup_ahafs(const char* filename, int *fd) { + int rc = 0; + char mon_file_write_string[RDWR_BUF_SIZE]; + char mon_file[PATH_MAX]; + int file_is_directory = 0; /* -1 == NO, 0 == YES */ + + /* Create monitor file name for object */ + file_is_directory = uv__path_is_a_directory((char*)filename); + + if (file_is_directory == 0) + sprintf(mon_file, "/aha/fs/modDir.monFactory"); + else + sprintf(mon_file, "/aha/fs/modFile.monFactory"); + + if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX) + return -ENAMETOOLONG; + + /* Make the necessary subdirectories for the monitor file */ + rc = uv__make_subdirs_p(filename); + if (rc == -1 && errno != EEXIST) + return rc; + + strcat(mon_file, filename); + strcat(mon_file, ".mon"); + + *fd = 0; errno = 0; + + /* Open the monitor file, creating it if necessary */ + *fd = open(mon_file, O_CREAT|O_RDWR); + if (*fd < 0) + return -errno; + + /* Write out the monitoring specifications. + * In this case, we are monitoring for a state change event type + * CHANGED=YES + * We will be waiting in select call, rather than a read: + * WAIT_TYPE=WAIT_IN_SELECT + * We only want minimal information for files: + * INFO_LVL=1 + * For directories, we want more information to track what file + * caused the change + * INFO_LVL=2 + */ + + if (file_is_directory == 0) + sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=2"); + else + sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1"); + + rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1); + if (rc < 0) + return -errno; + + return 0; +} + +/* + * Skips a specified number of lines in the buffer passed in. + * Walks the buffer pointed to by p and attempts to skip n lines. + * Returns the total number of lines skipped + */ +static int uv__skip_lines(char **p, int n) { + int lines = 0; + + while(n > 0) { + *p = strchr(*p, '\n'); + if (!p) + return lines; + + (*p)++; + n--; + lines++; + } + return lines; +} + + +/* + * Parse the event occurrence data to figure out what event just occurred + * and take proper action. + * + * The buf is a pointer to the buffer containing the event occurrence data + * Returns 0 on success, -1 if unrecoverable error in parsing + * + */ +static int uv__parse_data(char *buf, int *events, uv_fs_event_t* handle) { + int evp_rc, i; + char *p; + char filename[PATH_MAX]; /* To be used when handling directories */ + + p = buf; + *events = 0; + + /* Clean the filename buffer*/ + for(i = 0; i < PATH_MAX; i++) { + filename[i] = 0; + } + i = 0; + + /* Check for BUF_WRAP */ + if (strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0) { + assert(0 && "Buffer wrap detected, Some event occurrences lost!"); + return 0; + } + + /* Since we are using the default buffer size (4K), and have specified + * INFO_LVL=1, we won't see any EVENT_OVERFLOW conditions. Applications + * should check for this keyword if they are using an INFO_LVL of 2 or + * higher, and have a buffer size of <= 4K + */ + + /* Skip to RC_FROM_EVPROD */ + if (uv__skip_lines(&p, 9) != 9) + return -1; + + if (sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1) { + if (uv__path_is_a_directory(handle->path) == 0) { /* Directory */ + if (evp_rc == AHAFS_MODDIR_UNMOUNT || evp_rc == AHAFS_MODDIR_REMOVE_SELF) { + /* The directory is no longer available for monitoring */ + *events = UV_RENAME; + handle->dir_filename = NULL; + } else { + /* A file was added/removed inside the directory */ + *events = UV_CHANGE; + + /* Get the EVPROD_INFO */ + if (uv__skip_lines(&p, 1) != 1) + return -1; + + /* Scan out the name of the file that triggered the event*/ + if (sscanf(p, "BEGIN_EVPROD_INFO\n%sEND_EVPROD_INFO", filename) == 1) { + handle->dir_filename = uv__strdup((const char*)&filename); + } else + return -1; + } + } else { /* Regular File */ + if (evp_rc == AHAFS_MODFILE_RENAME) + *events = UV_RENAME; + else + *events = UV_CHANGE; + } + } + else + return -1; + + return 0; +} + + +/* This is the internal callback */ +static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) { + char result_data[RDWR_BUF_SIZE]; + int bytes, rc = 0; + uv_fs_event_t* handle; + int events = 0; + char fname[PATH_MAX]; + char *p; + + handle = container_of(event_watch, uv_fs_event_t, event_watcher); + + /* At this point, we assume that polling has been done on the + * file descriptor, so we can just read the AHAFS event occurrence + * data and parse its results without having to block anything + */ + bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0); + + assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file"); + + /* Parse the data */ + if(bytes > 0) + rc = uv__parse_data(result_data, &events, handle); + + /* Unrecoverable error */ + if (rc == -1) + return; + + /* For directory changes, the name of the files that triggered the change + * are never absolute pathnames + */ + if (uv__path_is_a_directory(handle->path) == 0) { + p = handle->dir_filename; + } else { + p = strrchr(handle->path, '/'); + if (p == NULL) + p = handle->path; + else + p++; + } + strncpy(fname, p, sizeof(fname) - 1); + /* Just in case */ + fname[sizeof(fname) - 1] = '\0'; + + handle->cb(handle, fname, events, 0); +} +#endif + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { +#ifdef HAVE_SYS_AHAFS_EVPRODS_H + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + return 0; +#else + return -ENOSYS; +#endif +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* filename, + unsigned int flags) { +#ifdef HAVE_SYS_AHAFS_EVPRODS_H + int fd, rc, str_offset = 0; + char cwd[PATH_MAX]; + char absolute_path[PATH_MAX]; + char readlink_cwd[PATH_MAX]; + + + /* Figure out whether filename is absolute or not */ + if (filename[0] == '/') { + /* We have absolute pathname */ + snprintf(absolute_path, sizeof(absolute_path), "%s", filename); + } else { + /* We have a relative pathname, compose the absolute pathname */ + snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid()); + rc = readlink(cwd, readlink_cwd, sizeof(readlink_cwd) - 1); + if (rc < 0) + return rc; + /* readlink does not null terminate our string */ + readlink_cwd[rc] = '\0'; + + if (filename[0] == '.' && filename[1] == '/') + str_offset = 2; + + snprintf(absolute_path, sizeof(absolute_path), "%s%s", readlink_cwd, + filename + str_offset); + } + + if (uv__is_ahafs_mounted() < 0) /* /aha checks failed */ + return UV_ENOSYS; + + /* Setup ahafs */ + rc = uv__setup_ahafs((const char *)absolute_path, &fd); + if (rc != 0) + return rc; + + /* Setup/Initialize all the libuv routines */ + uv__handle_start(handle); + uv__io_init(&handle->event_watcher, uv__ahafs_event, fd); + handle->path = uv__strdup(filename); + handle->cb = cb; + + uv__io_start(handle->loop, &handle->event_watcher, POLLIN); + + return 0; +#else + return -ENOSYS; +#endif +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { +#ifdef HAVE_SYS_AHAFS_EVPRODS_H + if (!uv__is_active(handle)) + return 0; + + uv__io_close(handle->loop, &handle->event_watcher); + uv__handle_stop(handle); + + if (uv__path_is_a_directory(handle->path) == 0) { + uv__free(handle->dir_filename); + handle->dir_filename = NULL; + } + + uv__free(handle->path); + handle->path = NULL; + uv__close(handle->event_watcher.fd); + handle->event_watcher.fd = -1; + + return 0; +#else + return -ENOSYS; +#endif +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { +#ifdef HAVE_SYS_AHAFS_EVPRODS_H + uv_fs_event_stop(handle); +#else + UNREACHABLE(); +#endif +} + + +char** uv_setup_args(int argc, char** argv) { + return argv; +} + + +int uv_set_process_title(const char* title) { + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + if (buffer == NULL || size == 0) + return -EINVAL; + + buffer[0] = '\0'; + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + char pp[64]; + psinfo_t psinfo; + int err; + int fd; + + snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); + + fd = open(pp, O_RDONLY); + if (fd == -1) + return -errno; + + /* FIXME(bnoordhuis) Handle EINTR. */ + err = -EINVAL; + if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) { + *rss = (size_t)psinfo.pr_rssize * 1024; + err = 0; + } + uv__close(fd); + + return err; +} + + +int uv_uptime(double* uptime) { + struct utmp *utmp_buf; + size_t entries = 0; + time_t boot_time; + + utmpname(UTMP_FILE); + + setutent(); + + while ((utmp_buf = getutent()) != NULL) { + if (utmp_buf->ut_user[0] && utmp_buf->ut_type == USER_PROCESS) + ++entries; + if (utmp_buf->ut_type == BOOT_TIME) + boot_time = utmp_buf->ut_time; + } + + endutent(); + + if (boot_time == 0) + return -ENOSYS; + + *uptime = time(NULL) - boot_time; + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + uv_cpu_info_t* cpu_info; + perfstat_cpu_total_t ps_total; + perfstat_cpu_t* ps_cpus; + perfstat_id_t cpu_id; + int result, ncpus, idx = 0; + + result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1); + if (result == -1) { + return -ENOSYS; + } + + ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0); + if (result == -1) { + return -ENOSYS; + } + + ps_cpus = (perfstat_cpu_t*) uv__malloc(ncpus * sizeof(perfstat_cpu_t)); + if (!ps_cpus) { + return -ENOMEM; + } + + strcpy(cpu_id.name, FIRST_CPU); + result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus); + if (result == -1) { + uv__free(ps_cpus); + return -ENOSYS; + } + + *cpu_infos = (uv_cpu_info_t*) uv__malloc(ncpus * sizeof(uv_cpu_info_t)); + if (!*cpu_infos) { + uv__free(ps_cpus); + return -ENOMEM; + } + + *count = ncpus; + + cpu_info = *cpu_infos; + while (idx < ncpus) { + cpu_info->speed = (int)(ps_total.processorHZ / 1000000); + cpu_info->model = uv__strdup(ps_total.description); + cpu_info->cpu_times.user = ps_cpus[idx].user; + cpu_info->cpu_times.sys = ps_cpus[idx].sys; + cpu_info->cpu_times.idle = ps_cpus[idx].idle; + cpu_info->cpu_times.irq = ps_cpus[idx].wait; + cpu_info->cpu_times.nice = 0; + cpu_info++; + idx++; + } + + uv__free(ps_cpus); + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; ++i) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, + int* count) { + uv_interface_address_t* address; + int sockfd, size = 1; + struct ifconf ifc; + struct ifreq *ifr, *p, flg; + + *count = 0; + + if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) { + return -errno; + } + + if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) { + uv__close(sockfd); + return -errno; + } + + ifc.ifc_req = (struct ifreq*)uv__malloc(size); + ifc.ifc_len = size; + if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { + uv__close(sockfd); + return -errno; + } + +#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p)) + + /* Count all up and running ipv4/ipv6 addresses */ + ifr = ifc.ifc_req; + while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { + p = ifr; + ifr = (struct ifreq*) + ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); + + if (!(p->ifr_addr.sa_family == AF_INET6 || + p->ifr_addr.sa_family == AF_INET)) + continue; + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return -errno; + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + (*count)++; + } + + /* Alloc the return interface structs */ + *addresses = (uv_interface_address_t*) + uv__malloc(*count * sizeof(uv_interface_address_t)); + if (!(*addresses)) { + uv__close(sockfd); + return -ENOMEM; + } + address = *addresses; + + ifr = ifc.ifc_req; + while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { + p = ifr; + ifr = (struct ifreq*) + ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); + + if (!(p->ifr_addr.sa_family == AF_INET6 || + p->ifr_addr.sa_family == AF_INET)) + continue; + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return -ENOSYS; + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + /* All conditions above must match count loop */ + + address->name = uv__strdup(p->ifr_name); + + if (p->ifr_addr.sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); + } + + /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ + + address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; + + address++; + } + +#undef ADDR_SIZE + + uv__close(sockfd); + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; ++i) { + uv__free(addresses[i].name); + } + + uv__free(addresses); +} + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct pollfd* events; + uintptr_t i; + uintptr_t nfds; + struct poll_ctl pc; + + assert(loop->watchers != NULL); + + events = (struct pollfd*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + + if (events != NULL) + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].fd == fd) + events[i].fd = -1; + + /* Remove the file descriptor from the poll set */ + pc.events = 0; + pc.cmd = PS_DELETE; + pc.fd = fd; + if(loop->backend_fd >= 0) + pollset_ctl(loop->backend_fd, &pc, 1); +} diff --git a/src/unix/android-ifaddrs.c b/src/unix/android-ifaddrs.c new file mode 100644 index 0000000..30f681b --- /dev/null +++ b/src/unix/android-ifaddrs.c @@ -0,0 +1,703 @@ +/* +Copyright (c) 2013, Kenneth MacKay +Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016) +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. + +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. +*/ + +#include "android-ifaddrs.h" +#include "uv-common.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct NetlinkList +{ + struct NetlinkList *m_next; + struct nlmsghdr *m_data; + unsigned int m_size; +} NetlinkList; + +static int netlink_socket(void) +{ + struct sockaddr_nl l_addr; + + int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if(l_socket < 0) + { + return -1; + } + + memset(&l_addr, 0, sizeof(l_addr)); + l_addr.nl_family = AF_NETLINK; + if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0) + { + close(l_socket); + return -1; + } + + return l_socket; +} + +static int netlink_send(int p_socket, int p_request) +{ + char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))]; + + struct nlmsghdr *l_hdr; + struct rtgenmsg *l_msg; + struct sockaddr_nl l_addr; + + memset(l_buffer, 0, sizeof(l_buffer)); + + l_hdr = (struct nlmsghdr *)l_buffer; + l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr); + + l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg)); + l_hdr->nlmsg_type = p_request; + l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; + l_hdr->nlmsg_pid = 0; + l_hdr->nlmsg_seq = p_socket; + l_msg->rtgen_family = AF_UNSPEC; + + memset(&l_addr, 0, sizeof(l_addr)); + l_addr.nl_family = AF_NETLINK; + return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr))); +} + +static int netlink_recv(int p_socket, void *p_buffer, size_t p_len) +{ + struct sockaddr_nl l_addr; + struct msghdr l_msg; + + struct iovec l_iov; + l_iov.iov_base = p_buffer; + l_iov.iov_len = p_len; + + for(;;) + { + int l_result; + l_msg.msg_name = (void *)&l_addr; + l_msg.msg_namelen = sizeof(l_addr); + l_msg.msg_iov = &l_iov; + l_msg.msg_iovlen = 1; + l_msg.msg_control = NULL; + l_msg.msg_controllen = 0; + l_msg.msg_flags = 0; + l_result = recvmsg(p_socket, &l_msg, 0); + + if(l_result < 0) + { + if(errno == EINTR) + { + continue; + } + return -2; + } + + /* Buffer was too small */ + if(l_msg.msg_flags & MSG_TRUNC) + { + return -1; + } + return l_result; + } +} + +static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done) +{ + size_t l_size = 4096; + void *l_buffer = NULL; + + for(;;) + { + int l_read; + + uv__free(l_buffer); + l_buffer = uv__malloc(l_size); + if (l_buffer == NULL) + { + return NULL; + } + + l_read = netlink_recv(p_socket, l_buffer, l_size); + *p_size = l_read; + if(l_read == -2) + { + uv__free(l_buffer); + return NULL; + } + if(l_read >= 0) + { + pid_t l_pid = getpid(); + struct nlmsghdr *l_hdr; + for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read)) + { + if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + { + continue; + } + + if(l_hdr->nlmsg_type == NLMSG_DONE) + { + *p_done = 1; + break; + } + + if(l_hdr->nlmsg_type == NLMSG_ERROR) + { + uv__free(l_buffer); + return NULL; + } + } + return l_buffer; + } + + l_size *= 2; + } +} + +static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size) +{ + NetlinkList *l_item = uv__malloc(sizeof(NetlinkList)); + if (l_item == NULL) + { + return NULL; + } + + l_item->m_next = NULL; + l_item->m_data = p_data; + l_item->m_size = p_size; + return l_item; +} + +static void freeResultList(NetlinkList *p_list) +{ + NetlinkList *l_cur; + while(p_list) + { + l_cur = p_list; + p_list = p_list->m_next; + uv__free(l_cur->m_data); + uv__free(l_cur); + } +} + +static NetlinkList *getResultList(int p_socket, int p_request) +{ + int l_size; + int l_done; + NetlinkList *l_list; + NetlinkList *l_end; + + if(netlink_send(p_socket, p_request) < 0) + { + return NULL; + } + + l_list = NULL; + l_end = NULL; + + l_done = 0; + while(!l_done) + { + NetlinkList *l_item; + + struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); + /* Error */ + if(!l_hdr) + { + freeResultList(l_list); + return NULL; + } + + l_item = newListItem(l_hdr, l_size); + if (!l_item) + { + freeResultList(l_list); + return NULL; + } + if(!l_list) + { + l_list = l_item; + } + else + { + l_end->m_next = l_item; + } + l_end = l_item; + } + return l_list; +} + +static size_t maxSize(size_t a, size_t b) +{ + return (a > b ? a : b); +} + +static size_t calcAddrLen(sa_family_t p_family, int p_dataSize) +{ + switch(p_family) + { + case AF_INET: + return sizeof(struct sockaddr_in); + case AF_INET6: + return sizeof(struct sockaddr_in6); + case AF_PACKET: + return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize); + default: + return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize); + } +} + +static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size) +{ + switch(p_family) + { + case AF_INET: + memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size); + break; + case AF_INET6: + memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size); + break; + case AF_PACKET: + memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size); + ((struct sockaddr_ll*)p_dest)->sll_halen = p_size; + break; + default: + memcpy(p_dest->sa_data, p_data, p_size); + break; + } + p_dest->sa_family = p_family; +} + +static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry) +{ + if(!*p_resultList) + { + *p_resultList = p_entry; + } + else + { + struct ifaddrs *l_cur = *p_resultList; + while(l_cur->ifa_next) + { + l_cur = l_cur->ifa_next; + } + l_cur->ifa_next = p_entry; + } +} + +static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList) +{ + struct ifaddrs *l_entry; + + char *l_index; + char *l_name; + char *l_addr; + char *l_data; + + struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr); + + size_t l_nameSize = 0; + size_t l_addrSize = 0; + size_t l_dataSize = 0; + + size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); + struct rtattr *l_rta; + for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + switch(l_rta->rta_type) + { + case IFLA_ADDRESS: + case IFLA_BROADCAST: + l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize)); + break; + case IFLA_IFNAME: + l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); + break; + case IFLA_STATS: + l_dataSize += NLMSG_ALIGN(l_rtaSize); + break; + default: + break; + } + } + + l_entry = uv__malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize); + if (l_entry == NULL) + { + return -1; + } + memset(l_entry, 0, sizeof(struct ifaddrs)); + l_entry->ifa_name = ""; + + l_index = ((char *)l_entry) + sizeof(struct ifaddrs); + l_name = l_index + sizeof(int); + l_addr = l_name + l_nameSize; + l_data = l_addr + l_addrSize; + + /* Save the interface index so we can look it up when handling the + * addresses. + */ + memcpy(l_index, &l_info->ifi_index, sizeof(int)); + + l_entry->ifa_flags = l_info->ifi_flags; + + l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); + for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + void *l_rtaData = RTA_DATA(l_rta); + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + switch(l_rta->rta_type) + { + case IFLA_ADDRESS: + case IFLA_BROADCAST: + { + size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize); + makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); + ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index; + ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type; + if(l_rta->rta_type == IFLA_ADDRESS) + { + l_entry->ifa_addr = (struct sockaddr *)l_addr; + } + else + { + l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; + } + l_addr += NLMSG_ALIGN(l_addrLen); + break; + } + case IFLA_IFNAME: + strncpy(l_name, l_rtaData, l_rtaDataSize); + l_name[l_rtaDataSize] = '\0'; + l_entry->ifa_name = l_name; + break; + case IFLA_STATS: + memcpy(l_data, l_rtaData, l_rtaDataSize); + l_entry->ifa_data = l_data; + break; + default: + break; + } + } + + addToEnd(p_resultList, l_entry); + return 0; +} + +static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks) +{ + int l_num = 0; + struct ifaddrs *l_cur = *p_links; + while(l_cur && l_num < p_numLinks) + { + char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs); + int l_index; + memcpy(&l_index, l_indexPtr, sizeof(int)); + if(l_index == p_index) + { + return l_cur; + } + + l_cur = l_cur->ifa_next; + ++l_num; + } + return NULL; +} + +static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks) +{ + struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr); + struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks); + + size_t l_nameSize = 0; + size_t l_addrSize = 0; + + int l_addedNetmask = 0; + + size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); + struct rtattr *l_rta; + struct ifaddrs *l_entry; + + char *l_name; + char *l_addr; + + for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + if(l_info->ifa_family == AF_PACKET) + { + continue; + } + + switch(l_rta->rta_type) + { + case IFA_ADDRESS: + case IFA_LOCAL: + if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) + { + /* Make room for netmask */ + l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); + l_addedNetmask = 1; + } + case IFA_BROADCAST: + l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); + break; + case IFA_LABEL: + l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); + break; + default: + break; + } + } + + l_entry = uv__malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize); + if (l_entry == NULL) + { + return -1; + } + memset(l_entry, 0, sizeof(struct ifaddrs)); + l_entry->ifa_name = (l_interface ? l_interface->ifa_name : ""); + + l_name = ((char *)l_entry) + sizeof(struct ifaddrs); + l_addr = l_name + l_nameSize; + + l_entry->ifa_flags = l_info->ifa_flags; + if(l_interface) + { + l_entry->ifa_flags |= l_interface->ifa_flags; + } + + l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); + for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + void *l_rtaData = RTA_DATA(l_rta); + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + switch(l_rta->rta_type) + { + case IFA_ADDRESS: + case IFA_BROADCAST: + case IFA_LOCAL: + { + size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize); + makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); + if(l_info->ifa_family == AF_INET6) + { + if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) + { + ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index; + } + } + + /* Apparently in a point-to-point network IFA_ADDRESS contains + * the dest address and IFA_LOCAL contains the local address + */ + if(l_rta->rta_type == IFA_ADDRESS) + { + if(l_entry->ifa_addr) + { + l_entry->ifa_dstaddr = (struct sockaddr *)l_addr; + } + else + { + l_entry->ifa_addr = (struct sockaddr *)l_addr; + } + } + else if(l_rta->rta_type == IFA_LOCAL) + { + if(l_entry->ifa_addr) + { + l_entry->ifa_dstaddr = l_entry->ifa_addr; + } + l_entry->ifa_addr = (struct sockaddr *)l_addr; + } + else + { + l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; + } + l_addr += NLMSG_ALIGN(l_addrLen); + break; + } + case IFA_LABEL: + strncpy(l_name, l_rtaData, l_rtaDataSize); + l_name[l_rtaDataSize] = '\0'; + l_entry->ifa_name = l_name; + break; + default: + break; + } + } + + if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6)) + { + unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128); + unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen); + char l_mask[16] = {0}; + unsigned i; + for(i=0; i<(l_prefix/8); ++i) + { + l_mask[i] = 0xff; + } + if(l_prefix % 8) + { + l_mask[i] = 0xff << (8 - (l_prefix % 8)); + } + + makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8); + l_entry->ifa_netmask = (struct sockaddr *)l_addr; + } + + addToEnd(p_resultList, l_entry); + return 0; +} + +static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList) +{ + + int l_numLinks = 0; + pid_t l_pid = getpid(); + for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) + { + unsigned int l_nlsize = p_netlinkList->m_size; + struct nlmsghdr *l_hdr; + for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) + { + if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + { + continue; + } + + if(l_hdr->nlmsg_type == NLMSG_DONE) + { + break; + } + + if(l_hdr->nlmsg_type == RTM_NEWLINK) + { + if(interpretLink(l_hdr, p_resultList) == -1) + { + return -1; + } + ++l_numLinks; + } + } + } + return l_numLinks; +} + +static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks) +{ + pid_t l_pid = getpid(); + for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) + { + unsigned int l_nlsize = p_netlinkList->m_size; + struct nlmsghdr *l_hdr; + for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) + { + if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + { + continue; + } + + if(l_hdr->nlmsg_type == NLMSG_DONE) + { + break; + } + + if(l_hdr->nlmsg_type == RTM_NEWADDR) + { + if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1) + { + return -1; + } + } + } + } + return 0; +} + +int getifaddrs(struct ifaddrs **ifap) +{ + int l_socket; + int l_result; + int l_numLinks; + NetlinkList *l_linkResults; + NetlinkList *l_addrResults; + + if(!ifap) + { + return -1; + } + *ifap = NULL; + + l_socket = netlink_socket(); + if(l_socket < 0) + { + return -1; + } + + l_linkResults = getResultList(l_socket, RTM_GETLINK); + if(!l_linkResults) + { + close(l_socket); + return -1; + } + + l_addrResults = getResultList(l_socket, RTM_GETADDR); + if(!l_addrResults) + { + close(l_socket); + freeResultList(l_linkResults); + return -1; + } + + l_result = 0; + l_numLinks = interpretLinks(l_socket, l_linkResults, ifap); + if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1) + { + l_result = -1; + } + + freeResultList(l_linkResults); + freeResultList(l_addrResults); + close(l_socket); + return l_result; +} + +void freeifaddrs(struct ifaddrs *ifa) +{ + struct ifaddrs *l_cur; + while(ifa) + { + l_cur = ifa; + ifa = ifa->ifa_next; + uv__free(l_cur); + } +} diff --git a/src/unix/async.c b/src/unix/async.c new file mode 100644 index 0000000..393cdeb --- /dev/null +++ b/src/unix/async.c @@ -0,0 +1,290 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +/* This file contains both the uv__async internal infrastructure and the + * user-facing uv_async_t functions. + */ + +#include "uv.h" +#include "internal.h" +#include "atomic-ops.h" + +#include +#include /* snprintf() */ +#include +#include +#include +#include + +static void uv__async_event(uv_loop_t* loop, + struct uv__async* w, + unsigned int nevents); +static int uv__async_eventfd(void); + + +int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { + int err; + + err = uv__async_start(loop, &loop->async_watcher, uv__async_event); + if (err) + return err; + + uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC); + handle->async_cb = async_cb; + handle->pending = 0; + + QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue); + uv__handle_start(handle); + + return 0; +} + + +int uv_async_send(uv_async_t* handle) { + /* Do a cheap read first. */ + if (ACCESS_ONCE(int, handle->pending) != 0) + return 0; + + if (cmpxchgi(&handle->pending, 0, 1) == 0) + uv__async_send(&handle->loop->async_watcher); + + return 0; +} + + +void uv__async_close(uv_async_t* handle) { + QUEUE_REMOVE(&handle->queue); + uv__handle_stop(handle); +} + + +static void uv__async_event(uv_loop_t* loop, + struct uv__async* w, + unsigned int nevents) { + QUEUE queue; + QUEUE* q; + uv_async_t* h; + + QUEUE_MOVE(&loop->async_handles, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + h = QUEUE_DATA(q, uv_async_t, queue); + + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&loop->async_handles, q); + + if (cmpxchgi(&h->pending, 1, 0) == 0) + continue; + + if (h->async_cb == NULL) + continue; + h->async_cb(h); + } +} + + +static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + struct uv__async* wa; + char buf[1024]; + unsigned n; + ssize_t r; + + n = 0; + for (;;) { + r = read(w->fd, buf, sizeof(buf)); + + if (r > 0) + n += r; + + if (r == sizeof(buf)) + continue; + + if (r != -1) + break; + + if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + + if (errno == EINTR) + continue; + + abort(); + } + + wa = container_of(w, struct uv__async, io_watcher); + +#if defined(__linux__) + if (wa->wfd == -1) { + uint64_t val; + assert(n == sizeof(val)); + memcpy(&val, buf, sizeof(val)); /* Avoid alignment issues. */ + wa->cb(loop, wa, val); + return; + } +#endif + + wa->cb(loop, wa, n); +} + + +void uv__async_send(struct uv__async* wa) { + const void* buf; + ssize_t len; + int fd; + int r; + + buf = ""; + len = 1; + fd = wa->wfd; + +#if defined(__linux__) + if (fd == -1) { + static const uint64_t val = 1; + buf = &val; + len = sizeof(val); + fd = wa->io_watcher.fd; /* eventfd */ + } +#endif + + do + r = write(fd, buf, len); + while (r == -1 && errno == EINTR); + + if (r == len) + return; + + if (r == -1) + if (errno == EAGAIN || errno == EWOULDBLOCK) + return; + + abort(); +} + + +void uv__async_init(struct uv__async* wa) { + wa->io_watcher.fd = -1; + wa->wfd = -1; +} + + +int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) { + int pipefd[2]; + int err; + + if (wa->io_watcher.fd != -1) + return 0; + + err = uv__async_eventfd(); + if (err >= 0) { + pipefd[0] = err; + pipefd[1] = -1; + } + else if (err == -ENOSYS) { + err = uv__make_pipe(pipefd, UV__F_NONBLOCK); +#if defined(__linux__) + /* Save a file descriptor by opening one of the pipe descriptors as + * read/write through the procfs. That file descriptor can then + * function as both ends of the pipe. + */ + if (err == 0) { + char buf[32]; + int fd; + + snprintf(buf, sizeof(buf), "/proc/self/fd/%d", pipefd[0]); + fd = uv__open_cloexec(buf, O_RDWR); + if (fd >= 0) { + uv__close(pipefd[0]); + uv__close(pipefd[1]); + pipefd[0] = fd; + pipefd[1] = fd; + } + } +#endif + } + + if (err < 0) + return err; + + uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]); + uv__io_start(loop, &wa->io_watcher, POLLIN); + wa->wfd = pipefd[1]; + wa->cb = cb; + + return 0; +} + + +void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) { + if (wa->io_watcher.fd == -1) + return; + + if (wa->wfd != -1) { + if (wa->wfd != wa->io_watcher.fd) + uv__close(wa->wfd); + wa->wfd = -1; + } + + uv__io_stop(loop, &wa->io_watcher, POLLIN); + uv__close(wa->io_watcher.fd); + wa->io_watcher.fd = -1; +} + + +static int uv__async_eventfd() { +#if defined(__linux__) + static int no_eventfd2; + static int no_eventfd; + int fd; + + if (no_eventfd2) + goto skip_eventfd2; + + fd = uv__eventfd2(0, UV__EFD_CLOEXEC | UV__EFD_NONBLOCK); + if (fd != -1) + return fd; + + if (errno != ENOSYS) + return -errno; + + no_eventfd2 = 1; + +skip_eventfd2: + + if (no_eventfd) + goto skip_eventfd; + + fd = uv__eventfd(0); + if (fd != -1) { + uv__cloexec(fd, 1); + uv__nonblock(fd, 1); + return fd; + } + + if (errno != ENOSYS) + return -errno; + + no_eventfd = 1; + +skip_eventfd: + +#endif + + return -ENOSYS; +} diff --git a/src/unix/atomic-ops.h b/src/unix/atomic-ops.h new file mode 100644 index 0000000..815e355 --- /dev/null +++ b/src/unix/atomic-ops.h @@ -0,0 +1,88 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef UV_ATOMIC_OPS_H_ +#define UV_ATOMIC_OPS_H_ + +#include "internal.h" /* UV_UNUSED */ + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#include +#define __sync_val_compare_and_swap(p, o, n) atomic_cas_ptr(p, o, n) +#endif + +UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)); +UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)); +UV_UNUSED(static void cpu_relax(void)); + +/* Prefer hand-rolled assembly over the gcc builtins because the latter also + * issue full memory barriers. + */ +UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { +#if defined(__i386__) || defined(__x86_64__) + int out; + __asm__ __volatile__ ("lock; cmpxchg %2, %1;" + : "=a" (out), "+m" (*(volatile int*) ptr) + : "r" (newval), "0" (oldval) + : "memory"); + return out; +#elif defined(_AIX) && defined(__xlC__) + const int out = (*(volatile int*) ptr); + __compare_and_swap(ptr, &oldval, newval); + return out; +#elif defined(__MVS__) + return __plo_CS(ptr, (unsigned int*) ptr, + oldval, (unsigned int*) &newval); +#else + return __sync_val_compare_and_swap(ptr, oldval, newval); +#endif +} + +UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) { +#if defined(__i386__) || defined(__x86_64__) + long out; + __asm__ __volatile__ ("lock; cmpxchg %2, %1;" + : "=a" (out), "+m" (*(volatile long*) ptr) + : "r" (newval), "0" (oldval) + : "memory"); + return out; +#elif defined(_AIX) && defined(__xlC__) + const long out = (*(volatile int*) ptr); +# if defined(__64BIT__) + __compare_and_swaplp(ptr, &oldval, newval); +# else + __compare_and_swap(ptr, &oldval, newval); +# endif /* if defined(__64BIT__) */ + return out; +#elif defined (__MVS__) +# ifdef _LP64 + return __plo_CSGR(ptr, (unsigned long long*) ptr, + oldval, (unsigned long long*) &newval); +# else + return __plo_CS(ptr, (unsigned int*) ptr, + oldval, (unsigned int*) &newval); +# endif +#else + return __sync_val_compare_and_swap(ptr, oldval, newval); +#endif +} + +UV_UNUSED(static void cpu_relax(void)) { +#if defined(__i386__) || defined(__x86_64__) + __asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */ +#endif +} + +#endif /* UV_ATOMIC_OPS_H_ */ diff --git a/src/unix/core.c b/src/unix/core.c new file mode 100644 index 0000000..d88fc1d --- /dev/null +++ b/src/unix/core.c @@ -0,0 +1,1238 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include /* NULL */ +#include /* printf */ +#include +#include /* strerror */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* INT_MAX, PATH_MAX, IOV_MAX */ +#include /* writev */ +#include /* getrusage */ +#include + +#ifdef __sun +# include +# include +# include +#endif + +#ifdef __APPLE__ +# include /* _NSGetExecutablePath */ +# include +# if defined(O_CLOEXEC) +# define UV__O_CLOEXEC O_CLOEXEC +# endif +#endif + +#if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) +# include +# include +# include +# define UV__O_CLOEXEC O_CLOEXEC +# if defined(__FreeBSD__) && __FreeBSD__ >= 10 +# define uv__accept4 accept4 +# define UV__SOCK_NONBLOCK SOCK_NONBLOCK +# define UV__SOCK_CLOEXEC SOCK_CLOEXEC +# endif +# if !defined(F_DUP2FD_CLOEXEC) && defined(_F_DUP2FD_CLOEXEC) +# define F_DUP2FD_CLOEXEC _F_DUP2FD_CLOEXEC +# endif +#endif + +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 +# include /* for dlsym */ +#endif + +#if defined(__MVS__) +#include +#endif + +static int uv__run_pending(uv_loop_t* loop); + +/* Verify that uv_buf_t is ABI-compatible with struct iovec. */ +STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec)); +STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->base) == + sizeof(((struct iovec*) 0)->iov_base)); +STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->len) == + sizeof(((struct iovec*) 0)->iov_len)); +STATIC_ASSERT(offsetof(uv_buf_t, base) == offsetof(struct iovec, iov_base)); +STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len)); + + +uint64_t uv_hrtime(void) { + return uv__hrtime(UV_CLOCK_PRECISE); +} + + +void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + + handle->flags |= UV_CLOSING; + handle->close_cb = close_cb; + + switch (handle->type) { + case UV_NAMED_PIPE: + uv__pipe_close((uv_pipe_t*)handle); + break; + + case UV_TTY: + uv__stream_close((uv_stream_t*)handle); + break; + + case UV_TCP: + uv__tcp_close((uv_tcp_t*)handle); + break; + + case UV_UDP: + uv__udp_close((uv_udp_t*)handle); + break; + + case UV_PREPARE: + uv__prepare_close((uv_prepare_t*)handle); + break; + + case UV_CHECK: + uv__check_close((uv_check_t*)handle); + break; + + case UV_IDLE: + uv__idle_close((uv_idle_t*)handle); + break; + + case UV_ASYNC: + uv__async_close((uv_async_t*)handle); + break; + + case UV_TIMER: + uv__timer_close((uv_timer_t*)handle); + break; + + case UV_PROCESS: + uv__process_close((uv_process_t*)handle); + break; + + case UV_FS_EVENT: + uv__fs_event_close((uv_fs_event_t*)handle); + break; + + case UV_POLL: + uv__poll_close((uv_poll_t*)handle); + break; + + case UV_FS_POLL: + uv__fs_poll_close((uv_fs_poll_t*)handle); + break; + + case UV_SIGNAL: + uv__signal_close((uv_signal_t*) handle); + /* Signal handles may not be closed immediately. The signal code will */ + /* itself close uv__make_close_pending whenever appropriate. */ + return; + + default: + assert(0); + } + + uv__make_close_pending(handle); +} + +int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { + int r; + int fd; + socklen_t len; + + if (handle == NULL || value == NULL) + return -EINVAL; + + if (handle->type == UV_TCP || handle->type == UV_NAMED_PIPE) + fd = uv__stream_fd((uv_stream_t*) handle); + else if (handle->type == UV_UDP) + fd = ((uv_udp_t *) handle)->io_watcher.fd; + else + return -ENOTSUP; + + len = sizeof(*value); + + if (*value == 0) + r = getsockopt(fd, SOL_SOCKET, optname, value, &len); + else + r = setsockopt(fd, SOL_SOCKET, optname, (const void*) value, len); + + if (r < 0) + return -errno; + + return 0; +} + +void uv__make_close_pending(uv_handle_t* handle) { + assert(handle->flags & UV_CLOSING); + assert(!(handle->flags & UV_CLOSED)); + handle->next_closing = handle->loop->closing_handles; + handle->loop->closing_handles = handle; +} + +int uv__getiovmax(void) { +#if defined(IOV_MAX) + return IOV_MAX; +#elif defined(_SC_IOV_MAX) + static int iovmax = -1; + if (iovmax == -1) { + iovmax = sysconf(_SC_IOV_MAX); + /* On some embedded devices (arm-linux-uclibc based ip camera), + * sysconf(_SC_IOV_MAX) can not get the correct value. The return + * value is -1 and the errno is EINPROGRESS. Degrade the value to 1. + */ + if (iovmax == -1) iovmax = 1; + } + return iovmax; +#else + return 1024; +#endif +} + + +static void uv__finish_close(uv_handle_t* handle) { + /* Note: while the handle is in the UV_CLOSING state now, it's still possible + * for it to be active in the sense that uv__is_active() returns true. + * A good example is when the user calls uv_shutdown(), immediately followed + * by uv_close(). The handle is considered active at this point because the + * completion of the shutdown req is still pending. + */ + assert(handle->flags & UV_CLOSING); + assert(!(handle->flags & UV_CLOSED)); + handle->flags |= UV_CLOSED; + + switch (handle->type) { + case UV_PREPARE: + case UV_CHECK: + case UV_IDLE: + case UV_ASYNC: + case UV_TIMER: + case UV_PROCESS: + case UV_FS_EVENT: + case UV_FS_POLL: + case UV_POLL: + case UV_SIGNAL: + break; + + case UV_NAMED_PIPE: + case UV_TCP: + case UV_TTY: + uv__stream_destroy((uv_stream_t*)handle); + break; + + case UV_UDP: + uv__udp_finish_close((uv_udp_t*)handle); + break; + + default: + assert(0); + break; + } + + uv__handle_unref(handle); + QUEUE_REMOVE(&handle->handle_queue); + + if (handle->close_cb) { + handle->close_cb(handle); + } +} + + +static void uv__run_closing_handles(uv_loop_t* loop) { + uv_handle_t* p; + uv_handle_t* q; + + p = loop->closing_handles; + loop->closing_handles = NULL; + + while (p) { + q = p->next_closing; + uv__finish_close(p); + p = q; + } +} + + +int uv_is_closing(const uv_handle_t* handle) { + return uv__is_closing(handle); +} + + +int uv_backend_fd(const uv_loop_t* loop) { + return loop->backend_fd; +} + + +int uv_backend_timeout(const uv_loop_t* loop) { + if (loop->stop_flag != 0) + return 0; + + if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop)) + return 0; + + if (!QUEUE_EMPTY(&loop->idle_handles)) + return 0; + + if (!QUEUE_EMPTY(&loop->pending_queue)) + return 0; + + if (loop->closing_handles) + return 0; + + return uv__next_timeout(loop); +} + + +static int uv__loop_alive(const uv_loop_t* loop) { + return uv__has_active_handles(loop) || + uv__has_active_reqs(loop) || + loop->closing_handles != NULL; +} + + +int uv_loop_alive(const uv_loop_t* loop) { + return uv__loop_alive(loop); +} + + +int uv_run(uv_loop_t* loop, uv_run_mode mode) { + int timeout; + int r; + int ran_pending; + + r = uv__loop_alive(loop); + if (!r) + uv__update_time(loop); + + while (r != 0 && loop->stop_flag == 0) { + uv__update_time(loop); + uv__run_timers(loop); + ran_pending = uv__run_pending(loop); + uv__run_idle(loop); + uv__run_prepare(loop); + + timeout = 0; + if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) + timeout = uv_backend_timeout(loop); + + uv__io_poll(loop, timeout); + uv__run_check(loop); + uv__run_closing_handles(loop); + + if (mode == UV_RUN_ONCE) { + /* UV_RUN_ONCE implies forward progress: at least one callback must have + * been invoked when it returns. uv__io_poll() can return without doing + * I/O (meaning: no callbacks) when its timeout expires - which means we + * have pending timers that satisfy the forward progress constraint. + * + * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from + * the check. + */ + uv__update_time(loop); + uv__run_timers(loop); + } + + r = uv__loop_alive(loop); + if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT) + break; + } + + /* The if statement lets gcc compile it to a conditional store. Avoids + * dirtying a cache line. + */ + if (loop->stop_flag != 0) + loop->stop_flag = 0; + + return r; +} + + +void uv_update_time(uv_loop_t* loop) { + uv__update_time(loop); +} + + +int uv_is_active(const uv_handle_t* handle) { + return uv__is_active(handle); +} + + +/* Open a socket in non-blocking close-on-exec mode, atomically if possible. */ +int uv__socket(int domain, int type, int protocol) { + int sockfd; + int err; + +#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC) + sockfd = socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); + if (sockfd != -1) + return sockfd; + + if (errno != EINVAL) + return -errno; +#endif + + sockfd = socket(domain, type, protocol); + if (sockfd == -1) + return -errno; + + err = uv__nonblock(sockfd, 1); + if (err == 0) + err = uv__cloexec(sockfd, 1); + + if (err) { + uv__close(sockfd); + return err; + } + +#if defined(SO_NOSIGPIPE) + { + int on = 1; + setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on)); + } +#endif + + return sockfd; +} + +/* get a file pointer to a file in read-only and close-on-exec mode */ +FILE* uv__open_file(const char* path) { + int fd; + FILE* fp; + + fd = uv__open_cloexec(path, O_RDONLY); + if (fd < 0) + return NULL; + + fp = fdopen(fd, "r"); + if (fp == NULL) + uv__close(fd); + + return fp; +} + + +int uv__accept(int sockfd) { + int peerfd; + int err; + + assert(sockfd >= 0); + + while (1) { +#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) + static int no_accept4; + + if (no_accept4) + goto skip; + + peerfd = uv__accept4(sockfd, + NULL, + NULL, + UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC); + if (peerfd != -1) + return peerfd; + + if (errno == EINTR) + continue; + + if (errno != ENOSYS) + return -errno; + + no_accept4 = 1; +skip: +#endif + + peerfd = accept(sockfd, NULL, NULL); + if (peerfd == -1) { + if (errno == EINTR) + continue; + return -errno; + } + + err = uv__cloexec(peerfd, 1); + if (err == 0) + err = uv__nonblock(peerfd, 1); + + if (err) { + uv__close(peerfd); + return err; + } + + return peerfd; + } +} + + +int uv__close_nocheckstdio(int fd) { + int saved_errno; + int rc; + + assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */ + + saved_errno = errno; + rc = close(fd); + if (rc == -1) { + rc = -errno; + if (rc == -EINTR || rc == -EINPROGRESS) + rc = 0; /* The close is in progress, not an error. */ + errno = saved_errno; + } + + return rc; +} + + +int uv__close(int fd) { + assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ + return uv__close_nocheckstdio(fd); +} + + +int uv__nonblock_ioctl(int fd, int set) { + int r; + + do + r = ioctl(fd, FIONBIO, &set); + while (r == -1 && errno == EINTR); + + if (r) + return -errno; + + return 0; +} + + +int uv__cloexec_ioctl(int fd, int set) { + int r; + + do + r = ioctl(fd, set ? FIOCLEX : FIONCLEX); + while (r == -1 && errno == EINTR); + + if (r) + return -errno; + + return 0; +} + + +int uv__nonblock_fcntl(int fd, int set) { + int flags; + int r; + + do + r = fcntl(fd, F_GETFL); + while (r == -1 && errno == EINTR); + + if (r == -1) + return -errno; + + /* Bail out now if already set/clear. */ + if (!!(r & O_NONBLOCK) == !!set) + return 0; + + if (set) + flags = r | O_NONBLOCK; + else + flags = r & ~O_NONBLOCK; + + do + r = fcntl(fd, F_SETFL, flags); + while (r == -1 && errno == EINTR); + + if (r) + return -errno; + + return 0; +} + + +int uv__cloexec_fcntl(int fd, int set) { + int flags; + int r; + + do + r = fcntl(fd, F_GETFD); + while (r == -1 && errno == EINTR); + + if (r == -1) + return -errno; + + /* Bail out now if already set/clear. */ + if (!!(r & FD_CLOEXEC) == !!set) + return 0; + + if (set) + flags = r | FD_CLOEXEC; + else + flags = r & ~FD_CLOEXEC; + + do + r = fcntl(fd, F_SETFD, flags); + while (r == -1 && errno == EINTR); + + if (r) + return -errno; + + return 0; +} + + +/* This function is not execve-safe, there is a race window + * between the call to dup() and fcntl(FD_CLOEXEC). + */ +int uv__dup(int fd) { + int err; + + fd = dup(fd); + + if (fd == -1) + return -errno; + + err = uv__cloexec(fd, 1); + if (err) { + uv__close(fd); + return err; + } + + return fd; +} + + +ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { + struct cmsghdr* cmsg; + ssize_t rc; + int* pfd; + int* end; +#if defined(__linux__) + static int no_msg_cmsg_cloexec; + if (no_msg_cmsg_cloexec == 0) { + rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */ + if (rc != -1) + return rc; + if (errno != EINVAL) + return -errno; + rc = recvmsg(fd, msg, flags); + if (rc == -1) + return -errno; + no_msg_cmsg_cloexec = 1; + } else { + rc = recvmsg(fd, msg, flags); + } +#else + rc = recvmsg(fd, msg, flags); +#endif + if (rc == -1) + return -errno; + if (msg->msg_controllen == 0) + return rc; + for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) + if (cmsg->cmsg_type == SCM_RIGHTS) + for (pfd = (int*) CMSG_DATA(cmsg), + end = (int*) ((char*) cmsg + cmsg->cmsg_len); + pfd < end; + pfd += 1) + uv__cloexec(*pfd, 1); + return rc; +} + + +int uv_cwd(char* buffer, size_t* size) { + if (buffer == NULL || size == NULL) + return -EINVAL; + + if (getcwd(buffer, *size) == NULL) + return -errno; + + *size = strlen(buffer); + if (*size > 1 && buffer[*size - 1] == '/') { + buffer[*size-1] = '\0'; + (*size)--; + } + + return 0; +} + + +int uv_chdir(const char* dir) { + if (chdir(dir)) + return -errno; + + return 0; +} + + +void uv_disable_stdio_inheritance(void) { + int fd; + + /* Set the CLOEXEC flag on all open descriptors. Unconditionally try the + * first 16 file descriptors. After that, bail out after the first error. + */ + for (fd = 0; ; fd++) + if (uv__cloexec(fd, 1) && fd > 15) + break; +} + + +int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) { + int fd_out; + + switch (handle->type) { + case UV_TCP: + case UV_NAMED_PIPE: + case UV_TTY: + fd_out = uv__stream_fd((uv_stream_t*) handle); + break; + + case UV_UDP: + fd_out = ((uv_udp_t *) handle)->io_watcher.fd; + break; + + case UV_POLL: + fd_out = ((uv_poll_t *) handle)->io_watcher.fd; + break; + + default: + return -EINVAL; + } + + if (uv__is_closing(handle) || fd_out == -1) + return -EBADF; + + *fd = fd_out; + return 0; +} + + +static int uv__run_pending(uv_loop_t* loop) { + QUEUE* q; + QUEUE pq; + uv__io_t* w; + + if (QUEUE_EMPTY(&loop->pending_queue)) + return 0; + + QUEUE_MOVE(&loop->pending_queue, &pq); + + while (!QUEUE_EMPTY(&pq)) { + q = QUEUE_HEAD(&pq); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + w = QUEUE_DATA(q, uv__io_t, pending_queue); + w->cb(loop, w, POLLOUT); + } + + return 1; +} + + +static unsigned int next_power_of_two(unsigned int val) { + val -= 1; + val |= val >> 1; + val |= val >> 2; + val |= val >> 4; + val |= val >> 8; + val |= val >> 16; + val += 1; + return val; +} + +static void maybe_resize(uv_loop_t* loop, unsigned int len) { + uv__io_t** watchers; + void* fake_watcher_list; + void* fake_watcher_count; + unsigned int nwatchers; + unsigned int i; + + if (len <= loop->nwatchers) + return; + + /* Preserve fake watcher list and count at the end of the watchers */ + if (loop->watchers != NULL) { + fake_watcher_list = loop->watchers[loop->nwatchers]; + fake_watcher_count = loop->watchers[loop->nwatchers + 1]; + } else { + fake_watcher_list = NULL; + fake_watcher_count = NULL; + } + + nwatchers = next_power_of_two(len + 2) - 2; + watchers = uv__realloc(loop->watchers, + (nwatchers + 2) * sizeof(loop->watchers[0])); + + if (watchers == NULL) + abort(); + for (i = loop->nwatchers; i < nwatchers; i++) + watchers[i] = NULL; + watchers[nwatchers] = fake_watcher_list; + watchers[nwatchers + 1] = fake_watcher_count; + + loop->watchers = watchers; + loop->nwatchers = nwatchers; +} + + +void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { + assert(cb != NULL); + assert(fd >= -1); + QUEUE_INIT(&w->pending_queue); + QUEUE_INIT(&w->watcher_queue); + w->cb = cb; + w->fd = fd; + w->events = 0; + w->pevents = 0; + +#if defined(UV_HAVE_KQUEUE) + w->rcount = 0; + w->wcount = 0; +#endif /* defined(UV_HAVE_KQUEUE) */ +} + + +void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); + assert(0 != events); + assert(w->fd >= 0); + assert(w->fd < INT_MAX); + + w->pevents |= events; + maybe_resize(loop, w->fd + 1); + +#if !defined(__sun) + /* The event ports backend needs to rearm all file descriptors on each and + * every tick of the event loop but the other backends allow us to + * short-circuit here if the event mask is unchanged. + */ + if (w->events == w->pevents) { + if (w->events == 0 && !QUEUE_EMPTY(&w->watcher_queue)) { + QUEUE_REMOVE(&w->watcher_queue); + QUEUE_INIT(&w->watcher_queue); + } + return; + } +#endif + + if (QUEUE_EMPTY(&w->watcher_queue)) + QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); + + if (loop->watchers[w->fd] == NULL) { + loop->watchers[w->fd] = w; + loop->nfds++; + } +} + + +void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); + assert(0 != events); + + if (w->fd == -1) + return; + + assert(w->fd >= 0); + + /* Happens when uv__io_stop() is called on a handle that was never started. */ + if ((unsigned) w->fd >= loop->nwatchers) + return; + + w->pevents &= ~events; + + if (w->pevents == 0) { + QUEUE_REMOVE(&w->watcher_queue); + QUEUE_INIT(&w->watcher_queue); + + if (loop->watchers[w->fd] != NULL) { + assert(loop->watchers[w->fd] == w); + assert(loop->nfds > 0); + loop->watchers[w->fd] = NULL; + loop->nfds--; + w->events = 0; + } + } + else if (QUEUE_EMPTY(&w->watcher_queue)) + QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); +} + + +void uv__io_close(uv_loop_t* loop, uv__io_t* w) { + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); + QUEUE_REMOVE(&w->pending_queue); + + /* Remove stale events for this file descriptor */ + uv__platform_invalidate_fd(loop, w->fd); +} + + +void uv__io_feed(uv_loop_t* loop, uv__io_t* w) { + if (QUEUE_EMPTY(&w->pending_queue)) + QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue); +} + + +int uv__io_active(const uv__io_t* w, unsigned int events) { + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); + assert(0 != events); + return 0 != (w->pevents & events); +} + + +int uv_getrusage(uv_rusage_t* rusage) { + struct rusage usage; + + if (getrusage(RUSAGE_SELF, &usage)) + return -errno; + + rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec; + rusage->ru_utime.tv_usec = usage.ru_utime.tv_usec; + + rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec; + rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec; + +#if !defined(__MVS__) + rusage->ru_maxrss = usage.ru_maxrss; + rusage->ru_ixrss = usage.ru_ixrss; + rusage->ru_idrss = usage.ru_idrss; + rusage->ru_isrss = usage.ru_isrss; + rusage->ru_minflt = usage.ru_minflt; + rusage->ru_majflt = usage.ru_majflt; + rusage->ru_nswap = usage.ru_nswap; + rusage->ru_inblock = usage.ru_inblock; + rusage->ru_oublock = usage.ru_oublock; + rusage->ru_msgsnd = usage.ru_msgsnd; + rusage->ru_msgrcv = usage.ru_msgrcv; + rusage->ru_nsignals = usage.ru_nsignals; + rusage->ru_nvcsw = usage.ru_nvcsw; + rusage->ru_nivcsw = usage.ru_nivcsw; +#endif + + return 0; +} + + +int uv__open_cloexec(const char* path, int flags) { + int err; + int fd; + +#if defined(UV__O_CLOEXEC) + static int no_cloexec; + + if (!no_cloexec) { + fd = open(path, flags | UV__O_CLOEXEC); + if (fd != -1) + return fd; + + if (errno != EINVAL) + return -errno; + + /* O_CLOEXEC not supported. */ + no_cloexec = 1; + } +#endif + + fd = open(path, flags); + if (fd == -1) + return -errno; + + err = uv__cloexec(fd, 1); + if (err) { + uv__close(fd); + return err; + } + + return fd; +} + + +int uv__dup2_cloexec(int oldfd, int newfd) { + int r; +#if defined(__FreeBSD__) && __FreeBSD__ >= 10 + r = dup3(oldfd, newfd, O_CLOEXEC); + if (r == -1) + return -errno; + return r; +#elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC) + r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd); + if (r != -1) + return r; + if (errno != EINVAL) + return -errno; + /* Fall through. */ +#elif defined(__linux__) + static int no_dup3; + if (!no_dup3) { + do + r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC); + while (r == -1 && errno == EBUSY); + if (r != -1) + return r; + if (errno != ENOSYS) + return -errno; + /* Fall through. */ + no_dup3 = 1; + } +#endif + { + int err; + do + r = dup2(oldfd, newfd); +#if defined(__linux__) + while (r == -1 && errno == EBUSY); +#else + while (0); /* Never retry. */ +#endif + + if (r == -1) + return -errno; + + err = uv__cloexec(newfd, 1); + if (err) { + uv__close(newfd); + return err; + } + + return r; + } +} + + +int uv_os_homedir(char* buffer, size_t* size) { + uv_passwd_t pwd; + char* buf; + size_t len; + int r; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + /* Check if the HOME environment variable is set first */ + buf = getenv("HOME"); + + if (buf != NULL) { + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return -ENOBUFS; + } + + memcpy(buffer, buf, len + 1); + *size = len; + + return 0; + } + + /* HOME is not set, so call uv__getpwuid_r() */ + r = uv__getpwuid_r(&pwd); + + if (r != 0) { + return r; + } + + len = strlen(pwd.homedir); + + if (len >= *size) { + *size = len + 1; + uv_os_free_passwd(&pwd); + return -ENOBUFS; + } + + memcpy(buffer, pwd.homedir, len + 1); + *size = len; + uv_os_free_passwd(&pwd); + + return 0; +} + + +int uv_os_tmpdir(char* buffer, size_t* size) { + const char* buf; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + +#define CHECK_ENV_VAR(name) \ + do { \ + buf = getenv(name); \ + if (buf != NULL) \ + goto return_buffer; \ + } \ + while (0) + + /* Check the TMPDIR, TMP, TEMP, and TEMPDIR environment variables in order */ + CHECK_ENV_VAR("TMPDIR"); + CHECK_ENV_VAR("TMP"); + CHECK_ENV_VAR("TEMP"); + CHECK_ENV_VAR("TEMPDIR"); + +#undef CHECK_ENV_VAR + + /* No temp environment variables defined */ + #if defined(__ANDROID__) + buf = "/data/local/tmp"; + #else + buf = "/tmp"; + #endif + +return_buffer: + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return -ENOBUFS; + } + + /* The returned directory should not have a trailing slash. */ + if (len > 1 && buf[len - 1] == '/') { + len--; + } + + memcpy(buffer, buf, len + 1); + buffer[len] = '\0'; + *size = len; + + return 0; +} + + +int uv__getpwuid_r(uv_passwd_t* pwd) { + struct passwd pw; + struct passwd* result; + char* buf; + uid_t uid; + size_t bufsize; + size_t name_size; + size_t homedir_size; + size_t shell_size; + long initsize; + int r; +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); + + getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); + if (getpwuid_r == NULL) + return -ENOSYS; +#endif + + if (pwd == NULL) + return -EINVAL; + + initsize = sysconf(_SC_GETPW_R_SIZE_MAX); + + if (initsize <= 0) + bufsize = 4096; + else + bufsize = (size_t) initsize; + + uid = geteuid(); + buf = NULL; + + for (;;) { + uv__free(buf); + buf = uv__malloc(bufsize); + + if (buf == NULL) + return -ENOMEM; + + r = getpwuid_r(uid, &pw, buf, bufsize, &result); + + if (r != ERANGE) + break; + + bufsize *= 2; + } + + if (r != 0) { + uv__free(buf); + return -r; + } + + if (result == NULL) { + uv__free(buf); + return -ENOENT; + } + + /* Allocate memory for the username, shell, and home directory */ + name_size = strlen(pw.pw_name) + 1; + homedir_size = strlen(pw.pw_dir) + 1; + shell_size = strlen(pw.pw_shell) + 1; + pwd->username = uv__malloc(name_size + homedir_size + shell_size); + + if (pwd->username == NULL) { + uv__free(buf); + return -ENOMEM; + } + + /* Copy the username */ + memcpy(pwd->username, pw.pw_name, name_size); + + /* Copy the home directory */ + pwd->homedir = pwd->username + name_size; + memcpy(pwd->homedir, pw.pw_dir, homedir_size); + + /* Copy the shell */ + pwd->shell = pwd->homedir + homedir_size; + memcpy(pwd->shell, pw.pw_shell, shell_size); + + /* Copy the uid and gid */ + pwd->uid = pw.pw_uid; + pwd->gid = pw.pw_gid; + + uv__free(buf); + + return 0; +} + + +void uv_os_free_passwd(uv_passwd_t* pwd) { + if (pwd == NULL) + return; + + /* + The memory for name, shell, and homedir are allocated in a single + uv__malloc() call. The base of the pointer is stored in pwd->username, so + that is the field that needs to be freed. + */ + uv__free(pwd->username); + pwd->username = NULL; + pwd->shell = NULL; + pwd->homedir = NULL; +} + + +int uv_os_get_passwd(uv_passwd_t* pwd) { + return uv__getpwuid_r(pwd); +} diff --git a/src/unix/darwin-proctitle.c b/src/unix/darwin-proctitle.c new file mode 100644 index 0000000..1142311 --- /dev/null +++ b/src/unix/darwin-proctitle.c @@ -0,0 +1,206 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include +#include +#include +#include + +#include + +#if !TARGET_OS_IPHONE +# include +# include +#endif + + +static int uv__pthread_setname_np(const char* name) { + int (*dynamic_pthread_setname_np)(const char* name); + char namebuf[64]; /* MAXTHREADNAMESIZE */ + int err; + + /* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */ + *(void **)(&dynamic_pthread_setname_np) = + dlsym(RTLD_DEFAULT, "pthread_setname_np"); + + if (dynamic_pthread_setname_np == NULL) + return -ENOSYS; + + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + + err = dynamic_pthread_setname_np(namebuf); + if (err) + return -err; + + return 0; +} + + +int uv__set_process_title(const char* title) { +#if TARGET_OS_IPHONE + return uv__pthread_setname_np(title); +#else + CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef, + const char*, + CFStringEncoding); + CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef); + void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef); + void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef); + CFTypeRef (*pLSGetCurrentApplicationASN)(void); + OSStatus (*pLSSetApplicationInformationItem)(int, + CFTypeRef, + CFStringRef, + CFStringRef, + CFDictionaryRef*); + void* application_services_handle; + void* core_foundation_handle; + CFBundleRef launch_services_bundle; + CFStringRef* display_name_key; + CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef); + CFBundleRef (*pCFBundleGetMainBundle)(void); + CFBundleRef hi_services_bundle; + OSStatus (*pSetApplicationIsDaemon)(int); + CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef); + void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t, + void*); + CFTypeRef asn; + int err; + + err = -ENOENT; + application_services_handle = dlopen("/System/Library/Frameworks/" + "ApplicationServices.framework/" + "Versions/A/ApplicationServices", + RTLD_LAZY | RTLD_LOCAL); + core_foundation_handle = dlopen("/System/Library/Frameworks/" + "CoreFoundation.framework/" + "Versions/A/CoreFoundation", + RTLD_LAZY | RTLD_LOCAL); + + if (application_services_handle == NULL || core_foundation_handle == NULL) + goto out; + + *(void **)(&pCFStringCreateWithCString) = + dlsym(core_foundation_handle, "CFStringCreateWithCString"); + *(void **)(&pCFBundleGetBundleWithIdentifier) = + dlsym(core_foundation_handle, "CFBundleGetBundleWithIdentifier"); + *(void **)(&pCFBundleGetDataPointerForName) = + dlsym(core_foundation_handle, "CFBundleGetDataPointerForName"); + *(void **)(&pCFBundleGetFunctionPointerForName) = + dlsym(core_foundation_handle, "CFBundleGetFunctionPointerForName"); + + if (pCFStringCreateWithCString == NULL || + pCFBundleGetBundleWithIdentifier == NULL || + pCFBundleGetDataPointerForName == NULL || + pCFBundleGetFunctionPointerForName == NULL) { + goto out; + } + +#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8) + + launch_services_bundle = + pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices")); + + if (launch_services_bundle == NULL) + goto out; + + *(void **)(&pLSGetCurrentApplicationASN) = + pCFBundleGetFunctionPointerForName(launch_services_bundle, + S("_LSGetCurrentApplicationASN")); + + if (pLSGetCurrentApplicationASN == NULL) + goto out; + + *(void **)(&pLSSetApplicationInformationItem) = + pCFBundleGetFunctionPointerForName(launch_services_bundle, + S("_LSSetApplicationInformationItem")); + + if (pLSSetApplicationInformationItem == NULL) + goto out; + + display_name_key = pCFBundleGetDataPointerForName(launch_services_bundle, + S("_kLSDisplayNameKey")); + + if (display_name_key == NULL || *display_name_key == NULL) + goto out; + + *(void **)(&pCFBundleGetInfoDictionary) = dlsym(core_foundation_handle, + "CFBundleGetInfoDictionary"); + *(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle, + "CFBundleGetMainBundle"); + if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL) + goto out; + + /* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */ + hi_services_bundle = + pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices")); + err = -ENOENT; + if (hi_services_bundle == NULL) + goto out; + + *(void **)(&pSetApplicationIsDaemon) = pCFBundleGetFunctionPointerForName( + hi_services_bundle, + S("SetApplicationIsDaemon")); + *(void **)(&pLSApplicationCheckIn) = pCFBundleGetFunctionPointerForName( + launch_services_bundle, + S("_LSApplicationCheckIn")); + *(void **)(&pLSSetApplicationLaunchServicesServerConnectionStatus) = + pCFBundleGetFunctionPointerForName( + launch_services_bundle, + S("_LSSetApplicationLaunchServicesServerConnectionStatus")); + if (pSetApplicationIsDaemon == NULL || + pLSApplicationCheckIn == NULL || + pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) { + goto out; + } + + if (pSetApplicationIsDaemon(1) != noErr) + goto out; + + pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL); + + /* Check into process manager?! */ + pLSApplicationCheckIn(-2, + pCFBundleGetInfoDictionary(pCFBundleGetMainBundle())); + + asn = pLSGetCurrentApplicationASN(); + + err = -EINVAL; + if (pLSSetApplicationInformationItem(-2, /* Magic value. */ + asn, + *display_name_key, + S(title), + NULL) != noErr) { + goto out; + } + + uv__pthread_setname_np(title); /* Don't care if it fails. */ + err = 0; + +out: + if (core_foundation_handle != NULL) + dlclose(core_foundation_handle); + + if (application_services_handle != NULL) + dlclose(application_services_handle); + + return err; +#endif /* !TARGET_OS_IPHONE */ +} diff --git a/src/unix/darwin.c b/src/unix/darwin.c new file mode 100644 index 0000000..cf95da2 --- /dev/null +++ b/src/unix/darwin.c @@ -0,0 +1,335 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include /* _NSGetExecutablePath */ +#include +#include +#include /* sysconf */ + + +int uv__platform_loop_init(uv_loop_t* loop) { + loop->cf_state = NULL; + + if (uv__kqueue_init(loop)) + return -errno; + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + uv__fsevents_loop_delete(loop); +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + static mach_timebase_info_data_t info; + + if ((ACCESS_ONCE(uint32_t, info.numer) == 0 || + ACCESS_ONCE(uint32_t, info.denom) == 0) && + mach_timebase_info(&info) != KERN_SUCCESS) + abort(); + + return mach_absolute_time() * info.numer / info.denom; +} + + +int uv_exepath(char* buffer, size_t* size) { + /* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */ + char abspath[PATH_MAX * 2 + 1]; + char exepath[PATH_MAX + 1]; + uint32_t exepath_size; + size_t abspath_size; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + exepath_size = sizeof(exepath); + if (_NSGetExecutablePath(exepath, &exepath_size)) + return -EIO; + + if (realpath(exepath, abspath) != abspath) + return -errno; + + abspath_size = strlen(abspath); + if (abspath_size == 0) + return -EIO; + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + return 0; +} + + +uint64_t uv_get_free_memory(void) { + vm_statistics_data_t info; + mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t); + + if (host_statistics(mach_host_self(), HOST_VM_INFO, + (host_info_t)&info, &count) != KERN_SUCCESS) { + return -EINVAL; /* FIXME(bnoordhuis) Translate error. */ + } + + return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE); +} + + +uint64_t uv_get_total_memory(void) { + uint64_t info; + int which[] = {CTL_HW, HW_MEMSIZE}; + size_t size = sizeof(info); + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info; +} + + +void uv_loadavg(double avg[3]) { + struct loadavg info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_LOADAVG}; + + if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return; + + avg[0] = (double) info.ldavg[0] / info.fscale; + avg[1] = (double) info.ldavg[1] / info.fscale; + avg[2] = (double) info.ldavg[2] / info.fscale; +} + + +int uv_resident_set_memory(size_t* rss) { + mach_msg_type_number_t count; + task_basic_info_data_t info; + kern_return_t err; + + count = TASK_BASIC_INFO_COUNT; + err = task_info(mach_task_self(), + TASK_BASIC_INFO, + (task_info_t) &info, + &count); + (void) &err; + /* task_info(TASK_BASIC_INFO) cannot really fail. Anything other than + * KERN_SUCCESS implies a libuv bug. + */ + assert(err == KERN_SUCCESS); + *rss = info.resident_size; + + return 0; +} + + +int uv_uptime(double* uptime) { + time_t now; + struct timeval info; + size_t size = sizeof(info); + static int which[] = {CTL_KERN, KERN_BOOTTIME}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + now = time(NULL); + *uptime = now - info.tv_sec; + + return 0; +} + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), + multiplier = ((uint64_t)1000L / ticks); + char model[512]; + uint64_t cpuspeed; + size_t size; + unsigned int i; + natural_t numcpus; + mach_msg_type_number_t msg_type; + processor_cpu_load_info_data_t *info; + uv_cpu_info_t* cpu_info; + + size = sizeof(model); + if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) && + sysctlbyname("hw.model", &model, &size, NULL, 0)) { + return -errno; + } + + size = sizeof(cpuspeed); + if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0)) + return -errno; + + if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus, + (processor_info_array_t*)&info, + &msg_type) != KERN_SUCCESS) { + return -EINVAL; /* FIXME(bnoordhuis) Translate error. */ + } + + *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) { + vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type); + return -ENOMEM; + } + + *count = numcpus; + + for (i = 0; i < numcpus; i++) { + cpu_info = &(*cpu_infos)[i]; + + cpu_info->cpu_times.user = (uint64_t)(info[i].cpu_ticks[0]) * multiplier; + cpu_info->cpu_times.nice = (uint64_t)(info[i].cpu_ticks[3]) * multiplier; + cpu_info->cpu_times.sys = (uint64_t)(info[i].cpu_ticks[1]) * multiplier; + cpu_info->cpu_times.idle = (uint64_t)(info[i].cpu_ticks[2]) * multiplier; + cpu_info->cpu_times.irq = 0; + + cpu_info->model = uv__strdup(model); + cpu_info->speed = cpuspeed/1000000; + } + vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type); + + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family == AF_LINK)) { + continue; + } + + (*count)++; + } + + *addresses = uv__malloc(*count * sizeof(**addresses)); + if (!(*addresses)) { + freeifaddrs(addrs); + return -ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + /* + * On Mac OS X getifaddrs returns information related to Mac Addresses for + * various devices, such as firewire, etc. These are not relevant here. + */ + if (ent->ifa_addr->sa_family == AF_LINK) + continue; + + address->name = uv__strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(addresses[i].name); + } + + uv__free(addresses); +} diff --git a/src/unix/dl.c b/src/unix/dl.c new file mode 100644 index 0000000..fc1c052 --- /dev/null +++ b/src/unix/dl.c @@ -0,0 +1,80 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include + +static int uv__dlerror(uv_lib_t* lib); + + +int uv_dlopen(const char* filename, uv_lib_t* lib) { + dlerror(); /* Reset error status. */ + lib->errmsg = NULL; + lib->handle = dlopen(filename, RTLD_LAZY); + return lib->handle ? 0 : uv__dlerror(lib); +} + + +void uv_dlclose(uv_lib_t* lib) { + uv__free(lib->errmsg); + lib->errmsg = NULL; + + if (lib->handle) { + /* Ignore errors. No good way to signal them without leaking memory. */ + dlclose(lib->handle); + lib->handle = NULL; + } +} + + +int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) { + dlerror(); /* Reset error status. */ + *ptr = dlsym(lib->handle, name); + return uv__dlerror(lib); +} + + +const char* uv_dlerror(const uv_lib_t* lib) { + return lib->errmsg ? lib->errmsg : "no error"; +} + + +static int uv__dlerror(uv_lib_t* lib) { + const char* errmsg; + + uv__free(lib->errmsg); + + errmsg = dlerror(); + + if (errmsg) { + lib->errmsg = uv__strdup(errmsg); + return -1; + } + else { + lib->errmsg = NULL; + return 0; + } +} diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c new file mode 100644 index 0000000..cba44a3 --- /dev/null +++ b/src/unix/freebsd.c @@ -0,0 +1,460 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include /* VM_LOADAVG */ +#include +#include +#include /* sysconf */ +#include + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + +#ifndef CPUSTATES +# define CPUSTATES 5U +#endif +#ifndef CP_USER +# define CP_USER 0 +# define CP_NICE 1 +# define CP_SYS 2 +# define CP_IDLE 3 +# define CP_INTR 4 +#endif + +static char *process_title; + + +int uv__platform_loop_init(uv_loop_t* loop) { + return uv__kqueue_init(loop); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); +} + + +#ifdef __DragonFly__ +int uv_exepath(char* buffer, size_t* size) { + char abspath[PATH_MAX * 2 + 1]; + ssize_t abspath_size; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath)); + if (abspath_size < 0) + return -errno; + + assert(abspath_size > 0); + *size -= 1; + + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + return 0; +} +#else +int uv_exepath(char* buffer, size_t* size) { + char abspath[PATH_MAX * 2 + 1]; + int mib[4]; + size_t abspath_size; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + + abspath_size = sizeof abspath; + if (sysctl(mib, 4, abspath, &abspath_size, NULL, 0)) + return -errno; + + assert(abspath_size > 0); + abspath_size -= 1; + *size -= 1; + + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + return 0; +} +#endif + +uint64_t uv_get_free_memory(void) { + int freecount; + size_t size = sizeof(freecount); + + if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0)) + return -errno; + + return (uint64_t) freecount * sysconf(_SC_PAGESIZE); + +} + + +uint64_t uv_get_total_memory(void) { + unsigned long info; + int which[] = {CTL_HW, HW_PHYSMEM}; + + size_t size = sizeof(info); + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info; +} + + +void uv_loadavg(double avg[3]) { + struct loadavg info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_LOADAVG}; + + if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return; + + avg[0] = (double) info.ldavg[0] / info.fscale; + avg[1] = (double) info.ldavg[1] / info.fscale; + avg[2] = (double) info.ldavg[2] / info.fscale; +} + + +char** uv_setup_args(int argc, char** argv) { + process_title = argc ? uv__strdup(argv[0]) : NULL; + return argv; +} + + +int uv_set_process_title(const char* title) { + int oid[4]; + + uv__free(process_title); + process_title = uv__strdup(title); + + oid[0] = CTL_KERN; + oid[1] = KERN_PROC; + oid[2] = KERN_PROC_ARGS; + oid[3] = getpid(); + + sysctl(oid, + ARRAY_SIZE(oid), + NULL, + NULL, + process_title, + strlen(process_title) + 1); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return -EINVAL; + + if (process_title) { + len = strlen(process_title) + 1; + + if (size < len) + return -ENOBUFS; + + memcpy(buffer, process_title, len); + } else { + len = 0; + } + + buffer[len] = '\0'; + + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + kvm_t *kd = NULL; + struct kinfo_proc *kinfo = NULL; + pid_t pid; + int nprocs; + size_t page_size = getpagesize(); + + pid = getpid(); + + kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); + if (kd == NULL) goto error; + + kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs); + if (kinfo == NULL) goto error; + +#ifdef __DragonFly__ + *rss = kinfo->kp_vm_rssize * page_size; +#else + *rss = kinfo->ki_rssize * page_size; +#endif + + kvm_close(kd); + + return 0; + +error: + if (kd) kvm_close(kd); + return -EPERM; +} + + +int uv_uptime(double* uptime) { + int r; + struct timespec sp; + r = clock_gettime(CLOCK_MONOTONIC, &sp); + if (r) + return -errno; + + *uptime = sp.tv_sec; + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), + multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus, + cur = 0; + uv_cpu_info_t* cpu_info; + const char* maxcpus_key; + const char* cptimes_key; + char model[512]; + long* cp_times; + int numcpus; + size_t size; + int i; + +#if defined(__DragonFly__) + /* This is not quite correct but DragonFlyBSD doesn't seem to have anything + * comparable to kern.smp.maxcpus or kern.cp_times (kern.cp_time is a total, + * not per CPU). At least this stops uv_cpu_info() from failing completely. + */ + maxcpus_key = "hw.ncpu"; + cptimes_key = "kern.cp_time"; +#else + maxcpus_key = "kern.smp.maxcpus"; + cptimes_key = "kern.cp_times"; +#endif + + size = sizeof(model); + if (sysctlbyname("hw.model", &model, &size, NULL, 0)) + return -errno; + + size = sizeof(numcpus); + if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) + return -errno; + + *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) + return -ENOMEM; + + *count = numcpus; + + size = sizeof(cpuspeed); + if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) { + uv__free(*cpu_infos); + return -errno; + } + + /* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of + * ncpu. + */ + size = sizeof(maxcpus); + if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) { + uv__free(*cpu_infos); + return -errno; + } + + size = maxcpus * CPUSTATES * sizeof(long); + + cp_times = uv__malloc(size); + if (cp_times == NULL) { + uv__free(*cpu_infos); + return -ENOMEM; + } + + if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) { + uv__free(cp_times); + uv__free(*cpu_infos); + return -errno; + } + + for (i = 0; i < numcpus; i++) { + cpu_info = &(*cpu_infos)[i]; + + cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier; + cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier; + cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier; + cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier; + cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier; + + cpu_info->model = uv__strdup(model); + cpu_info->speed = cpuspeed; + + cur+=CPUSTATES; + } + + uv__free(cp_times); + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family == AF_LINK)) { + continue; + } + + (*count)++; + } + + *addresses = uv__malloc(*count * sizeof(**addresses)); + if (!(*addresses)) { + freeifaddrs(addrs); + return -ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + /* + * On FreeBSD getifaddrs returns information related to the raw underlying + * devices. We're not interested in this information yet. + */ + if (ent->ifa_addr->sa_family == AF_LINK) + continue; + + address->name = uv__strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(addresses[i].name); + } + + uv__free(addresses); +} diff --git a/src/unix/fs.c b/src/unix/fs.c new file mode 100644 index 0000000..216ef97 --- /dev/null +++ b/src/unix/fs.c @@ -0,0 +1,1355 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +/* Caveat emptor: this file deviates from the libuv convention of returning + * negated errno codes. Most uv_fs_*() functions map directly to the system + * call of the same name. For more complex wrappers, it's easier to just + * return -1 with errno set. The dispatcher in uv__fs_work() takes care of + * getting the errno to the right place (req->result or as the return value.) + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include /* PATH_MAX */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel_) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# define HAVE_PREADV 1 +#else +# define HAVE_PREADV 0 +#endif + +#if defined(__linux__) || defined(__sun) +# include +#endif + +#define INIT(subtype) \ + do { \ + req->type = UV_FS; \ + if (cb != NULL) \ + uv__req_init(loop, req, UV_FS); \ + req->fs_type = UV_FS_ ## subtype; \ + req->result = 0; \ + req->ptr = NULL; \ + req->loop = loop; \ + req->path = NULL; \ + req->new_path = NULL; \ + req->cb = cb; \ + } \ + while (0) + +#define PATH \ + do { \ + assert(path != NULL); \ + if (cb == NULL) { \ + req->path = path; \ + } else { \ + req->path = uv__strdup(path); \ + if (req->path == NULL) { \ + uv__req_unregister(loop, req); \ + return -ENOMEM; \ + } \ + } \ + } \ + while (0) + +#define PATH2 \ + do { \ + if (cb == NULL) { \ + req->path = path; \ + req->new_path = new_path; \ + } else { \ + size_t path_len; \ + size_t new_path_len; \ + path_len = strlen(path) + 1; \ + new_path_len = strlen(new_path) + 1; \ + req->path = uv__malloc(path_len + new_path_len); \ + if (req->path == NULL) { \ + uv__req_unregister(loop, req); \ + return -ENOMEM; \ + } \ + req->new_path = req->path + path_len; \ + memcpy((void*) req->path, path, path_len); \ + memcpy((void*) req->new_path, new_path, new_path_len); \ + } \ + } \ + while (0) + +#define POST \ + do { \ + if (cb != NULL) { \ + uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \ + return 0; \ + } \ + else { \ + uv__fs_work(&req->work_req); \ + return req->result; \ + } \ + } \ + while (0) + + +static ssize_t uv__fs_fdatasync(uv_fs_t* req) { +#if defined(__linux__) || defined(__sun) || defined(__NetBSD__) + return fdatasync(req->file); +#elif defined(__APPLE__) && defined(SYS_fdatasync) + return syscall(SYS_fdatasync, req->file); +#else + return fsync(req->file); +#endif +} + + +static ssize_t uv__fs_futime(uv_fs_t* req) { +#if defined(__linux__) + /* utimesat() has nanosecond resolution but we stick to microseconds + * for the sake of consistency with other platforms. + */ + static int no_utimesat; + struct timespec ts[2]; + struct timeval tv[2]; + char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)]; + int r; + + if (no_utimesat) + goto skip; + + ts[0].tv_sec = req->atime; + ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; + ts[1].tv_sec = req->mtime; + ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; + + r = uv__utimesat(req->file, NULL, ts, 0); + if (r == 0) + return r; + + if (errno != ENOSYS) + return r; + + no_utimesat = 1; + +skip: + + tv[0].tv_sec = req->atime; + tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; + tv[1].tv_sec = req->mtime; + tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; + snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file); + + r = utimes(path, tv); + if (r == 0) + return r; + + switch (errno) { + case ENOENT: + if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF) + break; + /* Fall through. */ + + case EACCES: + case ENOTDIR: + errno = ENOSYS; + break; + } + + return r; + +#elif defined(__APPLE__) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__FreeBSD_kernel__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__sun) + struct timeval tv[2]; + tv[0].tv_sec = req->atime; + tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; + tv[1].tv_sec = req->mtime; + tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; +# if defined(__sun) + return futimesat(req->file, NULL, tv); +# else + return futimes(req->file, tv); +# endif +#elif defined(_AIX71) + struct timespec ts[2]; + ts[0].tv_sec = req->atime; + ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; + ts[1].tv_sec = req->mtime; + ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; + return futimens(req->file, ts); +#elif defined(__MVS__) + attrib_t atr; + memset(&atr, 0, sizeof(atr)); + atr.att_mtimechg = 1; + atr.att_atimechg = 1; + atr.att_mtime = req->mtime; + atr.att_atime = req->atime; + return __fchattr(req->file, &atr, sizeof(atr)); +#else + errno = ENOSYS; + return -1; +#endif +} + + +static ssize_t uv__fs_mkdtemp(uv_fs_t* req) { + return mkdtemp((char*) req->path) ? 0 : -1; +} + + +static ssize_t uv__fs_open(uv_fs_t* req) { + static int no_cloexec_support; + int r; + + /* Try O_CLOEXEC before entering locks */ + if (no_cloexec_support == 0) { +#ifdef O_CLOEXEC + r = open(req->path, req->flags | O_CLOEXEC, req->mode); + if (r >= 0) + return r; + if (errno != EINVAL) + return r; + no_cloexec_support = 1; +#endif /* O_CLOEXEC */ + } + + if (req->cb != NULL) + uv_rwlock_rdlock(&req->loop->cloexec_lock); + + r = open(req->path, req->flags, req->mode); + + /* In case of failure `uv__cloexec` will leave error in `errno`, + * so it is enough to just set `r` to `-1`. + */ + if (r >= 0 && uv__cloexec(r, 1) != 0) { + r = uv__close(r); + if (r != 0) + abort(); + r = -1; + } + + if (req->cb != NULL) + uv_rwlock_rdunlock(&req->loop->cloexec_lock); + + return r; +} + + +static ssize_t uv__fs_read(uv_fs_t* req) { +#if defined(__linux__) + static int no_preadv; +#endif + ssize_t result; + +#if defined(_AIX) + struct stat buf; + if(fstat(req->file, &buf)) + return -1; + if(S_ISDIR(buf.st_mode)) { + errno = EISDIR; + return -1; + } +#endif /* defined(_AIX) */ + if (req->off < 0) { + if (req->nbufs == 1) + result = read(req->file, req->bufs[0].base, req->bufs[0].len); + else + result = readv(req->file, (struct iovec*) req->bufs, req->nbufs); + } else { + if (req->nbufs == 1) { + result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off); + goto done; + } + +#if HAVE_PREADV + result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); +#else +# if defined(__linux__) + if (no_preadv) retry: +# endif + { + off_t nread; + size_t index; + + nread = 0; + index = 0; + result = 1; + do { + if (req->bufs[index].len > 0) { + result = pread(req->file, + req->bufs[index].base, + req->bufs[index].len, + req->off + nread); + if (result > 0) + nread += result; + } + index++; + } while (index < req->nbufs && result > 0); + if (nread > 0) + result = nread; + } +# if defined(__linux__) + else { + result = uv__preadv(req->file, + (struct iovec*)req->bufs, + req->nbufs, + req->off); + if (result == -1 && errno == ENOSYS) { + no_preadv = 1; + goto retry; + } + } +# endif +#endif + } + +done: + return result; +} + + +#if defined(__OpenBSD__) || (defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8)) +static int uv__fs_scandir_filter(uv__dirent_t* dent) { +#else +static int uv__fs_scandir_filter(const uv__dirent_t* dent) { +#endif + return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0; +} + + +static ssize_t uv__fs_scandir(uv_fs_t* req) { + uv__dirent_t **dents; + int saved_errno; + int n; + + dents = NULL; + n = scandir(req->path, &dents, uv__fs_scandir_filter, alphasort); + + /* NOTE: We will use nbufs as an index field */ + req->nbufs = 0; + + if (n == 0) + goto out; /* osx still needs to deallocate some memory */ + else if (n == -1) + return n; + + req->ptr = dents; + + return n; + +out: + saved_errno = errno; + if (dents != NULL) { + int i; + + /* Memory was allocated using the system allocator, so use free() here. */ + for (i = 0; i < n; i++) + free(dents[i]); + free(dents); + } + errno = saved_errno; + + req->ptr = NULL; + + return n; +} + + +static ssize_t uv__fs_pathmax_size(const char* path) { + ssize_t pathmax; + + pathmax = pathconf(path, _PC_PATH_MAX); + + if (pathmax == -1) { +#if defined(PATH_MAX) + return PATH_MAX; +#else +#error "PATH_MAX undefined in the current platform" +#endif + } + + return pathmax; +} + +static ssize_t uv__fs_readlink(uv_fs_t* req) { + ssize_t len; + char* buf; + + len = uv__fs_pathmax_size(req->path); + buf = uv__malloc(len + 1); + + if (buf == NULL) { + errno = ENOMEM; + return -1; + } + + len = readlink(req->path, buf, len); + + if (len == -1) { + uv__free(buf); + return -1; + } + + buf[len] = '\0'; + req->ptr = buf; + + return 0; +} + +static ssize_t uv__fs_realpath(uv_fs_t* req) { + ssize_t len; + char* buf; + + len = uv__fs_pathmax_size(req->path); + buf = uv__malloc(len + 1); + + if (buf == NULL) { + errno = ENOMEM; + return -1; + } + + if (realpath(req->path, buf) == NULL) { + uv__free(buf); + return -1; + } + + req->ptr = buf; + + return 0; +} + +static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) { + struct pollfd pfd; + int use_pread; + off_t offset; + ssize_t nsent; + ssize_t nread; + ssize_t nwritten; + size_t buflen; + size_t len; + ssize_t n; + int in_fd; + int out_fd; + char buf[8192]; + + len = req->bufsml[0].len; + in_fd = req->flags; + out_fd = req->file; + offset = req->off; + use_pread = 1; + + /* Here are the rules regarding errors: + * + * 1. Read errors are reported only if nsent==0, otherwise we return nsent. + * The user needs to know that some data has already been sent, to stop + * them from sending it twice. + * + * 2. Write errors are always reported. Write errors are bad because they + * mean data loss: we've read data but now we can't write it out. + * + * We try to use pread() and fall back to regular read() if the source fd + * doesn't support positional reads, for example when it's a pipe fd. + * + * If we get EAGAIN when writing to the target fd, we poll() on it until + * it becomes writable again. + * + * FIXME: If we get a write error when use_pread==1, it should be safe to + * return the number of sent bytes instead of an error because pread() + * is, in theory, idempotent. However, special files in /dev or /proc + * may support pread() but not necessarily return the same data on + * successive reads. + * + * FIXME: There is no way now to signal that we managed to send *some* data + * before a write error. + */ + for (nsent = 0; (size_t) nsent < len; ) { + buflen = len - nsent; + + if (buflen > sizeof(buf)) + buflen = sizeof(buf); + + do + if (use_pread) + nread = pread(in_fd, buf, buflen, offset); + else + nread = read(in_fd, buf, buflen); + while (nread == -1 && errno == EINTR); + + if (nread == 0) + goto out; + + if (nread == -1) { + if (use_pread && nsent == 0 && (errno == EIO || errno == ESPIPE)) { + use_pread = 0; + continue; + } + + if (nsent == 0) + nsent = -1; + + goto out; + } + + for (nwritten = 0; nwritten < nread; ) { + do + n = write(out_fd, buf + nwritten, nread - nwritten); + while (n == -1 && errno == EINTR); + + if (n != -1) { + nwritten += n; + continue; + } + + if (errno != EAGAIN && errno != EWOULDBLOCK) { + nsent = -1; + goto out; + } + + pfd.fd = out_fd; + pfd.events = POLLOUT; + pfd.revents = 0; + + do + n = poll(&pfd, 1, -1); + while (n == -1 && errno == EINTR); + + if (n == -1 || (pfd.revents & ~POLLOUT) != 0) { + errno = EIO; + nsent = -1; + goto out; + } + } + + offset += nread; + nsent += nread; + } + +out: + if (nsent != -1) + req->off = offset; + + return nsent; +} + + +static ssize_t uv__fs_sendfile(uv_fs_t* req) { + int in_fd; + int out_fd; + + in_fd = req->flags; + out_fd = req->file; + +#if defined(__linux__) || defined(__sun) + { + off_t off; + ssize_t r; + + off = req->off; + r = sendfile(out_fd, in_fd, &off, req->bufsml[0].len); + + /* sendfile() on SunOS returns EINVAL if the target fd is not a socket but + * it still writes out data. Fortunately, we can detect it by checking if + * the offset has been updated. + */ + if (r != -1 || off > req->off) { + r = off - req->off; + req->off = off; + return r; + } + + if (errno == EINVAL || + errno == EIO || + errno == ENOTSOCK || + errno == EXDEV) { + errno = 0; + return uv__fs_sendfile_emul(req); + } + + return -1; + } +#elif defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) + { + off_t len; + ssize_t r; + + /* sendfile() on FreeBSD and Darwin returns EAGAIN if the target fd is in + * non-blocking mode and not all data could be written. If a non-zero + * number of bytes have been sent, we don't consider it an error. + */ + +#if defined(__FreeBSD__) || defined(__DragonFly__) + len = 0; + r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0); +#elif defined(__FreeBSD_kernel__) + len = 0; + r = bsd_sendfile(in_fd, + out_fd, + req->off, + req->bufsml[0].len, + NULL, + &len, + 0); +#else + /* The darwin sendfile takes len as an input for the length to send, + * so make sure to initialize it with the caller's value. */ + len = req->bufsml[0].len; + r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0); +#endif + + /* + * The man page for sendfile(2) on DragonFly states that `len` contains + * a meaningful value ONLY in case of EAGAIN and EINTR. + * Nothing is said about it's value in case of other errors, so better + * not depend on the potential wrong assumption that is was not modified + * by the syscall. + */ + if (r == 0 || ((errno == EAGAIN || errno == EINTR) && len != 0)) { + req->off += len; + return (ssize_t) len; + } + + if (errno == EINVAL || + errno == EIO || + errno == ENOTSOCK || + errno == EXDEV) { + errno = 0; + return uv__fs_sendfile_emul(req); + } + + return -1; + } +#else + /* Squelch compiler warnings. */ + (void) &in_fd; + (void) &out_fd; + + return uv__fs_sendfile_emul(req); +#endif +} + + +static ssize_t uv__fs_utime(uv_fs_t* req) { + struct utimbuf buf; + buf.actime = req->atime; + buf.modtime = req->mtime; + return utime(req->path, &buf); /* TODO use utimes() where available */ +} + + +static ssize_t uv__fs_write(uv_fs_t* req) { +#if defined(__linux__) + static int no_pwritev; +#endif + ssize_t r; + + /* Serialize writes on OS X, concurrent write() and pwrite() calls result in + * data loss. We can't use a per-file descriptor lock, the descriptor may be + * a dup(). + */ +#if defined(__APPLE__) + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + + if (pthread_mutex_lock(&lock)) + abort(); +#endif + + if (req->off < 0) { + if (req->nbufs == 1) + r = write(req->file, req->bufs[0].base, req->bufs[0].len); + else + r = writev(req->file, (struct iovec*) req->bufs, req->nbufs); + } else { + if (req->nbufs == 1) { + r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off); + goto done; + } +#if HAVE_PREADV + r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); +#else +# if defined(__linux__) + if (no_pwritev) retry: +# endif + { + off_t written; + size_t index; + + written = 0; + index = 0; + r = 0; + do { + if (req->bufs[index].len > 0) { + r = pwrite(req->file, + req->bufs[index].base, + req->bufs[index].len, + req->off + written); + if (r > 0) + written += r; + } + index++; + } while (index < req->nbufs && r >= 0); + if (written > 0) + r = written; + } +# if defined(__linux__) + else { + r = uv__pwritev(req->file, + (struct iovec*) req->bufs, + req->nbufs, + req->off); + if (r == -1 && errno == ENOSYS) { + no_pwritev = 1; + goto retry; + } + } +# endif +#endif + } + +done: +#if defined(__APPLE__) + if (pthread_mutex_unlock(&lock)) + abort(); +#endif + + return r; +} + +static void uv__to_stat(struct stat* src, uv_stat_t* dst) { + dst->st_dev = src->st_dev; + dst->st_mode = src->st_mode; + dst->st_nlink = src->st_nlink; + dst->st_uid = src->st_uid; + dst->st_gid = src->st_gid; + dst->st_rdev = src->st_rdev; + dst->st_ino = src->st_ino; + dst->st_size = src->st_size; + dst->st_blksize = src->st_blksize; + dst->st_blocks = src->st_blocks; + +#if defined(__APPLE__) + dst->st_atim.tv_sec = src->st_atimespec.tv_sec; + dst->st_atim.tv_nsec = src->st_atimespec.tv_nsec; + dst->st_mtim.tv_sec = src->st_mtimespec.tv_sec; + dst->st_mtim.tv_nsec = src->st_mtimespec.tv_nsec; + dst->st_ctim.tv_sec = src->st_ctimespec.tv_sec; + dst->st_ctim.tv_nsec = src->st_ctimespec.tv_nsec; + dst->st_birthtim.tv_sec = src->st_birthtimespec.tv_sec; + dst->st_birthtim.tv_nsec = src->st_birthtimespec.tv_nsec; + dst->st_flags = src->st_flags; + dst->st_gen = src->st_gen; +#elif defined(__ANDROID__) + dst->st_atim.tv_sec = src->st_atime; + dst->st_atim.tv_nsec = src->st_atimensec; + dst->st_mtim.tv_sec = src->st_mtime; + dst->st_mtim.tv_nsec = src->st_mtimensec; + dst->st_ctim.tv_sec = src->st_ctime; + dst->st_ctim.tv_nsec = src->st_ctimensec; + dst->st_birthtim.tv_sec = src->st_ctime; + dst->st_birthtim.tv_nsec = src->st_ctimensec; + dst->st_flags = 0; + dst->st_gen = 0; +#elif !defined(_AIX) && ( \ + defined(_BSD_SOURCE) || \ + defined(_SVID_SOURCE) || \ + defined(_XOPEN_SOURCE) || \ + defined(_DEFAULT_SOURCE)) + dst->st_atim.tv_sec = src->st_atim.tv_sec; + dst->st_atim.tv_nsec = src->st_atim.tv_nsec; + dst->st_mtim.tv_sec = src->st_mtim.tv_sec; + dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec; + dst->st_ctim.tv_sec = src->st_ctim.tv_sec; + dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec; +# if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) + dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec; + dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec; + dst->st_flags = src->st_flags; + dst->st_gen = src->st_gen; +# else + dst->st_birthtim.tv_sec = src->st_ctim.tv_sec; + dst->st_birthtim.tv_nsec = src->st_ctim.tv_nsec; + dst->st_flags = 0; + dst->st_gen = 0; +# endif +#else + dst->st_atim.tv_sec = src->st_atime; + dst->st_atim.tv_nsec = 0; + dst->st_mtim.tv_sec = src->st_mtime; + dst->st_mtim.tv_nsec = 0; + dst->st_ctim.tv_sec = src->st_ctime; + dst->st_ctim.tv_nsec = 0; + dst->st_birthtim.tv_sec = src->st_ctime; + dst->st_birthtim.tv_nsec = 0; + dst->st_flags = 0; + dst->st_gen = 0; +#endif +} + + +static int uv__fs_stat(const char *path, uv_stat_t *buf) { + struct stat pbuf; + int ret; + + ret = stat(path, &pbuf); + if (ret == 0) + uv__to_stat(&pbuf, buf); + + return ret; +} + + +static int uv__fs_lstat(const char *path, uv_stat_t *buf) { + struct stat pbuf; + int ret; + + ret = lstat(path, &pbuf); + if (ret == 0) + uv__to_stat(&pbuf, buf); + + return ret; +} + + +static int uv__fs_fstat(int fd, uv_stat_t *buf) { + struct stat pbuf; + int ret; + + ret = fstat(fd, &pbuf); + if (ret == 0) + uv__to_stat(&pbuf, buf); + + return ret; +} + + +typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req); +static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) { + unsigned int iovmax; + unsigned int nbufs; + uv_buf_t* bufs; + ssize_t total; + ssize_t result; + + iovmax = uv__getiovmax(); + nbufs = req->nbufs; + bufs = req->bufs; + total = 0; + + while (nbufs > 0) { + req->nbufs = nbufs; + if (req->nbufs > iovmax) + req->nbufs = iovmax; + + result = process(req); + if (result <= 0) { + if (total == 0) + total = result; + break; + } + + if (req->off >= 0) + req->off += result; + + req->bufs += req->nbufs; + nbufs -= req->nbufs; + total += result; + } + + if (errno == EINTR && total == -1) + return total; + + if (bufs != req->bufsml) + uv__free(bufs); + + req->bufs = NULL; + req->nbufs = 0; + + return total; +} + + +static void uv__fs_work(struct uv__work* w) { + int retry_on_eintr; + uv_fs_t* req; + ssize_t r; + + req = container_of(w, uv_fs_t, work_req); + retry_on_eintr = !(req->fs_type == UV_FS_CLOSE); + + do { + errno = 0; + +#define X(type, action) \ + case UV_FS_ ## type: \ + r = action; \ + break; + + switch (req->fs_type) { + X(ACCESS, access(req->path, req->flags)); + X(CHMOD, chmod(req->path, req->mode)); + X(CHOWN, chown(req->path, req->uid, req->gid)); + X(CLOSE, close(req->file)); + X(FCHMOD, fchmod(req->file, req->mode)); + X(FCHOWN, fchown(req->file, req->uid, req->gid)); + X(FDATASYNC, uv__fs_fdatasync(req)); + X(FSTAT, uv__fs_fstat(req->file, &req->statbuf)); + X(FSYNC, fsync(req->file)); + X(FTRUNCATE, ftruncate(req->file, req->off)); + X(FUTIME, uv__fs_futime(req)); + X(LSTAT, uv__fs_lstat(req->path, &req->statbuf)); + X(LINK, link(req->path, req->new_path)); + X(MKDIR, mkdir(req->path, req->mode)); + X(MKDTEMP, uv__fs_mkdtemp(req)); + X(OPEN, uv__fs_open(req)); + X(READ, uv__fs_buf_iter(req, uv__fs_read)); + X(SCANDIR, uv__fs_scandir(req)); + X(READLINK, uv__fs_readlink(req)); + X(REALPATH, uv__fs_realpath(req)); + X(RENAME, rename(req->path, req->new_path)); + X(RMDIR, rmdir(req->path)); + X(SENDFILE, uv__fs_sendfile(req)); + X(STAT, uv__fs_stat(req->path, &req->statbuf)); + X(SYMLINK, symlink(req->path, req->new_path)); + X(UNLINK, unlink(req->path)); + X(UTIME, uv__fs_utime(req)); + X(WRITE, uv__fs_buf_iter(req, uv__fs_write)); + default: abort(); + } +#undef X + } while (r == -1 && errno == EINTR && retry_on_eintr); + + if (r == -1) + req->result = -errno; + else + req->result = r; + + if (r == 0 && (req->fs_type == UV_FS_STAT || + req->fs_type == UV_FS_FSTAT || + req->fs_type == UV_FS_LSTAT)) { + req->ptr = &req->statbuf; + } +} + + +static void uv__fs_done(struct uv__work* w, int status) { + uv_fs_t* req; + + req = container_of(w, uv_fs_t, work_req); + uv__req_unregister(req->loop, req); + + if (status == -ECANCELED) { + assert(req->result == 0); + req->result = -ECANCELED; + } + + req->cb(req); +} + + +int uv_fs_access(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + uv_fs_cb cb) { + INIT(ACCESS); + PATH; + req->flags = flags; + POST; +} + + +int uv_fs_chmod(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int mode, + uv_fs_cb cb) { + INIT(CHMOD); + PATH; + req->mode = mode; + POST; +} + + +int uv_fs_chown(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb) { + INIT(CHOWN); + PATH; + req->uid = uid; + req->gid = gid; + POST; +} + + +int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { + INIT(CLOSE); + req->file = file; + POST; +} + + +int uv_fs_fchmod(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + int mode, + uv_fs_cb cb) { + INIT(FCHMOD); + req->file = file; + req->mode = mode; + POST; +} + + +int uv_fs_fchown(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb) { + INIT(FCHOWN); + req->file = file; + req->uid = uid; + req->gid = gid; + POST; +} + + +int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { + INIT(FDATASYNC); + req->file = file; + POST; +} + + +int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { + INIT(FSTAT); + req->file = file; + POST; +} + + +int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { + INIT(FSYNC); + req->file = file; + POST; +} + + +int uv_fs_ftruncate(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + int64_t off, + uv_fs_cb cb) { + INIT(FTRUNCATE); + req->file = file; + req->off = off; + POST; +} + + +int uv_fs_futime(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + double atime, + double mtime, + uv_fs_cb cb) { + INIT(FUTIME); + req->file = file; + req->atime = atime; + req->mtime = mtime; + POST; +} + + +int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + INIT(LSTAT); + PATH; + POST; +} + + +int uv_fs_link(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + uv_fs_cb cb) { + INIT(LINK); + PATH2; + POST; +} + + +int uv_fs_mkdir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int mode, + uv_fs_cb cb) { + INIT(MKDIR); + PATH; + req->mode = mode; + POST; +} + + +int uv_fs_mkdtemp(uv_loop_t* loop, + uv_fs_t* req, + const char* tpl, + uv_fs_cb cb) { + INIT(MKDTEMP); + req->path = uv__strdup(tpl); + if (req->path == NULL) { + if (cb != NULL) + uv__req_unregister(loop, req); + return -ENOMEM; + } + POST; +} + + +int uv_fs_open(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + int mode, + uv_fs_cb cb) { + INIT(OPEN); + PATH; + req->flags = flags; + req->mode = mode; + POST; +} + + +int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, + uv_file file, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t off, + uv_fs_cb cb) { + if (bufs == NULL || nbufs == 0) + return -EINVAL; + + INIT(READ); + req->file = file; + + req->nbufs = nbufs; + req->bufs = req->bufsml; + if (nbufs > ARRAY_SIZE(req->bufsml)) + req->bufs = uv__malloc(nbufs * sizeof(*bufs)); + + if (req->bufs == NULL) { + if (cb != NULL) + uv__req_unregister(loop, req); + return -ENOMEM; + } + + memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); + + req->off = off; + POST; +} + + +int uv_fs_scandir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + uv_fs_cb cb) { + INIT(SCANDIR); + PATH; + req->flags = flags; + POST; +} + + +int uv_fs_readlink(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb) { + INIT(READLINK); + PATH; + POST; +} + + +int uv_fs_realpath(uv_loop_t* loop, + uv_fs_t* req, + const char * path, + uv_fs_cb cb) { + INIT(REALPATH); + PATH; + POST; +} + + +int uv_fs_rename(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + uv_fs_cb cb) { + INIT(RENAME); + PATH2; + POST; +} + + +int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + INIT(RMDIR); + PATH; + POST; +} + + +int uv_fs_sendfile(uv_loop_t* loop, + uv_fs_t* req, + uv_file out_fd, + uv_file in_fd, + int64_t off, + size_t len, + uv_fs_cb cb) { + INIT(SENDFILE); + req->flags = in_fd; /* hack */ + req->file = out_fd; + req->off = off; + req->bufsml[0].len = len; + POST; +} + + +int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + INIT(STAT); + PATH; + POST; +} + + +int uv_fs_symlink(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + int flags, + uv_fs_cb cb) { + INIT(SYMLINK); + PATH2; + req->flags = flags; + POST; +} + + +int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + INIT(UNLINK); + PATH; + POST; +} + + +int uv_fs_utime(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + double atime, + double mtime, + uv_fs_cb cb) { + INIT(UTIME); + PATH; + req->atime = atime; + req->mtime = mtime; + POST; +} + + +int uv_fs_write(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t off, + uv_fs_cb cb) { + if (bufs == NULL || nbufs == 0) + return -EINVAL; + + INIT(WRITE); + req->file = file; + + req->nbufs = nbufs; + req->bufs = req->bufsml; + if (nbufs > ARRAY_SIZE(req->bufsml)) + req->bufs = uv__malloc(nbufs * sizeof(*bufs)); + + if (req->bufs == NULL) { + if (cb != NULL) + uv__req_unregister(loop, req); + return -ENOMEM; + } + + memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); + + req->off = off; + POST; +} + + +void uv_fs_req_cleanup(uv_fs_t* req) { + /* Only necessary for asychronous requests, i.e., requests with a callback. + * Synchronous ones don't copy their arguments and have req->path and + * req->new_path pointing to user-owned memory. UV_FS_MKDTEMP is the + * exception to the rule, it always allocates memory. + */ + if (req->path != NULL && (req->cb != NULL || req->fs_type == UV_FS_MKDTEMP)) + uv__free((void*) req->path); /* Memory is shared with req->new_path. */ + + req->path = NULL; + req->new_path = NULL; + + if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL) + uv__fs_scandir_cleanup(req); + + if (req->ptr != &req->statbuf) + uv__free(req->ptr); + req->ptr = NULL; +} diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c new file mode 100644 index 0000000..d331a13 --- /dev/null +++ b/src/unix/fsevents.c @@ -0,0 +1,904 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#if TARGET_OS_IPHONE + +/* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */ + +int uv__fsevents_init(uv_fs_event_t* handle) { + return 0; +} + + +int uv__fsevents_close(uv_fs_event_t* handle) { + return 0; +} + + +void uv__fsevents_loop_delete(uv_loop_t* loop) { +} + +#else /* TARGET_OS_IPHONE */ + +#include +#include +#include +#include + +#include +#include + +/* These are macros to avoid "initializer element is not constant" errors + * with old versions of gcc. + */ +#define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod | \ + kFSEventStreamEventFlagItemModified | \ + kFSEventStreamEventFlagItemInodeMetaMod | \ + kFSEventStreamEventFlagItemChangeOwner | \ + kFSEventStreamEventFlagItemXattrMod) + +#define kFSEventsRenamed (kFSEventStreamEventFlagItemCreated | \ + kFSEventStreamEventFlagItemRemoved | \ + kFSEventStreamEventFlagItemRenamed) + +#define kFSEventsSystem (kFSEventStreamEventFlagUserDropped | \ + kFSEventStreamEventFlagKernelDropped | \ + kFSEventStreamEventFlagEventIdsWrapped | \ + kFSEventStreamEventFlagHistoryDone | \ + kFSEventStreamEventFlagMount | \ + kFSEventStreamEventFlagUnmount | \ + kFSEventStreamEventFlagRootChanged) + +typedef struct uv__fsevents_event_s uv__fsevents_event_t; +typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t; +typedef struct uv__cf_loop_state_s uv__cf_loop_state_t; + +enum uv__cf_loop_signal_type_e { + kUVCFLoopSignalRegular, + kUVCFLoopSignalClosing +}; +typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t; + +struct uv__cf_loop_signal_s { + QUEUE member; + uv_fs_event_t* handle; + uv__cf_loop_signal_type_t type; +}; + +struct uv__fsevents_event_s { + QUEUE member; + int events; + char path[1]; +}; + +struct uv__cf_loop_state_s { + CFRunLoopRef loop; + CFRunLoopSourceRef signal_source; + int fsevent_need_reschedule; + FSEventStreamRef fsevent_stream; + uv_sem_t fsevent_sem; + uv_mutex_t fsevent_mutex; + void* fsevent_handles[2]; + unsigned int fsevent_handle_count; +}; + +/* Forward declarations */ +static void uv__cf_loop_cb(void* arg); +static void* uv__cf_loop_runner(void* arg); +static int uv__cf_loop_signal(uv_loop_t* loop, + uv_fs_event_t* handle, + uv__cf_loop_signal_type_t type); + +/* Lazy-loaded by uv__fsevents_global_init(). */ +static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef, + const void**, + CFIndex, + const CFArrayCallBacks*); +static void (*pCFRelease)(CFTypeRef); +static void (*pCFRunLoopAddSource)(CFRunLoopRef, + CFRunLoopSourceRef, + CFStringRef); +static CFRunLoopRef (*pCFRunLoopGetCurrent)(void); +static void (*pCFRunLoopRemoveSource)(CFRunLoopRef, + CFRunLoopSourceRef, + CFStringRef); +static void (*pCFRunLoopRun)(void); +static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef, + CFIndex, + CFRunLoopSourceContext*); +static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef); +static void (*pCFRunLoopStop)(CFRunLoopRef); +static void (*pCFRunLoopWakeUp)(CFRunLoopRef); +static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)( + CFAllocatorRef, + const char*); +static CFStringEncoding (*pCFStringGetSystemEncoding)(void); +static CFStringRef (*pkCFRunLoopDefaultMode); +static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef, + FSEventStreamCallback, + FSEventStreamContext*, + CFArrayRef, + FSEventStreamEventId, + CFTimeInterval, + FSEventStreamCreateFlags); +static void (*pFSEventStreamFlushSync)(FSEventStreamRef); +static void (*pFSEventStreamInvalidate)(FSEventStreamRef); +static void (*pFSEventStreamRelease)(FSEventStreamRef); +static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef, + CFRunLoopRef, + CFStringRef); +static Boolean (*pFSEventStreamStart)(FSEventStreamRef); +static void (*pFSEventStreamStop)(FSEventStreamRef); + +#define UV__FSEVENTS_PROCESS(handle, block) \ + do { \ + QUEUE events; \ + QUEUE* q; \ + uv__fsevents_event_t* event; \ + int err; \ + uv_mutex_lock(&(handle)->cf_mutex); \ + /* Split-off all events and empty original queue */ \ + QUEUE_MOVE(&(handle)->cf_events, &events); \ + /* Get error (if any) and zero original one */ \ + err = (handle)->cf_error; \ + (handle)->cf_error = 0; \ + uv_mutex_unlock(&(handle)->cf_mutex); \ + /* Loop through events, deallocating each after processing */ \ + while (!QUEUE_EMPTY(&events)) { \ + q = QUEUE_HEAD(&events); \ + event = QUEUE_DATA(q, uv__fsevents_event_t, member); \ + QUEUE_REMOVE(q); \ + /* NOTE: Checking uv__is_active() is required here, because handle \ + * callback may close handle and invoking it after it will lead to \ + * incorrect behaviour */ \ + if (!uv__is_closing((handle)) && uv__is_active((handle))) \ + block \ + /* Free allocated data */ \ + uv__free(event); \ + } \ + if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle))) \ + (handle)->cb((handle), NULL, 0, err); \ + } while (0) + + +/* Runs in UV loop's thread, when there're events to report to handle */ +static void uv__fsevents_cb(uv_async_t* cb) { + uv_fs_event_t* handle; + + handle = cb->data; + + UV__FSEVENTS_PROCESS(handle, { + handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0); + }); +} + + +/* Runs in CF thread, pushed event into handle's event list */ +static void uv__fsevents_push_event(uv_fs_event_t* handle, + QUEUE* events, + int err) { + assert(events != NULL || err != 0); + uv_mutex_lock(&handle->cf_mutex); + + /* Concatenate two queues */ + if (events != NULL) + QUEUE_ADD(&handle->cf_events, events); + + /* Propagate error */ + if (err != 0) + handle->cf_error = err; + uv_mutex_unlock(&handle->cf_mutex); + + uv_async_send(handle->cf_cb); +} + + +/* Runs in CF thread, when there're events in FSEventStream */ +static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, + void* info, + size_t numEvents, + void* eventPaths, + const FSEventStreamEventFlags eventFlags[], + const FSEventStreamEventId eventIds[]) { + size_t i; + int len; + char** paths; + char* path; + char* pos; + uv_fs_event_t* handle; + QUEUE* q; + uv_loop_t* loop; + uv__cf_loop_state_t* state; + uv__fsevents_event_t* event; + QUEUE head; + + loop = info; + state = loop->cf_state; + assert(state != NULL); + paths = eventPaths; + + /* For each handle */ + uv_mutex_lock(&state->fsevent_mutex); + QUEUE_FOREACH(q, &state->fsevent_handles) { + handle = QUEUE_DATA(q, uv_fs_event_t, cf_member); + QUEUE_INIT(&head); + + /* Process and filter out events */ + for (i = 0; i < numEvents; i++) { + /* Ignore system events */ + if (eventFlags[i] & kFSEventsSystem) + continue; + + path = paths[i]; + len = strlen(path); + + /* Filter out paths that are outside handle's request */ + if (strncmp(path, handle->realpath, handle->realpath_len) != 0) + continue; + + if (handle->realpath_len > 1 || *handle->realpath != '/') { + path += handle->realpath_len; + len -= handle->realpath_len; + + /* Skip forward slash */ + if (*path != '\0') { + path++; + len--; + } + } + +#ifdef MAC_OS_X_VERSION_10_7 + /* Ignore events with path equal to directory itself */ + if (len == 0) + continue; +#endif /* MAC_OS_X_VERSION_10_7 */ + + /* Do not emit events from subdirectories (without option set) */ + if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != 0) { + pos = strchr(path + 1, '/'); + if (pos != NULL) + continue; + } + +#ifndef MAC_OS_X_VERSION_10_7 + path = ""; + len = 0; +#endif /* MAC_OS_X_VERSION_10_7 */ + + event = uv__malloc(sizeof(*event) + len); + if (event == NULL) + break; + + memset(event, 0, sizeof(*event)); + memcpy(event->path, path, len + 1); + + if ((eventFlags[i] & kFSEventsModified) != 0 && + (eventFlags[i] & kFSEventsRenamed) == 0) + event->events = UV_CHANGE; + else + event->events = UV_RENAME; + + QUEUE_INSERT_TAIL(&head, &event->member); + } + + if (!QUEUE_EMPTY(&head)) + uv__fsevents_push_event(handle, &head, 0); + } + uv_mutex_unlock(&state->fsevent_mutex); +} + + +/* Runs in CF thread */ +static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) { + uv__cf_loop_state_t* state; + FSEventStreamContext ctx; + FSEventStreamRef ref; + CFAbsoluteTime latency; + FSEventStreamCreateFlags flags; + + /* Initialize context */ + ctx.version = 0; + ctx.info = loop; + ctx.retain = NULL; + ctx.release = NULL; + ctx.copyDescription = NULL; + + latency = 0.05; + + /* Explanation of selected flags: + * 1. NoDefer - without this flag, events that are happening continuously + * (i.e. each event is happening after time interval less than `latency`, + * counted from previous event), will be deferred and passed to callback + * once they'll either fill whole OS buffer, or when this continuous stream + * will stop (i.e. there'll be delay between events, bigger than + * `latency`). + * Specifying this flag will invoke callback after `latency` time passed + * since event. + * 2. FileEvents - fire callback for file changes too (by default it is firing + * it only for directory changes). + */ + flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents; + + /* + * NOTE: It might sound like a good idea to remember last seen StreamEventId, + * but in reality one dir might have last StreamEventId less than, the other, + * that is being watched now. Which will cause FSEventStream API to report + * changes to files from the past. + */ + ref = pFSEventStreamCreate(NULL, + &uv__fsevents_event_cb, + &ctx, + paths, + kFSEventStreamEventIdSinceNow, + latency, + flags); + assert(ref != NULL); + + state = loop->cf_state; + pFSEventStreamScheduleWithRunLoop(ref, + state->loop, + *pkCFRunLoopDefaultMode); + if (!pFSEventStreamStart(ref)) { + pFSEventStreamInvalidate(ref); + pFSEventStreamRelease(ref); + return -EMFILE; + } + + state->fsevent_stream = ref; + return 0; +} + + +/* Runs in CF thread */ +static void uv__fsevents_destroy_stream(uv_loop_t* loop) { + uv__cf_loop_state_t* state; + + state = loop->cf_state; + + if (state->fsevent_stream == NULL) + return; + + /* Flush all accumulated events */ + pFSEventStreamFlushSync(state->fsevent_stream); + + /* Stop emitting events */ + pFSEventStreamStop(state->fsevent_stream); + + /* Release stream */ + pFSEventStreamInvalidate(state->fsevent_stream); + pFSEventStreamRelease(state->fsevent_stream); + state->fsevent_stream = NULL; +} + + +/* Runs in CF thread, when there're new fsevent handles to add to stream */ +static void uv__fsevents_reschedule(uv_fs_event_t* handle, + uv__cf_loop_signal_type_t type) { + uv__cf_loop_state_t* state; + QUEUE* q; + uv_fs_event_t* curr; + CFArrayRef cf_paths; + CFStringRef* paths; + unsigned int i; + int err; + unsigned int path_count; + + state = handle->loop->cf_state; + paths = NULL; + cf_paths = NULL; + err = 0; + /* NOTE: `i` is used in deallocation loop below */ + i = 0; + + /* Optimization to prevent O(n^2) time spent when starting to watch + * many files simultaneously + */ + uv_mutex_lock(&state->fsevent_mutex); + if (state->fsevent_need_reschedule == 0) { + uv_mutex_unlock(&state->fsevent_mutex); + goto final; + } + state->fsevent_need_reschedule = 0; + uv_mutex_unlock(&state->fsevent_mutex); + + /* Destroy previous FSEventStream */ + uv__fsevents_destroy_stream(handle->loop); + + /* Any failure below will be a memory failure */ + err = -ENOMEM; + + /* Create list of all watched paths */ + uv_mutex_lock(&state->fsevent_mutex); + path_count = state->fsevent_handle_count; + if (path_count != 0) { + paths = uv__malloc(sizeof(*paths) * path_count); + if (paths == NULL) { + uv_mutex_unlock(&state->fsevent_mutex); + goto final; + } + + q = &state->fsevent_handles; + for (; i < path_count; i++) { + q = QUEUE_NEXT(q); + assert(q != &state->fsevent_handles); + curr = QUEUE_DATA(q, uv_fs_event_t, cf_member); + + assert(curr->realpath != NULL); + paths[i] = + pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath); + if (paths[i] == NULL) { + uv_mutex_unlock(&state->fsevent_mutex); + goto final; + } + } + } + uv_mutex_unlock(&state->fsevent_mutex); + err = 0; + + if (path_count != 0) { + /* Create new FSEventStream */ + cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL); + if (cf_paths == NULL) { + err = -ENOMEM; + goto final; + } + err = uv__fsevents_create_stream(handle->loop, cf_paths); + } + +final: + /* Deallocate all paths in case of failure */ + if (err != 0) { + if (cf_paths == NULL) { + while (i != 0) + pCFRelease(paths[--i]); + uv__free(paths); + } else { + /* CFArray takes ownership of both strings and original C-array */ + pCFRelease(cf_paths); + } + + /* Broadcast error to all handles */ + uv_mutex_lock(&state->fsevent_mutex); + QUEUE_FOREACH(q, &state->fsevent_handles) { + curr = QUEUE_DATA(q, uv_fs_event_t, cf_member); + uv__fsevents_push_event(curr, NULL, err); + } + uv_mutex_unlock(&state->fsevent_mutex); + } + + /* + * Main thread will block until the removal of handle from the list, + * we must tell it when we're ready. + * + * NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close` + */ + if (type == kUVCFLoopSignalClosing) + uv_sem_post(&state->fsevent_sem); +} + + +static int uv__fsevents_global_init(void) { + static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER; + static void* core_foundation_handle; + static void* core_services_handle; + int err; + + err = 0; + pthread_mutex_lock(&global_init_mutex); + if (core_foundation_handle != NULL) + goto out; + + /* The libraries are never unloaded because we currently don't have a good + * mechanism for keeping a reference count. It's unlikely to be an issue + * but if it ever becomes one, we can turn the dynamic library handles into + * per-event loop properties and have the dynamic linker keep track for us. + */ + err = -ENOSYS; + core_foundation_handle = dlopen("/System/Library/Frameworks/" + "CoreFoundation.framework/" + "Versions/A/CoreFoundation", + RTLD_LAZY | RTLD_LOCAL); + if (core_foundation_handle == NULL) + goto out; + + core_services_handle = dlopen("/System/Library/Frameworks/" + "CoreServices.framework/" + "Versions/A/CoreServices", + RTLD_LAZY | RTLD_LOCAL); + if (core_services_handle == NULL) + goto out; + + err = -ENOENT; +#define V(handle, symbol) \ + do { \ + *(void **)(&p ## symbol) = dlsym((handle), #symbol); \ + if (p ## symbol == NULL) \ + goto out; \ + } \ + while (0) + V(core_foundation_handle, CFArrayCreate); + V(core_foundation_handle, CFRelease); + V(core_foundation_handle, CFRunLoopAddSource); + V(core_foundation_handle, CFRunLoopGetCurrent); + V(core_foundation_handle, CFRunLoopRemoveSource); + V(core_foundation_handle, CFRunLoopRun); + V(core_foundation_handle, CFRunLoopSourceCreate); + V(core_foundation_handle, CFRunLoopSourceSignal); + V(core_foundation_handle, CFRunLoopStop); + V(core_foundation_handle, CFRunLoopWakeUp); + V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation); + V(core_foundation_handle, CFStringGetSystemEncoding); + V(core_foundation_handle, kCFRunLoopDefaultMode); + V(core_services_handle, FSEventStreamCreate); + V(core_services_handle, FSEventStreamFlushSync); + V(core_services_handle, FSEventStreamInvalidate); + V(core_services_handle, FSEventStreamRelease); + V(core_services_handle, FSEventStreamScheduleWithRunLoop); + V(core_services_handle, FSEventStreamStart); + V(core_services_handle, FSEventStreamStop); +#undef V + err = 0; + +out: + if (err && core_services_handle != NULL) { + dlclose(core_services_handle); + core_services_handle = NULL; + } + + if (err && core_foundation_handle != NULL) { + dlclose(core_foundation_handle); + core_foundation_handle = NULL; + } + + pthread_mutex_unlock(&global_init_mutex); + return err; +} + + +/* Runs in UV loop */ +static int uv__fsevents_loop_init(uv_loop_t* loop) { + CFRunLoopSourceContext ctx; + uv__cf_loop_state_t* state; + pthread_attr_t attr_storage; + pthread_attr_t* attr; + int err; + + if (loop->cf_state != NULL) + return 0; + + err = uv__fsevents_global_init(); + if (err) + return err; + + state = uv__calloc(1, sizeof(*state)); + if (state == NULL) + return -ENOMEM; + + err = uv_mutex_init(&loop->cf_mutex); + if (err) + goto fail_mutex_init; + + err = uv_sem_init(&loop->cf_sem, 0); + if (err) + goto fail_sem_init; + + QUEUE_INIT(&loop->cf_signals); + + err = uv_sem_init(&state->fsevent_sem, 0); + if (err) + goto fail_fsevent_sem_init; + + err = uv_mutex_init(&state->fsevent_mutex); + if (err) + goto fail_fsevent_mutex_init; + + QUEUE_INIT(&state->fsevent_handles); + state->fsevent_need_reschedule = 0; + state->fsevent_handle_count = 0; + + memset(&ctx, 0, sizeof(ctx)); + ctx.info = loop; + ctx.perform = uv__cf_loop_cb; + state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx); + if (state->signal_source == NULL) { + err = -ENOMEM; + goto fail_signal_source_create; + } + + /* In the unlikely event that pthread_attr_init() fails, create the thread + * with the default stack size. We'll use a little more address space but + * that in itself is not a fatal error. + */ + attr = &attr_storage; + if (pthread_attr_init(attr)) + attr = NULL; + + if (attr != NULL) + if (pthread_attr_setstacksize(attr, 4 * PTHREAD_STACK_MIN)) + abort(); + + loop->cf_state = state; + + /* uv_thread_t is an alias for pthread_t. */ + err = -pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop); + + if (attr != NULL) + pthread_attr_destroy(attr); + + if (err) + goto fail_thread_create; + + /* Synchronize threads */ + uv_sem_wait(&loop->cf_sem); + return 0; + +fail_thread_create: + loop->cf_state = NULL; + +fail_signal_source_create: + uv_mutex_destroy(&state->fsevent_mutex); + +fail_fsevent_mutex_init: + uv_sem_destroy(&state->fsevent_sem); + +fail_fsevent_sem_init: + uv_sem_destroy(&loop->cf_sem); + +fail_sem_init: + uv_mutex_destroy(&loop->cf_mutex); + +fail_mutex_init: + uv__free(state); + return err; +} + + +/* Runs in UV loop */ +void uv__fsevents_loop_delete(uv_loop_t* loop) { + uv__cf_loop_signal_t* s; + uv__cf_loop_state_t* state; + QUEUE* q; + + if (loop->cf_state == NULL) + return; + + if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0) + abort(); + + uv_thread_join(&loop->cf_thread); + uv_sem_destroy(&loop->cf_sem); + uv_mutex_destroy(&loop->cf_mutex); + + /* Free any remaining data */ + while (!QUEUE_EMPTY(&loop->cf_signals)) { + q = QUEUE_HEAD(&loop->cf_signals); + s = QUEUE_DATA(q, uv__cf_loop_signal_t, member); + QUEUE_REMOVE(q); + uv__free(s); + } + + /* Destroy state */ + state = loop->cf_state; + uv_sem_destroy(&state->fsevent_sem); + uv_mutex_destroy(&state->fsevent_mutex); + pCFRelease(state->signal_source); + uv__free(state); + loop->cf_state = NULL; +} + + +/* Runs in CF thread. This is the CF loop's body */ +static void* uv__cf_loop_runner(void* arg) { + uv_loop_t* loop; + uv__cf_loop_state_t* state; + + loop = arg; + state = loop->cf_state; + state->loop = pCFRunLoopGetCurrent(); + + pCFRunLoopAddSource(state->loop, + state->signal_source, + *pkCFRunLoopDefaultMode); + + uv_sem_post(&loop->cf_sem); + + pCFRunLoopRun(); + pCFRunLoopRemoveSource(state->loop, + state->signal_source, + *pkCFRunLoopDefaultMode); + + return NULL; +} + + +/* Runs in CF thread, executed after `uv__cf_loop_signal()` */ +static void uv__cf_loop_cb(void* arg) { + uv_loop_t* loop; + uv__cf_loop_state_t* state; + QUEUE* item; + QUEUE split_head; + uv__cf_loop_signal_t* s; + + loop = arg; + state = loop->cf_state; + + uv_mutex_lock(&loop->cf_mutex); + QUEUE_MOVE(&loop->cf_signals, &split_head); + uv_mutex_unlock(&loop->cf_mutex); + + while (!QUEUE_EMPTY(&split_head)) { + item = QUEUE_HEAD(&split_head); + QUEUE_REMOVE(item); + + s = QUEUE_DATA(item, uv__cf_loop_signal_t, member); + + /* This was a termination signal */ + if (s->handle == NULL) + pCFRunLoopStop(state->loop); + else + uv__fsevents_reschedule(s->handle, s->type); + + uv__free(s); + } +} + + +/* Runs in UV loop to notify CF thread */ +int uv__cf_loop_signal(uv_loop_t* loop, + uv_fs_event_t* handle, + uv__cf_loop_signal_type_t type) { + uv__cf_loop_signal_t* item; + uv__cf_loop_state_t* state; + + item = uv__malloc(sizeof(*item)); + if (item == NULL) + return -ENOMEM; + + item->handle = handle; + item->type = type; + + uv_mutex_lock(&loop->cf_mutex); + QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member); + uv_mutex_unlock(&loop->cf_mutex); + + state = loop->cf_state; + assert(state != NULL); + pCFRunLoopSourceSignal(state->signal_source); + pCFRunLoopWakeUp(state->loop); + + return 0; +} + + +/* Runs in UV loop to initialize handle */ +int uv__fsevents_init(uv_fs_event_t* handle) { + int err; + uv__cf_loop_state_t* state; + + err = uv__fsevents_loop_init(handle->loop); + if (err) + return err; + + /* Get absolute path to file */ + handle->realpath = realpath(handle->path, NULL); + if (handle->realpath == NULL) + return -errno; + handle->realpath_len = strlen(handle->realpath); + + /* Initialize event queue */ + QUEUE_INIT(&handle->cf_events); + handle->cf_error = 0; + + /* + * Events will occur in other thread. + * Initialize callback for getting them back into event loop's thread + */ + handle->cf_cb = uv__malloc(sizeof(*handle->cf_cb)); + if (handle->cf_cb == NULL) { + err = -ENOMEM; + goto fail_cf_cb_malloc; + } + + handle->cf_cb->data = handle; + uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb); + handle->cf_cb->flags |= UV__HANDLE_INTERNAL; + uv_unref((uv_handle_t*) handle->cf_cb); + + err = uv_mutex_init(&handle->cf_mutex); + if (err) + goto fail_cf_mutex_init; + + /* Insert handle into the list */ + state = handle->loop->cf_state; + uv_mutex_lock(&state->fsevent_mutex); + QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member); + state->fsevent_handle_count++; + state->fsevent_need_reschedule = 1; + uv_mutex_unlock(&state->fsevent_mutex); + + /* Reschedule FSEventStream */ + assert(handle != NULL); + err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular); + if (err) + goto fail_loop_signal; + + return 0; + +fail_loop_signal: + uv_mutex_destroy(&handle->cf_mutex); + +fail_cf_mutex_init: + uv__free(handle->cf_cb); + handle->cf_cb = NULL; + +fail_cf_cb_malloc: + uv__free(handle->realpath); + handle->realpath = NULL; + handle->realpath_len = 0; + + return err; +} + + +/* Runs in UV loop to de-initialize handle */ +int uv__fsevents_close(uv_fs_event_t* handle) { + int err; + uv__cf_loop_state_t* state; + + if (handle->cf_cb == NULL) + return -EINVAL; + + /* Remove handle from the list */ + state = handle->loop->cf_state; + uv_mutex_lock(&state->fsevent_mutex); + QUEUE_REMOVE(&handle->cf_member); + state->fsevent_handle_count--; + state->fsevent_need_reschedule = 1; + uv_mutex_unlock(&state->fsevent_mutex); + + /* Reschedule FSEventStream */ + assert(handle != NULL); + err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing); + if (err) + return -err; + + /* Wait for deinitialization */ + uv_sem_wait(&state->fsevent_sem); + + uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) uv__free); + handle->cf_cb = NULL; + + /* Free data in queue */ + UV__FSEVENTS_PROCESS(handle, { + /* NOP */ + }); + + uv_mutex_destroy(&handle->cf_mutex); + uv__free(handle->realpath); + handle->realpath = NULL; + handle->realpath_len = 0; + + return 0; +} + +#endif /* TARGET_OS_IPHONE */ diff --git a/src/unix/getaddrinfo.c b/src/unix/getaddrinfo.c new file mode 100644 index 0000000..2049aea --- /dev/null +++ b/src/unix/getaddrinfo.c @@ -0,0 +1,202 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +/* Expose glibc-specific EAI_* error codes. Needs to be defined before we + * include any headers. + */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include "uv.h" +#include "internal.h" + +#include +#include /* NULL */ +#include +#include + +/* EAI_* constants. */ +#include + + +int uv__getaddrinfo_translate_error(int sys_err) { + switch (sys_err) { + case 0: return 0; +#if defined(EAI_ADDRFAMILY) + case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY; +#endif +#if defined(EAI_AGAIN) + case EAI_AGAIN: return UV_EAI_AGAIN; +#endif +#if defined(EAI_BADFLAGS) + case EAI_BADFLAGS: return UV_EAI_BADFLAGS; +#endif +#if defined(EAI_BADHINTS) + case EAI_BADHINTS: return UV_EAI_BADHINTS; +#endif +#if defined(EAI_CANCELED) + case EAI_CANCELED: return UV_EAI_CANCELED; +#endif +#if defined(EAI_FAIL) + case EAI_FAIL: return UV_EAI_FAIL; +#endif +#if defined(EAI_FAMILY) + case EAI_FAMILY: return UV_EAI_FAMILY; +#endif +#if defined(EAI_MEMORY) + case EAI_MEMORY: return UV_EAI_MEMORY; +#endif +#if defined(EAI_NODATA) + case EAI_NODATA: return UV_EAI_NODATA; +#endif +#if defined(EAI_NONAME) +# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME + case EAI_NONAME: return UV_EAI_NONAME; +# endif +#endif +#if defined(EAI_OVERFLOW) + case EAI_OVERFLOW: return UV_EAI_OVERFLOW; +#endif +#if defined(EAI_PROTOCOL) + case EAI_PROTOCOL: return UV_EAI_PROTOCOL; +#endif +#if defined(EAI_SERVICE) + case EAI_SERVICE: return UV_EAI_SERVICE; +#endif +#if defined(EAI_SOCKTYPE) + case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE; +#endif +#if defined(EAI_SYSTEM) + case EAI_SYSTEM: return -errno; +#endif + } + assert(!"unknown EAI_* error code"); + abort(); + return 0; /* Pacify compiler. */ +} + + +static void uv__getaddrinfo_work(struct uv__work* w) { + uv_getaddrinfo_t* req; + int err; + + req = container_of(w, uv_getaddrinfo_t, work_req); + err = getaddrinfo(req->hostname, req->service, req->hints, &req->addrinfo); + req->retcode = uv__getaddrinfo_translate_error(err); +} + + +static void uv__getaddrinfo_done(struct uv__work* w, int status) { + uv_getaddrinfo_t* req; + + req = container_of(w, uv_getaddrinfo_t, work_req); + uv__req_unregister(req->loop, req); + + /* See initialization in uv_getaddrinfo(). */ + if (req->hints) + uv__free(req->hints); + else if (req->service) + uv__free(req->service); + else if (req->hostname) + uv__free(req->hostname); + else + assert(0); + + req->hints = NULL; + req->service = NULL; + req->hostname = NULL; + + if (status == -ECANCELED) { + assert(req->retcode == 0); + req->retcode = UV_EAI_CANCELED; + } + + if (req->cb) + req->cb(req, req->retcode, req->addrinfo); +} + + +int uv_getaddrinfo(uv_loop_t* loop, + uv_getaddrinfo_t* req, + uv_getaddrinfo_cb cb, + const char* hostname, + const char* service, + const struct addrinfo* hints) { + size_t hostname_len; + size_t service_len; + size_t hints_len; + size_t len; + char* buf; + + if (req == NULL || (hostname == NULL && service == NULL)) + return -EINVAL; + + hostname_len = hostname ? strlen(hostname) + 1 : 0; + service_len = service ? strlen(service) + 1 : 0; + hints_len = hints ? sizeof(*hints) : 0; + buf = uv__malloc(hostname_len + service_len + hints_len); + + if (buf == NULL) + return -ENOMEM; + + uv__req_init(loop, req, UV_GETADDRINFO); + req->loop = loop; + req->cb = cb; + req->addrinfo = NULL; + req->hints = NULL; + req->service = NULL; + req->hostname = NULL; + req->retcode = 0; + + /* order matters, see uv_getaddrinfo_done() */ + len = 0; + + if (hints) { + req->hints = memcpy(buf + len, hints, sizeof(*hints)); + len += sizeof(*hints); + } + + if (service) { + req->service = memcpy(buf + len, service, service_len); + len += service_len; + } + + if (hostname) + req->hostname = memcpy(buf + len, hostname, hostname_len); + + if (cb) { + uv__work_submit(loop, + &req->work_req, + uv__getaddrinfo_work, + uv__getaddrinfo_done); + return 0; + } else { + uv__getaddrinfo_work(&req->work_req); + uv__getaddrinfo_done(&req->work_req, 0); + return req->retcode; + } +} + + +void uv_freeaddrinfo(struct addrinfo* ai) { + if (ai) + freeaddrinfo(ai); +} diff --git a/src/unix/getnameinfo.c b/src/unix/getnameinfo.c new file mode 100644 index 0000000..daa798a --- /dev/null +++ b/src/unix/getnameinfo.c @@ -0,0 +1,120 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. +* +* 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. +*/ + +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" + + +static void uv__getnameinfo_work(struct uv__work* w) { + uv_getnameinfo_t* req; + int err; + socklen_t salen; + + req = container_of(w, uv_getnameinfo_t, work_req); + + if (req->storage.ss_family == AF_INET) + salen = sizeof(struct sockaddr_in); + else if (req->storage.ss_family == AF_INET6) + salen = sizeof(struct sockaddr_in6); + else + abort(); + + err = getnameinfo((struct sockaddr*) &req->storage, + salen, + req->host, + sizeof(req->host), + req->service, + sizeof(req->service), + req->flags); + req->retcode = uv__getaddrinfo_translate_error(err); +} + +static void uv__getnameinfo_done(struct uv__work* w, int status) { + uv_getnameinfo_t* req; + char* host; + char* service; + + req = container_of(w, uv_getnameinfo_t, work_req); + uv__req_unregister(req->loop, req); + host = service = NULL; + + if (status == -ECANCELED) { + assert(req->retcode == 0); + req->retcode = UV_EAI_CANCELED; + } else if (req->retcode == 0) { + host = req->host; + service = req->service; + } + + if (req->getnameinfo_cb) + req->getnameinfo_cb(req, req->retcode, host, service); +} + +/* +* Entry point for getnameinfo +* return 0 if a callback will be made +* return error code if validation fails +*/ +int uv_getnameinfo(uv_loop_t* loop, + uv_getnameinfo_t* req, + uv_getnameinfo_cb getnameinfo_cb, + const struct sockaddr* addr, + int flags) { + if (req == NULL || addr == NULL) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) { + memcpy(&req->storage, + addr, + sizeof(struct sockaddr_in)); + } else if (addr->sa_family == AF_INET6) { + memcpy(&req->storage, + addr, + sizeof(struct sockaddr_in6)); + } else { + return UV_EINVAL; + } + + uv__req_init(loop, (uv_req_t*)req, UV_GETNAMEINFO); + + req->getnameinfo_cb = getnameinfo_cb; + req->flags = flags; + req->type = UV_GETNAMEINFO; + req->loop = loop; + req->retcode = 0; + + if (getnameinfo_cb) { + uv__work_submit(loop, + &req->work_req, + uv__getnameinfo_work, + uv__getnameinfo_done); + return 0; + } else { + uv__getnameinfo_work(&req->work_req); + uv__getnameinfo_done(&req->work_req, 0); + return req->retcode; + } +} diff --git a/src/unix/internal.h b/src/unix/internal.h new file mode 100644 index 0000000..c7b6019 --- /dev/null +++ b/src/unix/internal.h @@ -0,0 +1,325 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_UNIX_INTERNAL_H_ +#define UV_UNIX_INTERNAL_H_ + +#include "uv-common.h" + +#include +#include /* abort */ +#include /* strrchr */ +#include /* O_CLOEXEC, may be */ +#include + +#if defined(__STRICT_ANSI__) +# define inline __inline +#endif + +#if defined(__linux__) +# include "linux-syscalls.h" +#endif /* __linux__ */ + +#if defined(__sun) +# include +# include +#endif /* __sun */ + +#if defined(_AIX) +# define reqevents events +# define rtnevents revents +# include +#else +# include +#endif /* _AIX */ + +#if defined(__APPLE__) && !TARGET_OS_IPHONE +# include +#endif + +#if defined(__ANDROID__) +int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); +# ifdef pthread_sigmask +# undef pthread_sigmask +# endif +# define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset) +#endif + +#define ACCESS_ONCE(type, var) \ + (*(volatile type*) &(var)) + +#define ROUND_UP(a, b) \ + ((a) % (b) ? ((a) + (b)) - ((a) % (b)) : (a)) + +#define UNREACHABLE() \ + do { \ + assert(0 && "unreachable code"); \ + abort(); \ + } \ + while (0) + +#define SAVE_ERRNO(block) \ + do { \ + int _saved_errno = errno; \ + do { block; } while (0); \ + errno = _saved_errno; \ + } \ + while (0) + +/* The __clang__ and __INTEL_COMPILER checks are superfluous because they + * define __GNUC__. They are here to convey to you, dear reader, that these + * macros are enabled when compiling with clang or icc. + */ +#if defined(__clang__) || \ + defined(__GNUC__) || \ + defined(__INTEL_COMPILER) || \ + defined(__SUNPRO_C) +# define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration +# define UV_UNUSED(declaration) __attribute__((unused)) declaration +#else +# define UV_DESTRUCTOR(declaration) declaration +# define UV_UNUSED(declaration) declaration +#endif + +/* Leans on the fact that, on Linux, POLLRDHUP == EPOLLRDHUP. */ +#ifdef POLLRDHUP +# define UV__POLLRDHUP POLLRDHUP +#else +# define UV__POLLRDHUP 0x2000 +#endif + +#if !defined(O_CLOEXEC) && defined(__FreeBSD__) +/* + * It may be that we are just missing `__POSIX_VISIBLE >= 200809`. + * Try using fixed value const and give up, if it doesn't work + */ +# define O_CLOEXEC 0x00100000 +#endif + +typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t; + +/* handle flags */ +enum { + UV_CLOSING = 0x01, /* uv_close() called but not finished. */ + UV_CLOSED = 0x02, /* close(2) finished. */ + UV_STREAM_READING = 0x04, /* uv_read_start() called. */ + UV_STREAM_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */ + UV_STREAM_SHUT = 0x10, /* Write side closed. */ + UV_STREAM_READABLE = 0x20, /* The stream is readable */ + UV_STREAM_WRITABLE = 0x40, /* The stream is writable */ + UV_STREAM_BLOCKING = 0x80, /* Synchronous writes. */ + UV_STREAM_READ_PARTIAL = 0x100, /* read(2) read less than requested. */ + UV_STREAM_READ_EOF = 0x200, /* read(2) read EOF. */ + UV_TCP_NODELAY = 0x400, /* Disable Nagle. */ + UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */ + UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */ + UV_HANDLE_IPV6 = 0x10000, /* Handle is bound to a IPv6 socket. */ + UV_UDP_PROCESSING = 0x20000, /* Handle is running the send callback queue. */ + UV_HANDLE_BOUND = 0x40000 /* Handle is bound to an address and port */ +}; + +/* loop flags */ +enum { + UV_LOOP_BLOCK_SIGPROF = 1 +}; + +typedef enum { + UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */ + UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */ +} uv_clocktype_t; + +struct uv__stream_queued_fds_s { + unsigned int size; + unsigned int offset; + int fds[1]; +}; + + +#if defined(_AIX) || \ + defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__linux__) +#define uv__cloexec uv__cloexec_ioctl +#define uv__nonblock uv__nonblock_ioctl +#else +#define uv__cloexec uv__cloexec_fcntl +#define uv__nonblock uv__nonblock_fcntl +#endif + +/* core */ +int uv__cloexec_ioctl(int fd, int set); +int uv__cloexec_fcntl(int fd, int set); +int uv__nonblock_ioctl(int fd, int set); +int uv__nonblock_fcntl(int fd, int set); +int uv__close(int fd); +int uv__close_nocheckstdio(int fd); +int uv__socket(int domain, int type, int protocol); +int uv__dup(int fd); +ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags); +void uv__make_close_pending(uv_handle_t* handle); +int uv__getiovmax(void); + +void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd); +void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__io_close(uv_loop_t* loop, uv__io_t* w); +void uv__io_feed(uv_loop_t* loop, uv__io_t* w); +int uv__io_active(const uv__io_t* w, unsigned int events); +int uv__io_check_fd(uv_loop_t* loop, int fd); +void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */ + +/* async */ +void uv__async_send(struct uv__async* wa); +void uv__async_init(struct uv__async* wa); +int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb); +void uv__async_stop(uv_loop_t* loop, struct uv__async* wa); + +/* loop */ +void uv__run_idle(uv_loop_t* loop); +void uv__run_check(uv_loop_t* loop); +void uv__run_prepare(uv_loop_t* loop); + +/* stream */ +void uv__stream_init(uv_loop_t* loop, uv_stream_t* stream, + uv_handle_type type); +int uv__stream_open(uv_stream_t*, int fd, int flags); +void uv__stream_destroy(uv_stream_t* stream); +#if defined(__APPLE__) +int uv__stream_try_select(uv_stream_t* stream, int* fd); +#endif /* defined(__APPLE__) */ +void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); +int uv__accept(int sockfd); +int uv__dup2_cloexec(int oldfd, int newfd); +int uv__open_cloexec(const char* path, int flags); + +/* tcp */ +int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb); +int uv__tcp_nodelay(int fd, int on); +int uv__tcp_keepalive(int fd, int on, unsigned int delay); + +/* pipe */ +int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); + +/* timer */ +void uv__run_timers(uv_loop_t* loop); +int uv__next_timeout(const uv_loop_t* loop); + +/* signal */ +void uv__signal_close(uv_signal_t* handle); +void uv__signal_global_once_init(void); +void uv__signal_loop_cleanup(uv_loop_t* loop); + +/* platform specific */ +uint64_t uv__hrtime(uv_clocktype_t type); +int uv__kqueue_init(uv_loop_t* loop); +int uv__platform_loop_init(uv_loop_t* loop); +void uv__platform_loop_delete(uv_loop_t* loop); +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd); + +/* various */ +void uv__async_close(uv_async_t* handle); +void uv__check_close(uv_check_t* handle); +void uv__fs_event_close(uv_fs_event_t* handle); +void uv__idle_close(uv_idle_t* handle); +void uv__pipe_close(uv_pipe_t* handle); +void uv__poll_close(uv_poll_t* handle); +void uv__prepare_close(uv_prepare_t* handle); +void uv__process_close(uv_process_t* handle); +void uv__stream_close(uv_stream_t* handle); +void uv__tcp_close(uv_tcp_t* handle); +void uv__timer_close(uv_timer_t* handle); +void uv__udp_close(uv_udp_t* handle); +void uv__udp_finish_close(uv_udp_t* handle); +uv_handle_type uv__handle_type(int fd); +FILE* uv__open_file(const char* path); +int uv__getpwuid_r(uv_passwd_t* pwd); + + +#if defined(__APPLE__) +int uv___stream_fd(const uv_stream_t* handle); +#define uv__stream_fd(handle) (uv___stream_fd((const uv_stream_t*) (handle))) +#else +#define uv__stream_fd(handle) ((handle)->io_watcher.fd) +#endif /* defined(__APPLE__) */ + +#ifdef UV__O_NONBLOCK +# define UV__F_NONBLOCK UV__O_NONBLOCK +#else +# define UV__F_NONBLOCK 1 +#endif + +int uv__make_socketpair(int fds[2], int flags); +int uv__make_pipe(int fds[2], int flags); + +#if defined(__APPLE__) + +int uv__fsevents_init(uv_fs_event_t* handle); +int uv__fsevents_close(uv_fs_event_t* handle); +void uv__fsevents_loop_delete(uv_loop_t* loop); + +/* OSX < 10.7 has no file events, polyfill them */ +#ifndef MAC_OS_X_VERSION_10_7 + +static const int kFSEventStreamCreateFlagFileEvents = 0x00000010; +static const int kFSEventStreamEventFlagItemCreated = 0x00000100; +static const int kFSEventStreamEventFlagItemRemoved = 0x00000200; +static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400; +static const int kFSEventStreamEventFlagItemRenamed = 0x00000800; +static const int kFSEventStreamEventFlagItemModified = 0x00001000; +static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000; +static const int kFSEventStreamEventFlagItemChangeOwner = 0x00004000; +static const int kFSEventStreamEventFlagItemXattrMod = 0x00008000; +static const int kFSEventStreamEventFlagItemIsFile = 0x00010000; +static const int kFSEventStreamEventFlagItemIsDir = 0x00020000; +static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000; + +#endif /* __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 */ + +#endif /* defined(__APPLE__) */ + +UV_UNUSED(static void uv__req_init(uv_loop_t* loop, + uv_req_t* req, + uv_req_type type)) { + req->type = type; + uv__req_register(loop, req); +} +#define uv__req_init(loop, req, type) \ + uv__req_init((loop), (uv_req_t*)(req), (type)) + +UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) { + /* Use a fast time source if available. We only need millisecond precision. + */ + loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000; +} + +UV_UNUSED(static char* uv__basename_r(const char* path)) { + char* s; + + s = strrchr(path, '/'); + if (s == NULL) + return (char*) path; + + return s + 1; +} + +#endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c new file mode 100644 index 0000000..fffd462 --- /dev/null +++ b/src/unix/kqueue.c @@ -0,0 +1,463 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags); + + +int uv__kqueue_init(uv_loop_t* loop) { + loop->backend_fd = kqueue(); + if (loop->backend_fd == -1) + return -errno; + + uv__cloexec(loop->backend_fd, 1); + + return 0; +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct kevent ev; + int rc; + + rc = 0; + EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + rc = -errno; + + EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); + if (rc == 0) + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + abort(); + + return rc; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + struct kevent events[1024]; + struct kevent* ev; + struct timespec spec; + unsigned int nevents; + unsigned int revents; + QUEUE* q; + uv__io_t* w; + sigset_t* pset; + sigset_t set; + uint64_t base; + uint64_t diff; + int have_signals; + int filter; + int fflags; + int count; + int nfds; + int fd; + int op; + int i; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + nevents = 0; + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + assert(w->fd >= 0); + assert(w->fd < (int) loop->nwatchers); + + if ((w->events & POLLIN) == 0 && (w->pevents & POLLIN) != 0) { + filter = EVFILT_READ; + fflags = 0; + op = EV_ADD; + + if (w->cb == uv__fs_event) { + filter = EVFILT_VNODE; + fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME + | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE; + op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */ + } + + EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0); + + if (++nevents == ARRAY_SIZE(events)) { + if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) + abort(); + nevents = 0; + } + } + + if ((w->events & POLLOUT) == 0 && (w->pevents & POLLOUT) != 0) { + EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); + + if (++nevents == ARRAY_SIZE(events)) { + if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) + abort(); + nevents = 0; + } + } + + w->events = w->pevents; + } + + pset = NULL; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + pset = &set; + sigemptyset(pset); + sigaddset(pset, SIGPROF); + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + + for (;; nevents = 0) { + if (timeout != -1) { + spec.tv_sec = timeout / 1000; + spec.tv_nsec = (timeout % 1000) * 1000000; + } + + if (pset != NULL) + pthread_sigmask(SIG_BLOCK, pset, NULL); + + nfds = kevent(loop->backend_fd, + events, + nevents, + events, + ARRAY_SIZE(events), + timeout == -1 ? NULL : &spec); + + if (pset != NULL) + pthread_sigmask(SIG_UNBLOCK, pset, NULL); + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (nfds == 0) { + assert(timeout != -1); + return; + } + + if (nfds == -1) { + if (errno != EINTR) + abort(); + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + have_signals = 0; + nevents = 0; + + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + for (i = 0; i < nfds; i++) { + ev = events + i; + fd = ev->ident; + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (fd == -1) + continue; + w = loop->watchers[fd]; + + if (w == NULL) { + /* File descriptor that we've stopped watching, disarm it. */ + /* TODO batch up */ + struct kevent events[1]; + + EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); + if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) + if (errno != EBADF && errno != ENOENT) + abort(); + + continue; + } + + if (ev->filter == EVFILT_VNODE) { + assert(w->events == POLLIN); + assert(w->pevents == POLLIN); + w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */ + nevents++; + continue; + } + + revents = 0; + + if (ev->filter == EVFILT_READ) { + if (w->pevents & POLLIN) { + revents |= POLLIN; + w->rcount = ev->data; + } else { + /* TODO batch up */ + struct kevent events[1]; + EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); + if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) + if (errno != ENOENT) + abort(); + } + } + + if (ev->filter == EVFILT_WRITE) { + if (w->pevents & POLLOUT) { + revents |= POLLOUT; + w->wcount = ev->data; + } else { + /* TODO batch up */ + struct kevent events[1]; + EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); + if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) + if (errno != ENOENT) + abort(); + } + } + + if (ev->flags & EV_ERROR) + revents |= POLLERR; + + if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP)) + revents |= UV__POLLRDHUP; + + if (revents == 0) + continue; + + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, revents); + + nevents++; + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + diff = loop->time - base; + if (diff >= (uint64_t) timeout) + return; + + timeout -= diff; + } +} + + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct kevent* events; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + + events = (struct kevent*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + if (events == NULL) + return; + + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].ident == fd) + events[i].ident = -1; +} + + +static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) { + uv_fs_event_t* handle; + struct kevent ev; + int events; + const char* path; +#if defined(F_GETPATH) + /* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */ + char pathbuf[MAXPATHLEN]; +#endif + + handle = container_of(w, uv_fs_event_t, event_watcher); + + if (fflags & (NOTE_ATTRIB | NOTE_EXTEND)) + events = UV_CHANGE; + else + events = UV_RENAME; + + path = NULL; +#if defined(F_GETPATH) + /* Also works when the file has been unlinked from the file system. Passing + * in the path when the file has been deleted is arguably a little strange + * but it's consistent with what the inotify backend does. + */ + if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0) + path = uv__basename_r(pathbuf); +#endif + handle->cb(handle, path, events, 0); + + if (handle->event_watcher.fd == -1) + return; + + /* Watcher operates in one-shot mode, re-arm it. */ + fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME + | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE; + + EV_SET(&ev, w->fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, fflags, 0, 0); + + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + abort(); +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + return 0; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* path, + unsigned int flags) { +#if defined(__APPLE__) + struct stat statbuf; +#endif /* defined(__APPLE__) */ + int fd; + + if (uv__is_active(handle)) + return -EINVAL; + + /* TODO open asynchronously - but how do we report back errors? */ + fd = open(path, O_RDONLY); + if (fd == -1) + return -errno; + + uv__handle_start(handle); + uv__io_init(&handle->event_watcher, uv__fs_event, fd); + handle->path = uv__strdup(path); + handle->cb = cb; + +#if defined(__APPLE__) + /* Nullify field to perform checks later */ + handle->cf_cb = NULL; + handle->realpath = NULL; + handle->realpath_len = 0; + handle->cf_flags = flags; + + if (fstat(fd, &statbuf)) + goto fallback; + /* FSEvents works only with directories */ + if (!(statbuf.st_mode & S_IFDIR)) + goto fallback; + + /* The fallback fd is no longer needed */ + uv__close(fd); + handle->event_watcher.fd = -1; + + return uv__fsevents_init(handle); + +fallback: +#endif /* defined(__APPLE__) */ + + uv__io_start(handle->loop, &handle->event_watcher, POLLIN); + + return 0; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + if (!uv__is_active(handle)) + return 0; + + uv__handle_stop(handle); + +#if defined(__APPLE__) + if (uv__fsevents_close(handle)) +#endif /* defined(__APPLE__) */ + { + uv__io_close(handle->loop, &handle->event_watcher); + } + + uv__free(handle->path); + handle->path = NULL; + + if (handle->event_watcher.fd != -1) { + /* When FSEvents is used, we don't use the event_watcher's fd under certain + * confitions. (see uv_fs_event_start) */ + uv__close(handle->event_watcher.fd); + handle->event_watcher.fd = -1; + } + + return 0; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + uv_fs_event_stop(handle); +} diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c new file mode 100644 index 0000000..58dd813 --- /dev/null +++ b/src/unix/linux-core.c @@ -0,0 +1,985 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their + * EPOLL* counterparts. We use the POLL* variants in this file because that + * is what libuv uses elsewhere and it avoids a dependency on . + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define HAVE_IFADDRS_H 1 + +#ifdef __UCLIBC__ +# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32 +# undef HAVE_IFADDRS_H +# endif +#endif + +#ifdef HAVE_IFADDRS_H +# if defined(__ANDROID__) +# include "android-ifaddrs.h" +# else +# include +# endif +# include +# include +# include +#endif /* HAVE_IFADDRS_H */ + +/* Available from 2.6.32 onwards. */ +#ifndef CLOCK_MONOTONIC_COARSE +# define CLOCK_MONOTONIC_COARSE 6 +#endif + +/* This is rather annoying: CLOCK_BOOTTIME lives in but we can't + * include that file because it conflicts with . We'll just have to + * define it ourselves. + */ +#ifndef CLOCK_BOOTTIME +# define CLOCK_BOOTTIME 7 +#endif + +static int read_models(unsigned int numcpus, uv_cpu_info_t* ci); +static int read_times(FILE* statfile_fp, + unsigned int numcpus, + uv_cpu_info_t* ci); +static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); +static unsigned long read_cpufreq(unsigned int cpunum); + + +int uv__platform_loop_init(uv_loop_t* loop) { + int fd; + + fd = uv__epoll_create1(UV__EPOLL_CLOEXEC); + + /* epoll_create1() can fail either because it's not implemented (old kernel) + * or because it doesn't understand the EPOLL_CLOEXEC flag. + */ + if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) { + fd = uv__epoll_create(256); + + if (fd != -1) + uv__cloexec(fd, 1); + } + + loop->backend_fd = fd; + loop->inotify_fd = -1; + loop->inotify_watchers = NULL; + + if (fd == -1) + return -errno; + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->inotify_fd == -1) return; + uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN); + uv__close(loop->inotify_fd); + loop->inotify_fd = -1; +} + + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct uv__epoll_event* events; + struct uv__epoll_event dummy; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + + events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + if (events != NULL) + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].data == fd) + events[i].data = -1; + + /* Remove the file descriptor from the epoll. + * This avoids a problem where the same file description remains open + * in another process, causing repeated junk epoll events. + * + * We pass in a dummy epoll_event, to work around a bug in old kernels. + */ + if (loop->backend_fd >= 0) { + /* Work around a bug in kernels 3.10 to 3.19 where passing a struct that + * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings. + */ + memset(&dummy, 0, sizeof(dummy)); + uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy); + } +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct uv__epoll_event e; + int rc; + + e.events = POLLIN; + e.data = -1; + + rc = 0; + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e)) + if (errno != EEXIST) + rc = -errno; + + if (rc == 0) + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e)) + abort(); + + return rc; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes + * effectively infinite on 32 bits architectures. To avoid blocking + * indefinitely, we cap the timeout and poll again if necessary. + * + * Note that "30 minutes" is a simplification because it depends on + * the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200, + * that being the largest value I have seen in the wild (and only once.) + */ + static const int max_safe_timeout = 1789569; + static int no_epoll_pwait; + static int no_epoll_wait; + struct uv__epoll_event events[1024]; + struct uv__epoll_event* pe; + struct uv__epoll_event e; + int real_timeout; + QUEUE* q; + uv__io_t* w; + sigset_t sigset; + uint64_t sigmask; + uint64_t base; + int have_signals; + int nevents; + int count; + int nfds; + int fd; + int op; + int i; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + assert(w->fd >= 0); + assert(w->fd < (int) loop->nwatchers); + + e.events = w->pevents; + e.data = w->fd; + + if (w->events == 0) + op = UV__EPOLL_CTL_ADD; + else + op = UV__EPOLL_CTL_MOD; + + /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching + * events, skip the syscall and squelch the events after epoll_wait(). + */ + if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) { + if (errno != EEXIST) + abort(); + + assert(op == UV__EPOLL_CTL_ADD); + + /* We've reactivated a file descriptor that's been watched before. */ + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e)) + abort(); + } + + w->events = w->pevents; + } + + sigmask = 0; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + sigemptyset(&sigset); + sigaddset(&sigset, SIGPROF); + sigmask |= 1 << (SIGPROF - 1); + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + real_timeout = timeout; + + for (;;) { + /* See the comment for max_safe_timeout for an explanation of why + * this is necessary. Executive summary: kernel bug workaround. + */ + if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) + timeout = max_safe_timeout; + + if (sigmask != 0 && no_epoll_pwait != 0) + if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) + abort(); + + if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) { + nfds = uv__epoll_pwait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout, + sigmask); + if (nfds == -1 && errno == ENOSYS) + no_epoll_pwait = 1; + } else { + nfds = uv__epoll_wait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout); + if (nfds == -1 && errno == ENOSYS) + no_epoll_wait = 1; + } + + if (sigmask != 0 && no_epoll_pwait != 0) + if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL)) + abort(); + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (nfds == 0) { + assert(timeout != -1); + + if (timeout == 0) + return; + + /* We may have been inside the system call for longer than |timeout| + * milliseconds so we need to update the timestamp to avoid drift. + */ + goto update_timeout; + } + + if (nfds == -1) { + if (errno == ENOSYS) { + /* epoll_wait() or epoll_pwait() failed, try the other system call. */ + assert(no_epoll_wait == 0 || no_epoll_pwait == 0); + continue; + } + + if (errno != EINTR) + abort(); + + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + have_signals = 0; + nevents = 0; + + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + for (i = 0; i < nfds; i++) { + pe = events + i; + fd = pe->data; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (fd == -1) + continue; + + assert(fd >= 0); + assert((unsigned) fd < loop->nwatchers); + + w = loop->watchers[fd]; + + if (w == NULL) { + /* File descriptor that we've stopped watching, disarm it. + * + * Ignore all errors because we may be racing with another thread + * when the file descriptor is closed. + */ + uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe); + continue; + } + + /* Give users only events they're interested in. Prevents spurious + * callbacks when previous callback invocation in this loop has stopped + * the current watcher. Also, filters out events that users has not + * requested us to watch. + */ + pe->events &= w->pevents | POLLERR | POLLHUP; + + /* Work around an epoll quirk where it sometimes reports just the + * EPOLLERR or EPOLLHUP event. In order to force the event loop to + * move forward, we merge in the read/write events that the watcher + * is interested in; uv__read() and uv__write() will then deal with + * the error or hangup in the usual fashion. + * + * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user + * reads the available data, calls uv_read_stop(), then sometime later + * calls uv_read_start() again. By then, libuv has forgotten about the + * hangup and the kernel won't report EPOLLIN again because there's + * nothing left to read. If anything, libuv is to blame here. The + * current hack is just a quick bandaid; to properly fix it, libuv + * needs to remember the error/hangup event. We should get that for + * free when we switch over to edge-triggered I/O. + */ + if (pe->events == POLLERR || pe->events == POLLHUP) + pe->events |= w->pevents & (POLLIN | POLLOUT); + + if (pe->events != 0) { + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->events); + + nevents++; + } + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + real_timeout -= (loop->time - base); + if (real_timeout <= 0) + return; + + timeout = real_timeout; + } +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + static clock_t fast_clock_id = -1; + struct timespec t; + clock_t clock_id; + + /* Prefer CLOCK_MONOTONIC_COARSE if available but only when it has + * millisecond granularity or better. CLOCK_MONOTONIC_COARSE is + * serviced entirely from the vDSO, whereas CLOCK_MONOTONIC may + * decide to make a costly system call. + */ + /* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE + * when it has microsecond granularity or better (unlikely). + */ + if (type == UV_CLOCK_FAST && fast_clock_id == -1) { + if (clock_getres(CLOCK_MONOTONIC_COARSE, &t) == 0 && + t.tv_nsec <= 1 * 1000 * 1000) { + fast_clock_id = CLOCK_MONOTONIC_COARSE; + } else { + fast_clock_id = CLOCK_MONOTONIC; + } + } + + clock_id = CLOCK_MONOTONIC; + if (type == UV_CLOCK_FAST) + clock_id = fast_clock_id; + + if (clock_gettime(clock_id, &t)) + return 0; /* Not really possible. */ + + return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec; +} + + +void uv_loadavg(double avg[3]) { + struct sysinfo info; + + if (sysinfo(&info) < 0) return; + + avg[0] = (double) info.loads[0] / 65536.0; + avg[1] = (double) info.loads[1] / 65536.0; + avg[2] = (double) info.loads[2] / 65536.0; +} + + +int uv_exepath(char* buffer, size_t* size) { + ssize_t n; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + n = *size - 1; + if (n > 0) + n = readlink("/proc/self/exe", buffer, n); + + if (n == -1) + return -errno; + + buffer[n] = '\0'; + *size = n; + + return 0; +} + + +uint64_t uv_get_free_memory(void) { + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.freeram * info.mem_unit; + return 0; +} + + +uint64_t uv_get_total_memory(void) { + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.totalram * info.mem_unit; + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + char buf[1024]; + const char* s; + ssize_t n; + long val; + int fd; + int i; + + do + fd = open("/proc/self/stat", O_RDONLY); + while (fd == -1 && errno == EINTR); + + if (fd == -1) + return -errno; + + do + n = read(fd, buf, sizeof(buf) - 1); + while (n == -1 && errno == EINTR); + + uv__close(fd); + if (n == -1) + return -errno; + buf[n] = '\0'; + + s = strchr(buf, ' '); + if (s == NULL) + goto err; + + s += 1; + if (*s != '(') + goto err; + + s = strchr(s, ')'); + if (s == NULL) + goto err; + + for (i = 1; i <= 22; i++) { + s = strchr(s + 1, ' '); + if (s == NULL) + goto err; + } + + errno = 0; + val = strtol(s, NULL, 10); + if (errno != 0) + goto err; + if (val < 0) + goto err; + + *rss = val * getpagesize(); + return 0; + +err: + return -EINVAL; +} + + +int uv_uptime(double* uptime) { + static volatile int no_clock_boottime; + struct timespec now; + int r; + + /* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available + * (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system + * is suspended. + */ + if (no_clock_boottime) { + retry: r = clock_gettime(CLOCK_MONOTONIC, &now); + } + else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) { + no_clock_boottime = 1; + goto retry; + } + + if (r) + return -errno; + + *uptime = now.tv_sec; + return 0; +} + + +static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { + unsigned int num; + char buf[1024]; + + if (!fgets(buf, sizeof(buf), statfile_fp)) + return -EIO; + + num = 0; + while (fgets(buf, sizeof(buf), statfile_fp)) { + if (strncmp(buf, "cpu", 3)) + break; + num++; + } + + if (num == 0) + return -EIO; + + *numcpus = num; + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int numcpus; + uv_cpu_info_t* ci; + int err; + FILE* statfile_fp; + + *cpu_infos = NULL; + *count = 0; + + statfile_fp = uv__open_file("/proc/stat"); + if (statfile_fp == NULL) + return -errno; + + err = uv__cpu_num(statfile_fp, &numcpus); + if (err < 0) + goto out; + + err = -ENOMEM; + ci = uv__calloc(numcpus, sizeof(*ci)); + if (ci == NULL) + goto out; + + err = read_models(numcpus, ci); + if (err == 0) + err = read_times(statfile_fp, numcpus, ci); + + if (err) { + uv_free_cpu_info(ci, numcpus); + goto out; + } + + /* read_models() on x86 also reads the CPU speed from /proc/cpuinfo. + * We don't check for errors here. Worst case, the field is left zero. + */ + if (ci[0].speed == 0) + read_speeds(numcpus, ci); + + *cpu_infos = ci; + *count = numcpus; + err = 0; + +out: + + if (fclose(statfile_fp)) + if (errno != EINTR && errno != EINPROGRESS) + abort(); + + return err; +} + + +static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) { + unsigned int num; + + for (num = 0; num < numcpus; num++) + ci[num].speed = read_cpufreq(num) / 1000; +} + + +/* Also reads the CPU frequency on x86. The other architectures only have + * a BogoMIPS field, which may not be very accurate. + * + * Note: Simply returns on error, uv_cpu_info() takes care of the cleanup. + */ +static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { + static const char model_marker[] = "model name\t: "; + static const char speed_marker[] = "cpu MHz\t\t: "; + const char* inferred_model; + unsigned int model_idx; + unsigned int speed_idx; + char buf[1024]; + char* model; + FILE* fp; + + /* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */ + (void) &model_marker; + (void) &speed_marker; + (void) &speed_idx; + (void) &model; + (void) &buf; + (void) &fp; + + model_idx = 0; + speed_idx = 0; + +#if defined(__arm__) || \ + defined(__i386__) || \ + defined(__mips__) || \ + defined(__x86_64__) + fp = uv__open_file("/proc/cpuinfo"); + if (fp == NULL) + return -errno; + + while (fgets(buf, sizeof(buf), fp)) { + if (model_idx < numcpus) { + if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) { + model = buf + sizeof(model_marker) - 1; + model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */ + if (model == NULL) { + fclose(fp); + return -ENOMEM; + } + ci[model_idx++].model = model; + continue; + } + } +#if defined(__arm__) || defined(__mips__) + if (model_idx < numcpus) { +#if defined(__arm__) + /* Fallback for pre-3.8 kernels. */ + static const char model_marker[] = "Processor\t: "; +#else /* defined(__mips__) */ + static const char model_marker[] = "cpu model\t\t: "; +#endif + if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) { + model = buf + sizeof(model_marker) - 1; + model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */ + if (model == NULL) { + fclose(fp); + return -ENOMEM; + } + ci[model_idx++].model = model; + continue; + } + } +#else /* !__arm__ && !__mips__ */ + if (speed_idx < numcpus) { + if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) { + ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1); + continue; + } + } +#endif /* __arm__ || __mips__ */ + } + + fclose(fp); +#endif /* __arm__ || __i386__ || __mips__ || __x86_64__ */ + + /* Now we want to make sure that all the models contain *something* because + * it's not safe to leave them as null. Copy the last entry unless there + * isn't one, in that case we simply put "unknown" into everything. + */ + inferred_model = "unknown"; + if (model_idx > 0) + inferred_model = ci[model_idx - 1].model; + + while (model_idx < numcpus) { + model = uv__strndup(inferred_model, strlen(inferred_model)); + if (model == NULL) + return -ENOMEM; + ci[model_idx++].model = model; + } + + return 0; +} + + +static int read_times(FILE* statfile_fp, + unsigned int numcpus, + uv_cpu_info_t* ci) { + unsigned long clock_ticks; + struct uv_cpu_times_s ts; + unsigned long user; + unsigned long nice; + unsigned long sys; + unsigned long idle; + unsigned long dummy; + unsigned long irq; + unsigned int num; + unsigned int len; + char buf[1024]; + + clock_ticks = sysconf(_SC_CLK_TCK); + assert(clock_ticks != (unsigned long) -1); + assert(clock_ticks != 0); + + rewind(statfile_fp); + + if (!fgets(buf, sizeof(buf), statfile_fp)) + abort(); + + num = 0; + + while (fgets(buf, sizeof(buf), statfile_fp)) { + if (num >= numcpus) + break; + + if (strncmp(buf, "cpu", 3)) + break; + + /* skip "cpu " marker */ + { + unsigned int n; + int r = sscanf(buf, "cpu%u ", &n); + assert(r == 1); + (void) r; /* silence build warning */ + for (len = sizeof("cpu0"); n /= 10; len++); + } + + /* Line contains user, nice, system, idle, iowait, irq, softirq, steal, + * guest, guest_nice but we're only interested in the first four + irq. + * + * Don't use %*s to skip fields or %ll to read straight into the uint64_t + * fields, they're not allowed in C89 mode. + */ + if (6 != sscanf(buf + len, + "%lu %lu %lu %lu %lu %lu", + &user, + &nice, + &sys, + &idle, + &dummy, + &irq)) + abort(); + + ts.user = clock_ticks * user; + ts.nice = clock_ticks * nice; + ts.sys = clock_ticks * sys; + ts.idle = clock_ticks * idle; + ts.irq = clock_ticks * irq; + ci[num++].cpu_times = ts; + } + assert(num == numcpus); + + return 0; +} + + +static unsigned long read_cpufreq(unsigned int cpunum) { + unsigned long val; + char buf[1024]; + FILE* fp; + + snprintf(buf, + sizeof(buf), + "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", + cpunum); + + fp = uv__open_file(buf); + if (fp == NULL) + return 0; + + if (fscanf(fp, "%lu", &val) != 1) + val = 0; + + fclose(fp); + + return val; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, + int* count) { +#ifndef HAVE_IFADDRS_H + return -ENOSYS; +#else + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_ll *sll; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + *addresses = NULL; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family == PF_PACKET)) { + continue; + } + + (*count)++; + } + + if (*count == 0) + return 0; + + *addresses = uv__malloc(*count * sizeof(**addresses)); + if (!(*addresses)) { + freeifaddrs(addrs); + return -ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + /* + * On Linux getifaddrs returns information related to the raw underlying + * devices. We're not interested in this information yet. + */ + if (ent->ifa_addr->sa_family == PF_PACKET) + continue; + + address->name = uv__strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != PF_PACKET)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sll = (struct sockaddr_ll*)ent->ifa_addr; + memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +#endif +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(addresses[i].name); + } + + uv__free(addresses); +} + + +void uv__set_process_title(const char* title) { +#if defined(PR_SET_NAME) + prctl(PR_SET_NAME, title); /* Only copies first 16 characters. */ +#endif +} diff --git a/src/unix/linux-inotify.c b/src/unix/linux-inotify.c new file mode 100644 index 0000000..4708c05 --- /dev/null +++ b/src/unix/linux-inotify.c @@ -0,0 +1,285 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "tree.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +struct watcher_list { + RB_ENTRY(watcher_list) entry; + QUEUE watchers; + int iterating; + char* path; + int wd; +}; + +struct watcher_root { + struct watcher_list* rbh_root; +}; +#define CAST(p) ((struct watcher_root*)(p)) + + +static int compare_watchers(const struct watcher_list* a, + const struct watcher_list* b) { + if (a->wd < b->wd) return -1; + if (a->wd > b->wd) return 1; + return 0; +} + + +RB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers) + + +static void uv__inotify_read(uv_loop_t* loop, + uv__io_t* w, + unsigned int revents); + + +static int new_inotify_fd(void) { + int err; + int fd; + + fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC); + if (fd != -1) + return fd; + + if (errno != ENOSYS) + return -errno; + + fd = uv__inotify_init(); + if (fd == -1) + return -errno; + + err = uv__cloexec(fd, 1); + if (err == 0) + err = uv__nonblock(fd, 1); + + if (err) { + uv__close(fd); + return err; + } + + return fd; +} + + +static int init_inotify(uv_loop_t* loop) { + int err; + + if (loop->inotify_fd != -1) + return 0; + + err = new_inotify_fd(); + if (err < 0) + return err; + + loop->inotify_fd = err; + uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd); + uv__io_start(loop, &loop->inotify_read_watcher, POLLIN); + + return 0; +} + + +static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) { + struct watcher_list w; + w.wd = wd; + return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w); +} + +static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) { + /* if the watcher_list->watchers is being iterated over, we can't free it. */ + if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) { + /* No watchers left for this path. Clean up. */ + RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w); + uv__inotify_rm_watch(loop->inotify_fd, w->wd); + uv__free(w); + } +} + +static void uv__inotify_read(uv_loop_t* loop, + uv__io_t* dummy, + unsigned int events) { + const struct uv__inotify_event* e; + struct watcher_list* w; + uv_fs_event_t* h; + QUEUE queue; + QUEUE* q; + const char* path; + ssize_t size; + const char *p; + /* needs to be large enough for sizeof(inotify_event) + strlen(path) */ + char buf[4096]; + + while (1) { + do + size = read(loop->inotify_fd, buf, sizeof(buf)); + while (size == -1 && errno == EINTR); + + if (size == -1) { + assert(errno == EAGAIN || errno == EWOULDBLOCK); + break; + } + + assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */ + + /* Now we have one or more inotify_event structs. */ + for (p = buf; p < buf + size; p += sizeof(*e) + e->len) { + e = (const struct uv__inotify_event*)p; + + events = 0; + if (e->mask & (UV__IN_ATTRIB|UV__IN_MODIFY)) + events |= UV_CHANGE; + if (e->mask & ~(UV__IN_ATTRIB|UV__IN_MODIFY)) + events |= UV_RENAME; + + w = find_watcher(loop, e->wd); + if (w == NULL) + continue; /* Stale event, no watchers left. */ + + /* inotify does not return the filename when monitoring a single file + * for modifications. Repurpose the filename for API compatibility. + * I'm not convinced this is a good thing, maybe it should go. + */ + path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path); + + /* We're about to iterate over the queue and call user's callbacks. + * What can go wrong? + * A callback could call uv_fs_event_stop() + * and the queue can change under our feet. + * So, we use QUEUE_MOVE() trick to safely iterate over the queue. + * And we don't free the watcher_list until we're done iterating. + * + * First, + * tell uv_fs_event_stop() (that could be called from a user's callback) + * not to free watcher_list. + */ + w->iterating = 1; + QUEUE_MOVE(&w->watchers, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + h = QUEUE_DATA(q, uv_fs_event_t, watchers); + + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&w->watchers, q); + + h->cb(h, path, events, 0); + } + /* done iterating, time to (maybe) free empty watcher_list */ + w->iterating = 0; + maybe_free_watcher_list(w, loop); + } + } +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + return 0; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* path, + unsigned int flags) { + struct watcher_list* w; + int events; + int err; + int wd; + + if (uv__is_active(handle)) + return -EINVAL; + + err = init_inotify(handle->loop); + if (err) + return err; + + events = UV__IN_ATTRIB + | UV__IN_CREATE + | UV__IN_MODIFY + | UV__IN_DELETE + | UV__IN_DELETE_SELF + | UV__IN_MOVE_SELF + | UV__IN_MOVED_FROM + | UV__IN_MOVED_TO; + + wd = uv__inotify_add_watch(handle->loop->inotify_fd, path, events); + if (wd == -1) + return -errno; + + w = find_watcher(handle->loop, wd); + if (w) + goto no_insert; + + w = uv__malloc(sizeof(*w) + strlen(path) + 1); + if (w == NULL) + return -ENOMEM; + + w->wd = wd; + w->path = strcpy((char*)(w + 1), path); + QUEUE_INIT(&w->watchers); + w->iterating = 0; + RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w); + +no_insert: + uv__handle_start(handle); + QUEUE_INSERT_TAIL(&w->watchers, &handle->watchers); + handle->path = w->path; + handle->cb = cb; + handle->wd = wd; + + return 0; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + struct watcher_list* w; + + if (!uv__is_active(handle)) + return 0; + + w = find_watcher(handle->loop, handle->wd); + assert(w != NULL); + + handle->wd = -1; + handle->path = NULL; + uv__handle_stop(handle); + QUEUE_REMOVE(&handle->watchers); + + maybe_free_watcher_list(w, handle->loop); + + return 0; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + uv_fs_event_stop(handle); +} diff --git a/src/unix/linux-syscalls.c b/src/unix/linux-syscalls.c new file mode 100644 index 0000000..89998de --- /dev/null +++ b/src/unix/linux-syscalls.c @@ -0,0 +1,471 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "linux-syscalls.h" +#include +#include +#include +#include +#include + +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# define MSAN_ACTIVE 1 +# include +# endif +#endif + +#if defined(__i386__) +# ifndef __NR_socketcall +# define __NR_socketcall 102 +# endif +#endif + +#if defined(__arm__) +# if defined(__thumb__) || defined(__ARM_EABI__) +# define UV_SYSCALL_BASE 0 +# else +# define UV_SYSCALL_BASE 0x900000 +# endif +#endif /* __arm__ */ + +#ifndef __NR_accept4 +# if defined(__x86_64__) +# define __NR_accept4 288 +# elif defined(__i386__) + /* Nothing. Handled through socketcall(). */ +# elif defined(__arm__) +# define __NR_accept4 (UV_SYSCALL_BASE + 366) +# endif +#endif /* __NR_accept4 */ + +#ifndef __NR_eventfd +# if defined(__x86_64__) +# define __NR_eventfd 284 +# elif defined(__i386__) +# define __NR_eventfd 323 +# elif defined(__arm__) +# define __NR_eventfd (UV_SYSCALL_BASE + 351) +# endif +#endif /* __NR_eventfd */ + +#ifndef __NR_eventfd2 +# if defined(__x86_64__) +# define __NR_eventfd2 290 +# elif defined(__i386__) +# define __NR_eventfd2 328 +# elif defined(__arm__) +# define __NR_eventfd2 (UV_SYSCALL_BASE + 356) +# endif +#endif /* __NR_eventfd2 */ + +#ifndef __NR_epoll_create +# if defined(__x86_64__) +# define __NR_epoll_create 213 +# elif defined(__i386__) +# define __NR_epoll_create 254 +# elif defined(__arm__) +# define __NR_epoll_create (UV_SYSCALL_BASE + 250) +# endif +#endif /* __NR_epoll_create */ + +#ifndef __NR_epoll_create1 +# if defined(__x86_64__) +# define __NR_epoll_create1 291 +# elif defined(__i386__) +# define __NR_epoll_create1 329 +# elif defined(__arm__) +# define __NR_epoll_create1 (UV_SYSCALL_BASE + 357) +# endif +#endif /* __NR_epoll_create1 */ + +#ifndef __NR_epoll_ctl +# if defined(__x86_64__) +# define __NR_epoll_ctl 233 /* used to be 214 */ +# elif defined(__i386__) +# define __NR_epoll_ctl 255 +# elif defined(__arm__) +# define __NR_epoll_ctl (UV_SYSCALL_BASE + 251) +# endif +#endif /* __NR_epoll_ctl */ + +#ifndef __NR_epoll_wait +# if defined(__x86_64__) +# define __NR_epoll_wait 232 /* used to be 215 */ +# elif defined(__i386__) +# define __NR_epoll_wait 256 +# elif defined(__arm__) +# define __NR_epoll_wait (UV_SYSCALL_BASE + 252) +# endif +#endif /* __NR_epoll_wait */ + +#ifndef __NR_epoll_pwait +# if defined(__x86_64__) +# define __NR_epoll_pwait 281 +# elif defined(__i386__) +# define __NR_epoll_pwait 319 +# elif defined(__arm__) +# define __NR_epoll_pwait (UV_SYSCALL_BASE + 346) +# endif +#endif /* __NR_epoll_pwait */ + +#ifndef __NR_inotify_init +# if defined(__x86_64__) +# define __NR_inotify_init 253 +# elif defined(__i386__) +# define __NR_inotify_init 291 +# elif defined(__arm__) +# define __NR_inotify_init (UV_SYSCALL_BASE + 316) +# endif +#endif /* __NR_inotify_init */ + +#ifndef __NR_inotify_init1 +# if defined(__x86_64__) +# define __NR_inotify_init1 294 +# elif defined(__i386__) +# define __NR_inotify_init1 332 +# elif defined(__arm__) +# define __NR_inotify_init1 (UV_SYSCALL_BASE + 360) +# endif +#endif /* __NR_inotify_init1 */ + +#ifndef __NR_inotify_add_watch +# if defined(__x86_64__) +# define __NR_inotify_add_watch 254 +# elif defined(__i386__) +# define __NR_inotify_add_watch 292 +# elif defined(__arm__) +# define __NR_inotify_add_watch (UV_SYSCALL_BASE + 317) +# endif +#endif /* __NR_inotify_add_watch */ + +#ifndef __NR_inotify_rm_watch +# if defined(__x86_64__) +# define __NR_inotify_rm_watch 255 +# elif defined(__i386__) +# define __NR_inotify_rm_watch 293 +# elif defined(__arm__) +# define __NR_inotify_rm_watch (UV_SYSCALL_BASE + 318) +# endif +#endif /* __NR_inotify_rm_watch */ + +#ifndef __NR_pipe2 +# if defined(__x86_64__) +# define __NR_pipe2 293 +# elif defined(__i386__) +# define __NR_pipe2 331 +# elif defined(__arm__) +# define __NR_pipe2 (UV_SYSCALL_BASE + 359) +# endif +#endif /* __NR_pipe2 */ + +#ifndef __NR_recvmmsg +# if defined(__x86_64__) +# define __NR_recvmmsg 299 +# elif defined(__i386__) +# define __NR_recvmmsg 337 +# elif defined(__arm__) +# define __NR_recvmmsg (UV_SYSCALL_BASE + 365) +# endif +#endif /* __NR_recvmsg */ + +#ifndef __NR_sendmmsg +# if defined(__x86_64__) +# define __NR_sendmmsg 307 +# elif defined(__i386__) +# define __NR_sendmmsg 345 +# elif defined(__arm__) +# define __NR_sendmmsg (UV_SYSCALL_BASE + 374) +# endif +#endif /* __NR_sendmmsg */ + +#ifndef __NR_utimensat +# if defined(__x86_64__) +# define __NR_utimensat 280 +# elif defined(__i386__) +# define __NR_utimensat 320 +# elif defined(__arm__) +# define __NR_utimensat (UV_SYSCALL_BASE + 348) +# endif +#endif /* __NR_utimensat */ + +#ifndef __NR_preadv +# if defined(__x86_64__) +# define __NR_preadv 295 +# elif defined(__i386__) +# define __NR_preadv 333 +# elif defined(__arm__) +# define __NR_preadv (UV_SYSCALL_BASE + 361) +# endif +#endif /* __NR_preadv */ + +#ifndef __NR_pwritev +# if defined(__x86_64__) +# define __NR_pwritev 296 +# elif defined(__i386__) +# define __NR_pwritev 334 +# elif defined(__arm__) +# define __NR_pwritev (UV_SYSCALL_BASE + 362) +# endif +#endif /* __NR_pwritev */ + +#ifndef __NR_dup3 +# if defined(__x86_64__) +# define __NR_dup3 292 +# elif defined(__i386__) +# define __NR_dup3 330 +# elif defined(__arm__) +# define __NR_dup3 (UV_SYSCALL_BASE + 358) +# endif +#endif /* __NR_pwritev */ + + +int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) { +#if defined(__i386__) + unsigned long args[4]; + int r; + + args[0] = (unsigned long) fd; + args[1] = (unsigned long) addr; + args[2] = (unsigned long) addrlen; + args[3] = (unsigned long) flags; + + r = syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args); + + /* socketcall() raises EINVAL when SYS_ACCEPT4 is not supported but so does + * a bad flags argument. Try to distinguish between the two cases. + */ + if (r == -1) + if (errno == EINVAL) + if ((flags & ~(UV__SOCK_CLOEXEC|UV__SOCK_NONBLOCK)) == 0) + errno = ENOSYS; + + return r; +#elif defined(__NR_accept4) + return syscall(__NR_accept4, fd, addr, addrlen, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__eventfd(unsigned int count) { +#if defined(__NR_eventfd) + return syscall(__NR_eventfd, count); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__eventfd2(unsigned int count, int flags) { +#if defined(__NR_eventfd2) + return syscall(__NR_eventfd2, count, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__epoll_create(int size) { +#if defined(__NR_epoll_create) + return syscall(__NR_epoll_create, size); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__epoll_create1(int flags) { +#if defined(__NR_epoll_create1) + return syscall(__NR_epoll_create1, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event* events) { +#if defined(__NR_epoll_ctl) + return syscall(__NR_epoll_ctl, epfd, op, fd, events); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__epoll_wait(int epfd, + struct uv__epoll_event* events, + int nevents, + int timeout) { +#if defined(__NR_epoll_wait) + int result; + result = syscall(__NR_epoll_wait, epfd, events, nevents, timeout); +#if MSAN_ACTIVE + if (result > 0) + __msan_unpoison(events, sizeof(events[0]) * result); +#endif + return result; +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__epoll_pwait(int epfd, + struct uv__epoll_event* events, + int nevents, + int timeout, + uint64_t sigmask) { +#if defined(__NR_epoll_pwait) + int result; + result = syscall(__NR_epoll_pwait, + epfd, + events, + nevents, + timeout, + &sigmask, + sizeof(sigmask)); +#if MSAN_ACTIVE + if (result > 0) + __msan_unpoison(events, sizeof(events[0]) * result); +#endif + return result; +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__inotify_init(void) { +#if defined(__NR_inotify_init) + return syscall(__NR_inotify_init); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__inotify_init1(int flags) { +#if defined(__NR_inotify_init1) + return syscall(__NR_inotify_init1, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__inotify_add_watch(int fd, const char* path, uint32_t mask) { +#if defined(__NR_inotify_add_watch) + return syscall(__NR_inotify_add_watch, fd, path, mask); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__inotify_rm_watch(int fd, int32_t wd) { +#if defined(__NR_inotify_rm_watch) + return syscall(__NR_inotify_rm_watch, fd, wd); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__pipe2(int pipefd[2], int flags) { +#if defined(__NR_pipe2) + int result; + result = syscall(__NR_pipe2, pipefd, flags); +#if MSAN_ACTIVE + if (!result) + __msan_unpoison(pipefd, sizeof(int[2])); +#endif + return result; +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__sendmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags) { +#if defined(__NR_sendmmsg) + return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__recvmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags, + struct timespec* timeout) { +#if defined(__NR_recvmmsg) + return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__utimesat(int dirfd, + const char* path, + const struct timespec times[2], + int flags) +{ +#if defined(__NR_utimensat) + return syscall(__NR_utimensat, dirfd, path, times, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { +#if defined(__NR_preadv) + return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32)); +#else + return errno = ENOSYS, -1; +#endif +} + + +ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { +#if defined(__NR_pwritev) + return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32)); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__dup3(int oldfd, int newfd, int flags) { +#if defined(__NR_dup3) + return syscall(__NR_dup3, oldfd, newfd, flags); +#else + return errno = ENOSYS, -1; +#endif +} diff --git a/src/unix/linux-syscalls.h b/src/unix/linux-syscalls.h new file mode 100644 index 0000000..4c095e9 --- /dev/null +++ b/src/unix/linux-syscalls.h @@ -0,0 +1,151 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_LINUX_SYSCALL_H_ +#define UV_LINUX_SYSCALL_H_ + +#undef _GNU_SOURCE +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#if defined(__alpha__) +# define UV__O_CLOEXEC 0x200000 +#elif defined(__hppa__) +# define UV__O_CLOEXEC 0x200000 +#elif defined(__sparc__) +# define UV__O_CLOEXEC 0x400000 +#else +# define UV__O_CLOEXEC 0x80000 +#endif + +#if defined(__alpha__) +# define UV__O_NONBLOCK 0x4 +#elif defined(__hppa__) +# define UV__O_NONBLOCK O_NONBLOCK +#elif defined(__mips__) +# define UV__O_NONBLOCK 0x80 +#elif defined(__sparc__) +# define UV__O_NONBLOCK 0x4000 +#else +# define UV__O_NONBLOCK 0x800 +#endif + +#define UV__EFD_CLOEXEC UV__O_CLOEXEC +#define UV__EFD_NONBLOCK UV__O_NONBLOCK + +#define UV__IN_CLOEXEC UV__O_CLOEXEC +#define UV__IN_NONBLOCK UV__O_NONBLOCK + +#define UV__SOCK_CLOEXEC UV__O_CLOEXEC +#if defined(SOCK_NONBLOCK) +# define UV__SOCK_NONBLOCK SOCK_NONBLOCK +#else +# define UV__SOCK_NONBLOCK UV__O_NONBLOCK +#endif + +/* epoll flags */ +#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC +#define UV__EPOLL_CTL_ADD 1 +#define UV__EPOLL_CTL_DEL 2 +#define UV__EPOLL_CTL_MOD 3 + +/* inotify flags */ +#define UV__IN_ACCESS 0x001 +#define UV__IN_MODIFY 0x002 +#define UV__IN_ATTRIB 0x004 +#define UV__IN_CLOSE_WRITE 0x008 +#define UV__IN_CLOSE_NOWRITE 0x010 +#define UV__IN_OPEN 0x020 +#define UV__IN_MOVED_FROM 0x040 +#define UV__IN_MOVED_TO 0x080 +#define UV__IN_CREATE 0x100 +#define UV__IN_DELETE 0x200 +#define UV__IN_DELETE_SELF 0x400 +#define UV__IN_MOVE_SELF 0x800 + +#if defined(__x86_64__) +struct uv__epoll_event { + uint32_t events; + uint64_t data; +} __attribute__((packed)); +#else +struct uv__epoll_event { + uint32_t events; + uint64_t data; +}; +#endif + +struct uv__inotify_event { + int32_t wd; + uint32_t mask; + uint32_t cookie; + uint32_t len; + /* char name[0]; */ +}; + +struct uv__mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags); +int uv__eventfd(unsigned int count); +int uv__epoll_create(int size); +int uv__epoll_create1(int flags); +int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event *ev); +int uv__epoll_wait(int epfd, + struct uv__epoll_event* events, + int nevents, + int timeout); +int uv__epoll_pwait(int epfd, + struct uv__epoll_event* events, + int nevents, + int timeout, + uint64_t sigmask); +int uv__eventfd2(unsigned int count, int flags); +int uv__inotify_init(void); +int uv__inotify_init1(int flags); +int uv__inotify_add_watch(int fd, const char* path, uint32_t mask); +int uv__inotify_rm_watch(int fd, int32_t wd); +int uv__pipe2(int pipefd[2], int flags); +int uv__recvmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags, + struct timespec* timeout); +int uv__sendmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags); +int uv__utimesat(int dirfd, + const char* path, + const struct timespec times[2], + int flags); +ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset); +ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset); +int uv__dup3(int oldfd, int newfd, int flags); + +#endif /* UV_LINUX_SYSCALL_H_ */ diff --git a/src/unix/loop-watcher.c b/src/unix/loop-watcher.c new file mode 100644 index 0000000..340bb0d --- /dev/null +++ b/src/unix/loop-watcher.c @@ -0,0 +1,68 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#define UV_LOOP_WATCHER_DEFINE(name, type) \ + int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \ + uv__handle_init(loop, (uv_handle_t*)handle, UV_##type); \ + handle->name##_cb = NULL; \ + return 0; \ + } \ + \ + int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \ + if (uv__is_active(handle)) return 0; \ + if (cb == NULL) return -EINVAL; \ + QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \ + handle->name##_cb = cb; \ + uv__handle_start(handle); \ + return 0; \ + } \ + \ + int uv_##name##_stop(uv_##name##_t* handle) { \ + if (!uv__is_active(handle)) return 0; \ + QUEUE_REMOVE(&handle->queue); \ + uv__handle_stop(handle); \ + return 0; \ + } \ + \ + void uv__run_##name(uv_loop_t* loop) { \ + uv_##name##_t* h; \ + QUEUE queue; \ + QUEUE* q; \ + QUEUE_MOVE(&loop->name##_handles, &queue); \ + while (!QUEUE_EMPTY(&queue)) { \ + q = QUEUE_HEAD(&queue); \ + h = QUEUE_DATA(q, uv_##name##_t, queue); \ + QUEUE_REMOVE(q); \ + QUEUE_INSERT_TAIL(&loop->name##_handles, q); \ + h->name##_cb(h); \ + } \ + } \ + \ + void uv__##name##_close(uv_##name##_t* handle) { \ + uv_##name##_stop(handle); \ + } + +UV_LOOP_WATCHER_DEFINE(prepare, PREPARE) +UV_LOOP_WATCHER_DEFINE(check, CHECK) +UV_LOOP_WATCHER_DEFINE(idle, IDLE) diff --git a/src/unix/loop.c b/src/unix/loop.c new file mode 100644 index 0000000..bd63c2f --- /dev/null +++ b/src/unix/loop.c @@ -0,0 +1,159 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "tree.h" +#include "internal.h" +#include "heap-inl.h" +#include +#include +#include + +int uv_loop_init(uv_loop_t* loop) { + void* saved_data; + int err; + + uv__signal_global_once_init(); + + saved_data = loop->data; + memset(loop, 0, sizeof(*loop)); + loop->data = saved_data; + + heap_init((struct heap*) &loop->timer_heap); + QUEUE_INIT(&loop->wq); + QUEUE_INIT(&loop->active_reqs); + QUEUE_INIT(&loop->idle_handles); + QUEUE_INIT(&loop->async_handles); + QUEUE_INIT(&loop->check_handles); + QUEUE_INIT(&loop->prepare_handles); + QUEUE_INIT(&loop->handle_queue); + + loop->nfds = 0; + loop->watchers = NULL; + loop->nwatchers = 0; + QUEUE_INIT(&loop->pending_queue); + QUEUE_INIT(&loop->watcher_queue); + + loop->closing_handles = NULL; + uv__update_time(loop); + uv__async_init(&loop->async_watcher); + loop->signal_pipefd[0] = -1; + loop->signal_pipefd[1] = -1; + loop->backend_fd = -1; + loop->emfile_fd = -1; + + loop->timer_counter = 0; + loop->stop_flag = 0; + + err = uv__platform_loop_init(loop); + if (err) + return err; + + err = uv_signal_init(loop, &loop->child_watcher); + if (err) + goto fail_signal_init; + + uv__handle_unref(&loop->child_watcher); + loop->child_watcher.flags |= UV__HANDLE_INTERNAL; + QUEUE_INIT(&loop->process_handles); + + err = uv_rwlock_init(&loop->cloexec_lock); + if (err) + goto fail_rwlock_init; + + err = uv_mutex_init(&loop->wq_mutex); + if (err) + goto fail_mutex_init; + + err = uv_async_init(loop, &loop->wq_async, uv__work_done); + if (err) + goto fail_async_init; + + uv__handle_unref(&loop->wq_async); + loop->wq_async.flags |= UV__HANDLE_INTERNAL; + + return 0; + +fail_async_init: + uv_mutex_destroy(&loop->wq_mutex); + +fail_mutex_init: + uv_rwlock_destroy(&loop->cloexec_lock); + +fail_rwlock_init: + uv__signal_loop_cleanup(loop); + +fail_signal_init: + uv__platform_loop_delete(loop); + + return err; +} + + +void uv__loop_close(uv_loop_t* loop) { + uv__signal_loop_cleanup(loop); + uv__platform_loop_delete(loop); + uv__async_stop(loop, &loop->async_watcher); + + if (loop->emfile_fd != -1) { + uv__close(loop->emfile_fd); + loop->emfile_fd = -1; + } + + if (loop->backend_fd != -1) { + uv__close(loop->backend_fd); + loop->backend_fd = -1; + } + + uv_mutex_lock(&loop->wq_mutex); + assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!"); + assert(!uv__has_active_reqs(loop)); + uv_mutex_unlock(&loop->wq_mutex); + uv_mutex_destroy(&loop->wq_mutex); + + /* + * Note that all thread pool stuff is finished at this point and + * it is safe to just destroy rw lock + */ + uv_rwlock_destroy(&loop->cloexec_lock); + +#if 0 + assert(QUEUE_EMPTY(&loop->pending_queue)); + assert(QUEUE_EMPTY(&loop->watcher_queue)); + assert(loop->nfds == 0); +#endif + + uv__free(loop->watchers); + loop->watchers = NULL; + loop->nwatchers = 0; +} + + +int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) { + if (option != UV_LOOP_BLOCK_SIGNAL) + return UV_ENOSYS; + + if (va_arg(ap, int) != SIGPROF) + return UV_EINVAL; + + loop->flags |= UV_LOOP_BLOCK_SIGPROF; + return 0; +} diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c new file mode 100644 index 0000000..4a9e6cb --- /dev/null +++ b/src/unix/netbsd.c @@ -0,0 +1,380 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + +static char *process_title; + + +int uv__platform_loop_init(uv_loop_t* loop) { + return uv__kqueue_init(loop); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); +} + + +void uv_loadavg(double avg[3]) { + struct loadavg info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_LOADAVG}; + + if (sysctl(which, 2, &info, &size, NULL, 0) == -1) return; + + avg[0] = (double) info.ldavg[0] / info.fscale; + avg[1] = (double) info.ldavg[1] / info.fscale; + avg[2] = (double) info.ldavg[2] / info.fscale; +} + + +int uv_exepath(char* buffer, size_t* size) { + int mib[4]; + size_t cb; + pid_t mypid; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + mypid = getpid(); + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = mypid; + mib[3] = KERN_PROC_ARGV; + + cb = *size; + if (sysctl(mib, 4, buffer, &cb, NULL, 0)) + return -errno; + *size = strlen(buffer); + + return 0; +} + + +uint64_t uv_get_free_memory(void) { + struct uvmexp info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_UVMEXP}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info.free * sysconf(_SC_PAGESIZE); +} + + +uint64_t uv_get_total_memory(void) { +#if defined(HW_PHYSMEM64) + uint64_t info; + int which[] = {CTL_HW, HW_PHYSMEM64}; +#else + unsigned int info; + int which[] = {CTL_HW, HW_PHYSMEM}; +#endif + size_t size = sizeof(info); + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info; +} + + +char** uv_setup_args(int argc, char** argv) { + process_title = argc ? uv__strdup(argv[0]) : NULL; + return argv; +} + + +int uv_set_process_title(const char* title) { + if (process_title) uv__free(process_title); + + process_title = uv__strdup(title); + setproctitle("%s", title); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return -EINVAL; + + if (process_title) { + len = strlen(process_title) + 1; + + if (size < len) + return -ENOBUFS; + + memcpy(buffer, process_title, len); + } else { + len = 0; + } + + buffer[len] = '\0'; + + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + kvm_t *kd = NULL; + struct kinfo_proc2 *kinfo = NULL; + pid_t pid; + int nprocs; + int max_size = sizeof(struct kinfo_proc2); + int page_size; + + page_size = getpagesize(); + pid = getpid(); + + kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open"); + + if (kd == NULL) goto error; + + kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs); + if (kinfo == NULL) goto error; + + *rss = kinfo->p_vm_rssize * page_size; + + kvm_close(kd); + + return 0; + +error: + if (kd) kvm_close(kd); + return -EPERM; +} + + +int uv_uptime(double* uptime) { + time_t now; + struct timeval info; + size_t size = sizeof(info); + static int which[] = {CTL_KERN, KERN_BOOTTIME}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + now = time(NULL); + + *uptime = (double)(now - info.tv_sec); + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK); + unsigned int multiplier = ((uint64_t)1000L / ticks); + unsigned int cur = 0; + uv_cpu_info_t* cpu_info; + u_int64_t* cp_times; + char model[512]; + u_int64_t cpuspeed; + int numcpus; + size_t size; + int i; + + size = sizeof(model); + if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) && + sysctlbyname("hw.model", &model, &size, NULL, 0)) { + return -errno; + } + + size = sizeof(numcpus); + if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) + return -errno; + *count = numcpus; + + /* Only i386 and amd64 have machdep.tsc_freq */ + size = sizeof(cpuspeed); + if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0)) + cpuspeed = 0; + + size = numcpus * CPUSTATES * sizeof(*cp_times); + cp_times = uv__malloc(size); + if (cp_times == NULL) + return -ENOMEM; + + if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0)) + return -errno; + + *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) { + uv__free(cp_times); + uv__free(*cpu_infos); + return -ENOMEM; + } + + for (i = 0; i < numcpus; i++) { + cpu_info = &(*cpu_infos)[i]; + cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier; + cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier; + cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier; + cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier; + cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier; + cpu_info->model = uv__strdup(model); + cpu_info->speed = (int)(cpuspeed/(uint64_t) 1e6); + cur += CPUSTATES; + } + uv__free(cp_times); + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != PF_INET)) { + continue; + } + (*count)++; + } + + *addresses = uv__malloc(*count * sizeof(**addresses)); + + if (!(*addresses)) { + freeifaddrs(addrs); + return -ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + if (ent->ifa_addr->sa_family != PF_INET) + continue; + + address->name = uv__strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(addresses[i].name); + } + + uv__free(addresses); +} diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c new file mode 100644 index 0000000..909288c --- /dev/null +++ b/src/unix/openbsd.c @@ -0,0 +1,396 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + + +static char *process_title; + + +int uv__platform_loop_init(uv_loop_t* loop) { + return uv__kqueue_init(loop); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); +} + + +void uv_loadavg(double avg[3]) { + struct loadavg info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_LOADAVG}; + + if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return; + + avg[0] = (double) info.ldavg[0] / info.fscale; + avg[1] = (double) info.ldavg[1] / info.fscale; + avg[2] = (double) info.ldavg[2] / info.fscale; +} + + +int uv_exepath(char* buffer, size_t* size) { + int mib[4]; + char **argsbuf = NULL; + char **argsbuf_tmp; + size_t argsbuf_size = 100U; + size_t exepath_size; + pid_t mypid; + int err; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + mypid = getpid(); + for (;;) { + err = -ENOMEM; + argsbuf_tmp = uv__realloc(argsbuf, argsbuf_size); + if (argsbuf_tmp == NULL) + goto out; + argsbuf = argsbuf_tmp; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = mypid; + mib[3] = KERN_PROC_ARGV; + if (sysctl(mib, 4, argsbuf, &argsbuf_size, NULL, 0) == 0) { + break; + } + if (errno != ENOMEM) { + err = -errno; + goto out; + } + argsbuf_size *= 2U; + } + + if (argsbuf[0] == NULL) { + err = -EINVAL; /* FIXME(bnoordhuis) More appropriate error. */ + goto out; + } + + *size -= 1; + exepath_size = strlen(argsbuf[0]); + if (*size > exepath_size) + *size = exepath_size; + + memcpy(buffer, argsbuf[0], *size); + buffer[*size] = '\0'; + err = 0; + +out: + uv__free(argsbuf); + + return err; +} + + +uint64_t uv_get_free_memory(void) { + struct uvmexp info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_UVMEXP}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info.free * sysconf(_SC_PAGESIZE); +} + + +uint64_t uv_get_total_memory(void) { + uint64_t info; + int which[] = {CTL_HW, HW_PHYSMEM64}; + size_t size = sizeof(info); + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info; +} + + +char** uv_setup_args(int argc, char** argv) { + process_title = argc ? uv__strdup(argv[0]) : NULL; + return argv; +} + + +int uv_set_process_title(const char* title) { + uv__free(process_title); + process_title = uv__strdup(title); + setproctitle(title); + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return -EINVAL; + + if (process_title) { + len = strlen(process_title) + 1; + + if (size < len) + return -ENOBUFS; + + memcpy(buffer, process_title, len); + } else { + len = 0; + } + + buffer[len] = '\0'; + + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + struct kinfo_proc kinfo; + size_t page_size = getpagesize(); + size_t size = sizeof(struct kinfo_proc); + int mib[6]; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + mib[4] = sizeof(struct kinfo_proc); + mib[5] = 1; + + if (sysctl(mib, 6, &kinfo, &size, NULL, 0) < 0) + return -errno; + + *rss = kinfo.p_vm_rssize * page_size; + return 0; +} + + +int uv_uptime(double* uptime) { + time_t now; + struct timeval info; + size_t size = sizeof(info); + static int which[] = {CTL_KERN, KERN_BOOTTIME}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + now = time(NULL); + + *uptime = (double)(now - info.tv_sec); + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), + multiplier = ((uint64_t)1000L / ticks), cpuspeed; + uint64_t info[CPUSTATES]; + char model[512]; + int numcpus = 1; + int which[] = {CTL_HW,HW_MODEL,0}; + size_t size; + int i; + uv_cpu_info_t* cpu_info; + + size = sizeof(model); + if (sysctl(which, 2, &model, &size, NULL, 0)) + return -errno; + + which[1] = HW_NCPU; + size = sizeof(numcpus); + if (sysctl(which, 2, &numcpus, &size, NULL, 0)) + return -errno; + + *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) + return -ENOMEM; + + *count = numcpus; + + which[1] = HW_CPUSPEED; + size = sizeof(cpuspeed); + if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) { + uv__free(*cpu_infos); + return -errno; + } + + size = sizeof(info); + which[0] = CTL_KERN; + which[1] = KERN_CPTIME2; + for (i = 0; i < numcpus; i++) { + which[2] = i; + size = sizeof(info); + if (sysctl(which, 3, &info, &size, NULL, 0)) { + uv__free(*cpu_infos); + return -errno; + } + + cpu_info = &(*cpu_infos)[i]; + + cpu_info->cpu_times.user = (uint64_t)(info[CP_USER]) * multiplier; + cpu_info->cpu_times.nice = (uint64_t)(info[CP_NICE]) * multiplier; + cpu_info->cpu_times.sys = (uint64_t)(info[CP_SYS]) * multiplier; + cpu_info->cpu_times.idle = (uint64_t)(info[CP_IDLE]) * multiplier; + cpu_info->cpu_times.irq = (uint64_t)(info[CP_INTR]) * multiplier; + + cpu_info->model = uv__strdup(model); + cpu_info->speed = cpuspeed; + } + + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, + int* count) { + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; + + if (getifaddrs(&addrs) != 0) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != PF_INET)) { + continue; + } + (*count)++; + } + + *addresses = uv__malloc(*count * sizeof(**addresses)); + + if (!(*addresses)) { + freeifaddrs(addrs); + return -ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + if (ent->ifa_addr->sa_family != PF_INET) + continue; + + address->name = uv__strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(addresses[i].name); + } + + uv__free(addresses); +} diff --git a/src/unix/os390.c b/src/unix/os390.c new file mode 100644 index 0000000..bcdbc4b --- /dev/null +++ b/src/unix/os390.c @@ -0,0 +1,42 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * 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. + */ + +#include "internal.h" + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct pollfd p[1]; + int rv; + + p[0].fd = fd; + p[0].events = POLLIN; + + do + rv = poll(p, 1, 0); + while (rv == -1 && errno == EINTR); + + if (rv == -1) + abort(); + + if (p[0].revents & POLLNVAL) + return -1; + + return 0; +} diff --git a/src/unix/pipe.c b/src/unix/pipe.c new file mode 100644 index 0000000..b73994c --- /dev/null +++ b/src/unix/pipe.c @@ -0,0 +1,298 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + + +int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { + uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); + handle->shutdown_req = NULL; + handle->connect_req = NULL; + handle->pipe_fname = NULL; + handle->ipc = ipc; + return 0; +} + + +int uv_pipe_bind(uv_pipe_t* handle, const char* name) { + struct sockaddr_un saddr; + const char* pipe_fname; + int sockfd; + int err; + + pipe_fname = NULL; + sockfd = -1; + + /* Already bound? */ + if (uv__stream_fd(handle) >= 0) + return -EINVAL; + + /* Make a copy of the file name, it outlives this function's scope. */ + pipe_fname = uv__strdup(name); + if (pipe_fname == NULL) + return -ENOMEM; + + /* We've got a copy, don't touch the original any more. */ + name = NULL; + + err = uv__socket(AF_UNIX, SOCK_STREAM, 0); + if (err < 0) + goto err_socket; + sockfd = err; + + memset(&saddr, 0, sizeof saddr); + strncpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path) - 1); + saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0'; + saddr.sun_family = AF_UNIX; + + if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) { + err = -errno; + /* Convert ENOENT to EACCES for compatibility with Windows. */ + if (err == -ENOENT) + err = -EACCES; + goto err_bind; + } + + /* Success. */ + handle->flags |= UV_HANDLE_BOUND; + handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */ + handle->io_watcher.fd = sockfd; + return 0; + +err_bind: + uv__close(sockfd); + +err_socket: + uv__free((void*)pipe_fname); + return err; +} + + +int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { + if (uv__stream_fd(handle) == -1) + return -EINVAL; + +#if defined(__MVS__) + /* On zOS, backlog=0 has undefined behaviour */ + if (backlog == 0) + backlog = 1; + else if (backlog < 0) + backlog = SOMAXCONN; +#endif + + if (listen(uv__stream_fd(handle), backlog)) + return -errno; + + handle->connection_cb = cb; + handle->io_watcher.cb = uv__server_io; + uv__io_start(handle->loop, &handle->io_watcher, POLLIN); + return 0; +} + + +void uv__pipe_close(uv_pipe_t* handle) { + if (handle->pipe_fname) { + /* + * Unlink the file system entity before closing the file descriptor. + * Doing it the other way around introduces a race where our process + * unlinks a socket with the same name that's just been created by + * another thread or process. + */ + unlink(handle->pipe_fname); + uv__free((void*)handle->pipe_fname); + handle->pipe_fname = NULL; + } + + uv__stream_close((uv_stream_t*)handle); +} + + +int uv_pipe_open(uv_pipe_t* handle, uv_file fd) { + int err; + + err = uv__nonblock(fd, 1); + if (err) + return err; + +#if defined(__APPLE__) + err = uv__stream_try_select((uv_stream_t*) handle, &fd); + if (err) + return err; +#endif /* defined(__APPLE__) */ + + return uv__stream_open((uv_stream_t*)handle, + fd, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); +} + + +void uv_pipe_connect(uv_connect_t* req, + uv_pipe_t* handle, + const char* name, + uv_connect_cb cb) { + struct sockaddr_un saddr; + int new_sock; + int err; + int r; + + new_sock = (uv__stream_fd(handle) == -1); + + if (new_sock) { + err = uv__socket(AF_UNIX, SOCK_STREAM, 0); + if (err < 0) + goto out; + handle->io_watcher.fd = err; + } + + memset(&saddr, 0, sizeof saddr); + strncpy(saddr.sun_path, name, sizeof(saddr.sun_path) - 1); + saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0'; + saddr.sun_family = AF_UNIX; + + do { + r = connect(uv__stream_fd(handle), + (struct sockaddr*)&saddr, sizeof saddr); + } + while (r == -1 && errno == EINTR); + + if (r == -1 && errno != EINPROGRESS) { + err = -errno; + goto out; + } + + err = 0; + if (new_sock) { + err = uv__stream_open((uv_stream_t*)handle, + uv__stream_fd(handle), + UV_STREAM_READABLE | UV_STREAM_WRITABLE); + } + + if (err == 0) + uv__io_start(handle->loop, &handle->io_watcher, POLLIN | POLLOUT); + +out: + handle->delayed_error = err; + handle->connect_req = req; + + uv__req_init(handle->loop, req, UV_CONNECT); + req->handle = (uv_stream_t*)handle; + req->cb = cb; + QUEUE_INIT(&req->queue); + + /* Force callback to run on next tick in case of error. */ + if (err) + uv__io_feed(handle->loop, &handle->io_watcher); + +} + + +typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*); + + +static int uv__pipe_getsockpeername(const uv_pipe_t* handle, + uv__peersockfunc func, + char* buffer, + size_t* size) { + struct sockaddr_un sa; + socklen_t addrlen; + int err; + + addrlen = sizeof(sa); + memset(&sa, 0, addrlen); + err = func(uv__stream_fd(handle), (struct sockaddr*) &sa, &addrlen); + if (err < 0) { + *size = 0; + return -errno; + } + +#if defined(__linux__) + if (sa.sun_path[0] == 0) + /* Linux abstract namespace */ + addrlen -= offsetof(struct sockaddr_un, sun_path); + else +#endif + addrlen = strlen(sa.sun_path); + + + if (addrlen >= *size) { + *size = addrlen + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, sa.sun_path, addrlen); + *size = addrlen; + + /* only null-terminate if it's not an abstract socket */ + if (buffer[0] != '\0') + buffer[addrlen] = '\0'; + + return 0; +} + + +int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) { + return uv__pipe_getsockpeername(handle, getsockname, buffer, size); +} + + +int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) { + return uv__pipe_getsockpeername(handle, getpeername, buffer, size); +} + + +void uv_pipe_pending_instances(uv_pipe_t* handle, int count) { +} + + +int uv_pipe_pending_count(uv_pipe_t* handle) { + uv__stream_queued_fds_t* queued_fds; + + if (!handle->ipc) + return 0; + + if (handle->accepted_fd == -1) + return 0; + + if (handle->queued_fds == NULL) + return 1; + + queued_fds = handle->queued_fds; + return queued_fds->offset + 1; +} + + +uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { + if (!handle->ipc) + return UV_UNKNOWN_HANDLE; + + if (handle->accepted_fd == -1) + return UV_UNKNOWN_HANDLE; + else + return uv__handle_type(handle->accepted_fd); +} diff --git a/src/unix/poll.c b/src/unix/poll.c new file mode 100644 index 0000000..4c0d478 --- /dev/null +++ b/src/unix/poll.c @@ -0,0 +1,130 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + + +static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + uv_poll_t* handle; + int pevents; + + handle = container_of(w, uv_poll_t, io_watcher); + + if (events & POLLERR) { + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); + uv__handle_stop(handle); + handle->poll_cb(handle, -EBADF, 0); + return; + } + + pevents = 0; + if (events & POLLIN) + pevents |= UV_READABLE; + if (events & POLLOUT) + pevents |= UV_WRITABLE; + if (events & UV__POLLRDHUP) + pevents |= UV_DISCONNECT; + + handle->poll_cb(handle, 0, pevents); +} + + +int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { + int err; + + err = uv__io_check_fd(loop, fd); + if (err) + return err; + + /* If ioctl(FIONBIO) reports ENOTTY, try fcntl(F_GETFL) + fcntl(F_SETFL). + * Workaround for e.g. kqueue fds not supporting ioctls. + */ + err = uv__nonblock(fd, 1); + if (err == -ENOTTY) + if (uv__nonblock == uv__nonblock_ioctl) + err = uv__nonblock_fcntl(fd, 1); + + if (err) + return err; + + uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL); + uv__io_init(&handle->io_watcher, uv__poll_io, fd); + handle->poll_cb = NULL; + return 0; +} + + +int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, + uv_os_sock_t socket) { + return uv_poll_init(loop, handle, socket); +} + + +static void uv__poll_stop(uv_poll_t* handle) { + uv__io_stop(handle->loop, + &handle->io_watcher, + POLLIN | POLLOUT | UV__POLLRDHUP); + uv__handle_stop(handle); +} + + +int uv_poll_stop(uv_poll_t* handle) { + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + uv__poll_stop(handle); + return 0; +} + + +int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { + int events; + + assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + + uv__poll_stop(handle); + + if (pevents == 0) + return 0; + + events = 0; + if (pevents & UV_READABLE) + events |= POLLIN; + if (pevents & UV_WRITABLE) + events |= POLLOUT; + if (pevents & UV_DISCONNECT) + events |= UV__POLLRDHUP; + + uv__io_start(handle->loop, &handle->io_watcher, events); + uv__handle_start(handle); + handle->poll_cb = poll_cb; + + return 0; +} + + +void uv__poll_close(uv_poll_t* handle) { + uv__poll_stop(handle); +} diff --git a/src/unix/process.c b/src/unix/process.c new file mode 100644 index 0000000..45f5b45 --- /dev/null +++ b/src/unix/process.c @@ -0,0 +1,563 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(__APPLE__) && !TARGET_OS_IPHONE +# include +# define environ (*_NSGetEnviron()) +#else +extern char **environ; +#endif + +#if defined(__linux__) || defined(__GLIBC__) +# include +#endif + + +static void uv__chld(uv_signal_t* handle, int signum) { + uv_process_t* process; + uv_loop_t* loop; + int exit_status; + int term_signal; + int status; + pid_t pid; + QUEUE pending; + QUEUE* q; + QUEUE* h; + + assert(signum == SIGCHLD); + + QUEUE_INIT(&pending); + loop = handle->loop; + + h = &loop->process_handles; + q = QUEUE_HEAD(h); + while (q != h) { + process = QUEUE_DATA(q, uv_process_t, queue); + q = QUEUE_NEXT(q); + + do + pid = waitpid(process->pid, &status, WNOHANG); + while (pid == -1 && errno == EINTR); + + if (pid == 0) + continue; + + if (pid == -1) { + if (errno != ECHILD) + abort(); + continue; + } + + process->status = status; + QUEUE_REMOVE(&process->queue); + QUEUE_INSERT_TAIL(&pending, &process->queue); + } + + h = &pending; + q = QUEUE_HEAD(h); + while (q != h) { + process = QUEUE_DATA(q, uv_process_t, queue); + q = QUEUE_NEXT(q); + + QUEUE_REMOVE(&process->queue); + QUEUE_INIT(&process->queue); + uv__handle_stop(process); + + if (process->exit_cb == NULL) + continue; + + exit_status = 0; + if (WIFEXITED(process->status)) + exit_status = WEXITSTATUS(process->status); + + term_signal = 0; + if (WIFSIGNALED(process->status)) + term_signal = WTERMSIG(process->status); + + process->exit_cb(process, exit_status, term_signal); + } + assert(QUEUE_EMPTY(&pending)); +} + + +int uv__make_socketpair(int fds[2], int flags) { +#if defined(__linux__) + static int no_cloexec; + + if (no_cloexec) + goto skip; + + if (socketpair(AF_UNIX, SOCK_STREAM | UV__SOCK_CLOEXEC | flags, 0, fds) == 0) + return 0; + + /* Retry on EINVAL, it means SOCK_CLOEXEC is not supported. + * Anything else is a genuine error. + */ + if (errno != EINVAL) + return -errno; + + no_cloexec = 1; + +skip: +#endif + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) + return -errno; + + uv__cloexec(fds[0], 1); + uv__cloexec(fds[1], 1); + + if (flags & UV__F_NONBLOCK) { + uv__nonblock(fds[0], 1); + uv__nonblock(fds[1], 1); + } + + return 0; +} + + +int uv__make_pipe(int fds[2], int flags) { +#if defined(__linux__) + static int no_pipe2; + + if (no_pipe2) + goto skip; + + if (uv__pipe2(fds, flags | UV__O_CLOEXEC) == 0) + return 0; + + if (errno != ENOSYS) + return -errno; + + no_pipe2 = 1; + +skip: +#endif + + if (pipe(fds)) + return -errno; + + uv__cloexec(fds[0], 1); + uv__cloexec(fds[1], 1); + + if (flags & UV__F_NONBLOCK) { + uv__nonblock(fds[0], 1); + uv__nonblock(fds[1], 1); + } + + return 0; +} + + +/* + * Used for initializing stdio streams like options.stdin_stream. Returns + * zero on success. See also the cleanup section in uv_spawn(). + */ +static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { + int mask; + int fd; + + mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM; + + switch (container->flags & mask) { + case UV_IGNORE: + return 0; + + case UV_CREATE_PIPE: + assert(container->data.stream != NULL); + if (container->data.stream->type != UV_NAMED_PIPE) + return -EINVAL; + else + return uv__make_socketpair(fds, 0); + + case UV_INHERIT_FD: + case UV_INHERIT_STREAM: + if (container->flags & UV_INHERIT_FD) + fd = container->data.fd; + else + fd = uv__stream_fd(container->data.stream); + + if (fd == -1) + return -EINVAL; + + fds[1] = fd; + return 0; + + default: + assert(0 && "Unexpected flags"); + return -EINVAL; + } +} + + +static int uv__process_open_stream(uv_stdio_container_t* container, + int pipefds[2], + int writable) { + int flags; + int err; + + if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0) + return 0; + + err = uv__close(pipefds[1]); + if (err != 0) + abort(); + + pipefds[1] = -1; + uv__nonblock(pipefds[0], 1); + + if (container->data.stream->type == UV_NAMED_PIPE && + ((uv_pipe_t*)container->data.stream)->ipc) + flags = UV_STREAM_READABLE | UV_STREAM_WRITABLE; + else if (writable) + flags = UV_STREAM_WRITABLE; + else + flags = UV_STREAM_READABLE; + + return uv__stream_open(container->data.stream, pipefds[0], flags); +} + + +static void uv__process_close_stream(uv_stdio_container_t* container) { + if (!(container->flags & UV_CREATE_PIPE)) return; + uv__stream_close((uv_stream_t*)container->data.stream); +} + + +static void uv__write_int(int fd, int val) { + ssize_t n; + + do + n = write(fd, &val, sizeof(val)); + while (n == -1 && errno == EINTR); + + if (n == -1 && errno == EPIPE) + return; /* parent process has quit */ + + assert(n == sizeof(val)); +} + + +#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) +/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be + * avoided. Since this isn't called on those targets, the function + * doesn't even need to be defined for them. + */ +static void uv__process_child_init(const uv_process_options_t* options, + int stdio_count, + int (*pipes)[2], + int error_fd) { + int close_fd; + int use_fd; + int fd; + + if (options->flags & UV_PROCESS_DETACHED) + setsid(); + + /* First duplicate low numbered fds, since it's not safe to duplicate them, + * they could get replaced. Example: swapping stdout and stderr; without + * this fd 2 (stderr) would be duplicated into fd 1, thus making both + * stdout and stderr go to the same fd, which was not the intention. */ + for (fd = 0; fd < stdio_count; fd++) { + use_fd = pipes[fd][1]; + if (use_fd < 0 || use_fd >= fd) + continue; + pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); + if (pipes[fd][1] == -1) { + uv__write_int(error_fd, -errno); + _exit(127); + } + } + + for (fd = 0; fd < stdio_count; fd++) { + close_fd = pipes[fd][0]; + use_fd = pipes[fd][1]; + + if (use_fd < 0) { + if (fd >= 3) + continue; + else { + /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is + * set + */ + use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); + close_fd = use_fd; + + if (use_fd == -1) { + uv__write_int(error_fd, -errno); + _exit(127); + } + } + } + + if (fd == use_fd) + uv__cloexec(use_fd, 0); + else + fd = dup2(use_fd, fd); + + if (fd == -1) { + uv__write_int(error_fd, -errno); + _exit(127); + } + + if (fd <= 2) + uv__nonblock(fd, 0); + + if (close_fd >= stdio_count) + uv__close(close_fd); + } + + for (fd = 0; fd < stdio_count; fd++) { + use_fd = pipes[fd][1]; + + if (use_fd >= stdio_count) + uv__close(use_fd); + } + + if (options->cwd != NULL && chdir(options->cwd)) { + uv__write_int(error_fd, -errno); + _exit(127); + } + + if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) { + /* When dropping privileges from root, the `setgroups` call will + * remove any extraneous groups. If we don't call this, then + * even though our uid has dropped, we may still have groups + * that enable us to do super-user things. This will fail if we + * aren't root, so don't bother checking the return value, this + * is just done as an optimistic privilege dropping function. + */ + SAVE_ERRNO(setgroups(0, NULL)); + } + + if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) { + uv__write_int(error_fd, -errno); + _exit(127); + } + + if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) { + uv__write_int(error_fd, -errno); + _exit(127); + } + + if (options->env != NULL) { + environ = options->env; + } + + execvp(options->file, options->args); + uv__write_int(error_fd, -errno); + _exit(127); +} +#endif + + +int uv_spawn(uv_loop_t* loop, + uv_process_t* process, + const uv_process_options_t* options) { +#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) + /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */ + return -ENOSYS; +#else + int signal_pipe[2] = { -1, -1 }; + int (*pipes)[2]; + int stdio_count; + ssize_t r; + pid_t pid; + int err; + int exec_errorno; + int i; + int status; + + assert(options->file != NULL); + assert(!(options->flags & ~(UV_PROCESS_DETACHED | + UV_PROCESS_SETGID | + UV_PROCESS_SETUID | + UV_PROCESS_WINDOWS_HIDE | + UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); + + uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); + QUEUE_INIT(&process->queue); + + stdio_count = options->stdio_count; + if (stdio_count < 3) + stdio_count = 3; + + err = -ENOMEM; + pipes = uv__malloc(stdio_count * sizeof(*pipes)); + if (pipes == NULL) + goto error; + + for (i = 0; i < stdio_count; i++) { + pipes[i][0] = -1; + pipes[i][1] = -1; + } + + for (i = 0; i < options->stdio_count; i++) { + err = uv__process_init_stdio(options->stdio + i, pipes[i]); + if (err) + goto error; + } + + /* This pipe is used by the parent to wait until + * the child has called `execve()`. We need this + * to avoid the following race condition: + * + * if ((pid = fork()) > 0) { + * kill(pid, SIGTERM); + * } + * else if (pid == 0) { + * execve("/bin/cat", argp, envp); + * } + * + * The parent sends a signal immediately after forking. + * Since the child may not have called `execve()` yet, + * there is no telling what process receives the signal, + * our fork or /bin/cat. + * + * To avoid ambiguity, we create a pipe with both ends + * marked close-on-exec. Then, after the call to `fork()`, + * the parent polls the read end until it EOFs or errors with EPIPE. + */ + err = uv__make_pipe(signal_pipe, 0); + if (err) + goto error; + + uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); + + /* Acquire write lock to prevent opening new fds in worker threads */ + uv_rwlock_wrlock(&loop->cloexec_lock); + pid = fork(); + + if (pid == -1) { + err = -errno; + uv_rwlock_wrunlock(&loop->cloexec_lock); + uv__close(signal_pipe[0]); + uv__close(signal_pipe[1]); + goto error; + } + + if (pid == 0) { + uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]); + abort(); + } + + /* Release lock in parent process */ + uv_rwlock_wrunlock(&loop->cloexec_lock); + uv__close(signal_pipe[1]); + + process->status = 0; + exec_errorno = 0; + do + r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno)); + while (r == -1 && errno == EINTR); + + if (r == 0) + ; /* okay, EOF */ + else if (r == sizeof(exec_errorno)) { + do + err = waitpid(pid, &status, 0); /* okay, read errorno */ + while (err == -1 && errno == EINTR); + assert(err == pid); + } else if (r == -1 && errno == EPIPE) { + do + err = waitpid(pid, &status, 0); /* okay, got EPIPE */ + while (err == -1 && errno == EINTR); + assert(err == pid); + } else + abort(); + + uv__close_nocheckstdio(signal_pipe[0]); + + for (i = 0; i < options->stdio_count; i++) { + err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0); + if (err == 0) + continue; + + while (i--) + uv__process_close_stream(options->stdio + i); + + goto error; + } + + /* Only activate this handle if exec() happened successfully */ + if (exec_errorno == 0) { + QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue); + uv__handle_start(process); + } + + process->pid = pid; + process->exit_cb = options->exit_cb; + + uv__free(pipes); + return exec_errorno; + +error: + if (pipes != NULL) { + for (i = 0; i < stdio_count; i++) { + if (i < options->stdio_count) + if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM)) + continue; + if (pipes[i][0] != -1) + uv__close_nocheckstdio(pipes[i][0]); + if (pipes[i][1] != -1) + uv__close_nocheckstdio(pipes[i][1]); + } + uv__free(pipes); + } + + return err; +#endif +} + + +int uv_process_kill(uv_process_t* process, int signum) { + return uv_kill(process->pid, signum); +} + + +int uv_kill(int pid, int signum) { + if (kill(pid, signum)) + return -errno; + else + return 0; +} + + +void uv__process_close(uv_process_t* handle) { + QUEUE_REMOVE(&handle->queue); + uv__handle_stop(handle); + if (QUEUE_EMPTY(&handle->loop->process_handles)) + uv_signal_stop(&handle->loop->child_watcher); +} diff --git a/src/unix/proctitle.c b/src/unix/proctitle.c new file mode 100644 index 0000000..08d875f --- /dev/null +++ b/src/unix/proctitle.c @@ -0,0 +1,105 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +extern void uv__set_process_title(const char* title); + +static void* args_mem; + +static struct { + char* str; + size_t len; +} process_title; + + +char** uv_setup_args(int argc, char** argv) { + char** new_argv; + size_t size; + char* s; + int i; + + if (argc <= 0) + return argv; + + /* Calculate how much memory we need for the argv strings. */ + size = 0; + for (i = 0; i < argc; i++) + size += strlen(argv[i]) + 1; + + process_title.str = argv[0]; + process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0]; + assert(process_title.len + 1 == size); /* argv memory should be adjacent. */ + + /* Add space for the argv pointers. */ + size += (argc + 1) * sizeof(char*); + + new_argv = uv__malloc(size); + if (new_argv == NULL) + return argv; + args_mem = new_argv; + + /* Copy over the strings and set up the pointer table. */ + s = (char*) &new_argv[argc + 1]; + for (i = 0; i < argc; i++) { + size = strlen(argv[i]) + 1; + memcpy(s, argv[i], size); + new_argv[i] = s; + s += size; + } + new_argv[i] = NULL; + + return new_argv; +} + + +int uv_set_process_title(const char* title) { + if (process_title.len == 0) + return 0; + + /* No need to terminate, byte after is always '\0'. */ + strncpy(process_title.str, title, process_title.len); + uv__set_process_title(title); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + if (buffer == NULL || size == 0) + return -EINVAL; + else if (size <= process_title.len) + return -ENOBUFS; + + memcpy(buffer, process_title.str, process_title.len + 1); + buffer[process_title.len] = '\0'; + + return 0; +} + + +UV_DESTRUCTOR(static void free_args_mem(void)) { + uv__free(args_mem); /* Keep valgrind happy. */ + args_mem = NULL; +} diff --git a/src/unix/pthread-barrier.c b/src/unix/pthread-barrier.c new file mode 100644 index 0000000..f57bf25 --- /dev/null +++ b/src/unix/pthread-barrier.c @@ -0,0 +1,120 @@ +/* +Copyright (c) 2016, Kari Tristan Helgason + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +#include "uv-common.h" +#include "pthread-barrier.h" + +#include +#include + +/* TODO: support barrier_attr */ +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || count == 0) + return EINVAL; + + if (barrier_attr != NULL) + return ENOTSUP; + + b = uv__malloc(sizeof(*b)); + if (b == NULL) + return ENOMEM; + + b->in = 0; + b->out = 0; + b->threshold = count; + + if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) + goto error2; + if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) + goto error; + + barrier->b = b; + return 0; + +error: + pthread_mutex_destroy(&b->mutex); +error2: + uv__free(b); + return rc; +} + +int pthread_barrier_wait(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + /* Lock the mutex*/ + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + /* Increment the count. If this is the first thread to reach the threshold, + wake up waiters, unlock the mutex, then return + PTHREAD_BARRIER_SERIAL_THREAD. */ + if (++b->in == b->threshold) { + b->in = 0; + b->out = b->threshold - 1; + assert(pthread_cond_signal(&b->cond) == 0); + + pthread_mutex_unlock(&b->mutex); + return PTHREAD_BARRIER_SERIAL_THREAD; + } + /* Otherwise, wait for other threads until in is set to 0, + then return 0 to indicate this is not the first thread. */ + do { + if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) + break; + } while (b->in != 0); + + /* mark thread exit */ + b->out--; + pthread_cond_signal(&b->cond); + pthread_mutex_unlock(&b->mutex); + return rc; +} + +int pthread_barrier_destroy(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + if (b->in > 0 || b->out > 0) + rc = EBUSY; + + pthread_mutex_unlock(&b->mutex); + + if (rc) + return rc; + + pthread_cond_destroy(&b->cond); + pthread_mutex_destroy(&b->mutex); + uv__free(barrier->b); + barrier->b = NULL; + return 0; +} diff --git a/src/unix/pthread-fixes.c b/src/unix/pthread-fixes.c new file mode 100644 index 0000000..fb17995 --- /dev/null +++ b/src/unix/pthread-fixes.c @@ -0,0 +1,56 @@ +/* Copyright (c) 2013, Sony Mobile Communications AB + * Copyright (c) 2012, 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. +*/ + +/* Android versions < 4.1 have a broken pthread_sigmask. */ +#include +#include +#include + +int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) { + static int workaround; + int err; + + if (workaround) { + return sigprocmask(how, set, oset); + } else { + err = pthread_sigmask(how, set, oset); + if (err) { + if (err == EINVAL && sigprocmask(how, set, oset) == 0) { + workaround = 1; + return 0; + } else { + return -1; + } + } + } + + return 0; +} diff --git a/src/unix/signal.c b/src/unix/signal.c new file mode 100644 index 0000000..d82b9b7 --- /dev/null +++ b/src/unix/signal.c @@ -0,0 +1,467 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + + +typedef struct { + uv_signal_t* handle; + int signum; +} uv__signal_msg_t; + +RB_HEAD(uv__signal_tree_s, uv_signal_s); + + +static int uv__signal_unlock(void); +static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events); +static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2); +static void uv__signal_stop(uv_signal_t* handle); + + +static pthread_once_t uv__signal_global_init_guard = PTHREAD_ONCE_INIT; +static struct uv__signal_tree_s uv__signal_tree = + RB_INITIALIZER(uv__signal_tree); +static int uv__signal_lock_pipefd[2]; + + +RB_GENERATE_STATIC(uv__signal_tree_s, + uv_signal_s, tree_entry, + uv__signal_compare) + + +static void uv__signal_global_init(void) { + if (uv__make_pipe(uv__signal_lock_pipefd, 0)) + abort(); + + if (uv__signal_unlock()) + abort(); +} + + +void uv__signal_global_once_init(void) { + pthread_once(&uv__signal_global_init_guard, uv__signal_global_init); +} + + + +static int uv__signal_lock(void) { + int r; + char data; + + do { + r = read(uv__signal_lock_pipefd[0], &data, sizeof data); + } while (r < 0 && errno == EINTR); + + return (r < 0) ? -1 : 0; +} + + +static int uv__signal_unlock(void) { + int r; + char data = 42; + + do { + r = write(uv__signal_lock_pipefd[1], &data, sizeof data); + } while (r < 0 && errno == EINTR); + + return (r < 0) ? -1 : 0; +} + + +static void uv__signal_block_and_lock(sigset_t* saved_sigmask) { + sigset_t new_mask; + + if (sigfillset(&new_mask)) + abort(); + + if (pthread_sigmask(SIG_SETMASK, &new_mask, saved_sigmask)) + abort(); + + if (uv__signal_lock()) + abort(); +} + + +static void uv__signal_unlock_and_unblock(sigset_t* saved_sigmask) { + if (uv__signal_unlock()) + abort(); + + if (pthread_sigmask(SIG_SETMASK, saved_sigmask, NULL)) + abort(); +} + + +static uv_signal_t* uv__signal_first_handle(int signum) { + /* This function must be called with the signal lock held. */ + uv_signal_t lookup; + uv_signal_t* handle; + + lookup.signum = signum; + lookup.loop = NULL; + + handle = RB_NFIND(uv__signal_tree_s, &uv__signal_tree, &lookup); + + if (handle != NULL && handle->signum == signum) + return handle; + + return NULL; +} + + +static void uv__signal_handler(int signum) { + uv__signal_msg_t msg; + uv_signal_t* handle; + int saved_errno; + + saved_errno = errno; + memset(&msg, 0, sizeof msg); + + if (uv__signal_lock()) { + errno = saved_errno; + return; + } + + for (handle = uv__signal_first_handle(signum); + handle != NULL && handle->signum == signum; + handle = RB_NEXT(uv__signal_tree_s, &uv__signal_tree, handle)) { + int r; + + msg.signum = signum; + msg.handle = handle; + + /* write() should be atomic for small data chunks, so the entire message + * should be written at once. In theory the pipe could become full, in + * which case the user is out of luck. + */ + do { + r = write(handle->loop->signal_pipefd[1], &msg, sizeof msg); + } while (r == -1 && errno == EINTR); + + assert(r == sizeof msg || + (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))); + + if (r != -1) + handle->caught_signals++; + } + + uv__signal_unlock(); + errno = saved_errno; +} + + +static int uv__signal_register_handler(int signum) { + /* When this function is called, the signal lock must be held. */ + struct sigaction sa; + + /* XXX use a separate signal stack? */ + memset(&sa, 0, sizeof(sa)); + if (sigfillset(&sa.sa_mask)) + abort(); + sa.sa_handler = uv__signal_handler; + + /* XXX save old action so we can restore it later on? */ + if (sigaction(signum, &sa, NULL)) + return -errno; + + return 0; +} + + +static void uv__signal_unregister_handler(int signum) { + /* When this function is called, the signal lock must be held. */ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + + /* sigaction can only fail with EINVAL or EFAULT; an attempt to deregister a + * signal implies that it was successfully registered earlier, so EINVAL + * should never happen. + */ + if (sigaction(signum, &sa, NULL)) + abort(); +} + + +static int uv__signal_loop_once_init(uv_loop_t* loop) { + int err; + + /* Return if already initialized. */ + if (loop->signal_pipefd[0] != -1) + return 0; + + err = uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK); + if (err) + return err; + + uv__io_init(&loop->signal_io_watcher, + uv__signal_event, + loop->signal_pipefd[0]); + uv__io_start(loop, &loop->signal_io_watcher, POLLIN); + + return 0; +} + + +void uv__signal_loop_cleanup(uv_loop_t* loop) { + QUEUE* q; + + /* Stop all the signal watchers that are still attached to this loop. This + * ensures that the (shared) signal tree doesn't contain any invalid entries + * entries, and that signal handlers are removed when appropriate. + * It's safe to use QUEUE_FOREACH here because the handles and the handle + * queue are not modified by uv__signal_stop(). + */ + QUEUE_FOREACH(q, &loop->handle_queue) { + uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue); + + if (handle->type == UV_SIGNAL) + uv__signal_stop((uv_signal_t*) handle); + } + + if (loop->signal_pipefd[0] != -1) { + uv__close(loop->signal_pipefd[0]); + loop->signal_pipefd[0] = -1; + } + + if (loop->signal_pipefd[1] != -1) { + uv__close(loop->signal_pipefd[1]); + loop->signal_pipefd[1] = -1; + } +} + + +int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { + int err; + + err = uv__signal_loop_once_init(loop); + if (err) + return err; + + uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL); + handle->signum = 0; + handle->caught_signals = 0; + handle->dispatched_signals = 0; + + return 0; +} + + +void uv__signal_close(uv_signal_t* handle) { + + uv__signal_stop(handle); + + /* If there are any caught signals "trapped" in the signal pipe, we can't + * call the close callback yet. Otherwise, add the handle to the finish_close + * queue. + */ + if (handle->caught_signals == handle->dispatched_signals) { + uv__make_close_pending((uv_handle_t*) handle); + } +} + + +int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { + sigset_t saved_sigmask; + int err; + + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + + /* If the user supplies signum == 0, then return an error already. If the + * signum is otherwise invalid then uv__signal_register will find out + * eventually. + */ + if (signum == 0) + return -EINVAL; + + /* Short circuit: if the signal watcher is already watching {signum} don't + * go through the process of deregistering and registering the handler. + * Additionally, this avoids pending signals getting lost in the small time + * time frame that handle->signum == 0. + */ + if (signum == handle->signum) { + handle->signal_cb = signal_cb; + return 0; + } + + /* If the signal handler was already active, stop it first. */ + if (handle->signum != 0) { + uv__signal_stop(handle); + } + + uv__signal_block_and_lock(&saved_sigmask); + + /* If at this point there are no active signal watchers for this signum (in + * any of the loops), it's time to try and register a handler for it here. + */ + if (uv__signal_first_handle(signum) == NULL) { + err = uv__signal_register_handler(signum); + if (err) { + /* Registering the signal handler failed. Must be an invalid signal. */ + uv__signal_unlock_and_unblock(&saved_sigmask); + return err; + } + } + + handle->signum = signum; + RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle); + + uv__signal_unlock_and_unblock(&saved_sigmask); + + handle->signal_cb = signal_cb; + uv__handle_start(handle); + + return 0; +} + + +static void uv__signal_event(uv_loop_t* loop, + uv__io_t* w, + unsigned int events) { + uv__signal_msg_t* msg; + uv_signal_t* handle; + char buf[sizeof(uv__signal_msg_t) * 32]; + size_t bytes, end, i; + int r; + + bytes = 0; + end = 0; + + do { + r = read(loop->signal_pipefd[0], buf + bytes, sizeof(buf) - bytes); + + if (r == -1 && errno == EINTR) + continue; + + if (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { + /* If there are bytes in the buffer already (which really is extremely + * unlikely if possible at all) we can't exit the function here. We'll + * spin until more bytes are read instead. + */ + if (bytes > 0) + continue; + + /* Otherwise, there was nothing there. */ + return; + } + + /* Other errors really should never happen. */ + if (r == -1) + abort(); + + bytes += r; + + /* `end` is rounded down to a multiple of sizeof(uv__signal_msg_t). */ + end = (bytes / sizeof(uv__signal_msg_t)) * sizeof(uv__signal_msg_t); + + for (i = 0; i < end; i += sizeof(uv__signal_msg_t)) { + msg = (uv__signal_msg_t*) (buf + i); + handle = msg->handle; + + if (msg->signum == handle->signum) { + assert(!(handle->flags & UV_CLOSING)); + handle->signal_cb(handle, handle->signum); + } + + handle->dispatched_signals++; + + /* If uv_close was called while there were caught signals that were not + * yet dispatched, the uv__finish_close was deferred. Make close pending + * now if this has happened. + */ + if ((handle->flags & UV_CLOSING) && + (handle->caught_signals == handle->dispatched_signals)) { + uv__make_close_pending((uv_handle_t*) handle); + } + } + + bytes -= end; + + /* If there are any "partial" messages left, move them to the start of the + * the buffer, and spin. This should not happen. + */ + if (bytes) { + memmove(buf, buf + end, bytes); + continue; + } + } while (end == sizeof buf); +} + + +static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { + /* Compare signums first so all watchers with the same signnum end up + * adjacent. + */ + if (w1->signum < w2->signum) return -1; + if (w1->signum > w2->signum) return 1; + + /* Sort by loop pointer, so we can easily look up the first item after + * { .signum = x, .loop = NULL }. + */ + if (w1->loop < w2->loop) return -1; + if (w1->loop > w2->loop) return 1; + + if (w1 < w2) return -1; + if (w1 > w2) return 1; + + return 0; +} + + +int uv_signal_stop(uv_signal_t* handle) { + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + uv__signal_stop(handle); + return 0; +} + + +static void uv__signal_stop(uv_signal_t* handle) { + uv_signal_t* removed_handle; + sigset_t saved_sigmask; + + /* If the watcher wasn't started, this is a no-op. */ + if (handle->signum == 0) + return; + + uv__signal_block_and_lock(&saved_sigmask); + + removed_handle = RB_REMOVE(uv__signal_tree_s, &uv__signal_tree, handle); + assert(removed_handle == handle); + (void) removed_handle; + + /* Check if there are other active signal watchers observing this signal. If + * not, unregister the signal handler. + */ + if (uv__signal_first_handle(handle->signum) == NULL) + uv__signal_unregister_handler(handle->signum); + + uv__signal_unlock_and_unblock(&saved_sigmask); + + handle->signum = 0; + uv__handle_stop(handle); +} diff --git a/src/unix/spinlock.h b/src/unix/spinlock.h new file mode 100644 index 0000000..a20c83c --- /dev/null +++ b/src/unix/spinlock.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef UV_SPINLOCK_H_ +#define UV_SPINLOCK_H_ + +#include "internal.h" /* ACCESS_ONCE, UV_UNUSED */ +#include "atomic-ops.h" + +#define UV_SPINLOCK_INITIALIZER { 0 } + +typedef struct { + int lock; +} uv_spinlock_t; + +UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)); +UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)); +UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)); +UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)); + +UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)) { + ACCESS_ONCE(int, spinlock->lock) = 0; +} + +UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)) { + while (!uv_spinlock_trylock(spinlock)) cpu_relax(); +} + +UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)) { + ACCESS_ONCE(int, spinlock->lock) = 0; +} + +UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)) { + /* TODO(bnoordhuis) Maybe change to a ticket lock to guarantee fair queueing. + * Not really critical until we have locks that are (frequently) contended + * for by several threads. + */ + return 0 == cmpxchgi(&spinlock->lock, 0, 1); +} + +#endif /* UV_SPINLOCK_H_ */ diff --git a/src/unix/stream.c b/src/unix/stream.c new file mode 100644 index 0000000..d20d0bc --- /dev/null +++ b/src/unix/stream.c @@ -0,0 +1,1638 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include /* IOV_MAX */ + +#if defined(__APPLE__) +# include +# include +# include + +/* Forward declaration */ +typedef struct uv__stream_select_s uv__stream_select_t; + +struct uv__stream_select_s { + uv_stream_t* stream; + uv_thread_t thread; + uv_sem_t close_sem; + uv_sem_t async_sem; + uv_async_t async; + int events; + int fake_fd; + int int_fd; + int fd; + fd_set* sread; + size_t sread_sz; + fd_set* swrite; + size_t swrite_sz; +}; +#endif /* defined(__APPLE__) */ + +static void uv__stream_connect(uv_stream_t*); +static void uv__write(uv_stream_t* stream); +static void uv__read(uv_stream_t* stream); +static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); +static void uv__write_callbacks(uv_stream_t* stream); +static size_t uv__write_req_size(uv_write_t* req); + + +void uv__stream_init(uv_loop_t* loop, + uv_stream_t* stream, + uv_handle_type type) { + int err; + + uv__handle_init(loop, (uv_handle_t*)stream, type); + stream->read_cb = NULL; + stream->alloc_cb = NULL; + stream->close_cb = NULL; + stream->connection_cb = NULL; + stream->connect_req = NULL; + stream->shutdown_req = NULL; + stream->accepted_fd = -1; + stream->queued_fds = NULL; + stream->delayed_error = 0; + QUEUE_INIT(&stream->write_queue); + QUEUE_INIT(&stream->write_completed_queue); + stream->write_queue_size = 0; + + if (loop->emfile_fd == -1) { + err = uv__open_cloexec("/dev/null", O_RDONLY); + if (err < 0) + /* In the rare case that "/dev/null" isn't mounted open "/" + * instead. + */ + err = uv__open_cloexec("/", O_RDONLY); + if (err >= 0) + loop->emfile_fd = err; + } + +#if defined(__APPLE__) + stream->select = NULL; +#endif /* defined(__APPLE_) */ + + uv__io_init(&stream->io_watcher, uv__stream_io, -1); +} + + +static void uv__stream_osx_interrupt_select(uv_stream_t* stream) { +#if defined(__APPLE__) + /* Notify select() thread about state change */ + uv__stream_select_t* s; + int r; + + s = stream->select; + if (s == NULL) + return; + + /* Interrupt select() loop + * NOTE: fake_fd and int_fd are socketpair(), thus writing to one will + * emit read event on other side + */ + do + r = write(s->fake_fd, "x", 1); + while (r == -1 && errno == EINTR); + + assert(r == 1); +#else /* !defined(__APPLE__) */ + /* No-op on any other platform */ +#endif /* !defined(__APPLE__) */ +} + + +#if defined(__APPLE__) +static void uv__stream_osx_select(void* arg) { + uv_stream_t* stream; + uv__stream_select_t* s; + char buf[1024]; + int events; + int fd; + int r; + int max_fd; + + stream = arg; + s = stream->select; + fd = s->fd; + + if (fd > s->int_fd) + max_fd = fd; + else + max_fd = s->int_fd; + + while (1) { + /* Terminate on semaphore */ + if (uv_sem_trywait(&s->close_sem) == 0) + break; + + /* Watch fd using select(2) */ + memset(s->sread, 0, s->sread_sz); + memset(s->swrite, 0, s->swrite_sz); + + if (uv__io_active(&stream->io_watcher, POLLIN)) + FD_SET(fd, s->sread); + if (uv__io_active(&stream->io_watcher, POLLOUT)) + FD_SET(fd, s->swrite); + FD_SET(s->int_fd, s->sread); + + /* Wait indefinitely for fd events */ + r = select(max_fd + 1, s->sread, s->swrite, NULL, NULL); + if (r == -1) { + if (errno == EINTR) + continue; + + /* XXX: Possible?! */ + abort(); + } + + /* Ignore timeouts */ + if (r == 0) + continue; + + /* Empty socketpair's buffer in case of interruption */ + if (FD_ISSET(s->int_fd, s->sread)) + while (1) { + r = read(s->int_fd, buf, sizeof(buf)); + + if (r == sizeof(buf)) + continue; + + if (r != -1) + break; + + if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + + if (errno == EINTR) + continue; + + abort(); + } + + /* Handle events */ + events = 0; + if (FD_ISSET(fd, s->sread)) + events |= POLLIN; + if (FD_ISSET(fd, s->swrite)) + events |= POLLOUT; + + assert(events != 0 || FD_ISSET(s->int_fd, s->sread)); + if (events != 0) { + ACCESS_ONCE(int, s->events) = events; + + uv_async_send(&s->async); + uv_sem_wait(&s->async_sem); + + /* Should be processed at this stage */ + assert((s->events == 0) || (stream->flags & UV_CLOSING)); + } + } +} + + +static void uv__stream_osx_select_cb(uv_async_t* handle) { + uv__stream_select_t* s; + uv_stream_t* stream; + int events; + + s = container_of(handle, uv__stream_select_t, async); + stream = s->stream; + + /* Get and reset stream's events */ + events = s->events; + ACCESS_ONCE(int, s->events) = 0; + + assert(events != 0); + assert(events == (events & (POLLIN | POLLOUT))); + + /* Invoke callback on event-loop */ + if ((events & POLLIN) && uv__io_active(&stream->io_watcher, POLLIN)) + uv__stream_io(stream->loop, &stream->io_watcher, POLLIN); + + if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT)) + uv__stream_io(stream->loop, &stream->io_watcher, POLLOUT); + + if (stream->flags & UV_CLOSING) + return; + + /* NOTE: It is important to do it here, otherwise `select()` might be called + * before the actual `uv__read()`, leading to the blocking syscall + */ + uv_sem_post(&s->async_sem); +} + + +static void uv__stream_osx_cb_close(uv_handle_t* async) { + uv__stream_select_t* s; + + s = container_of(async, uv__stream_select_t, async); + uv__free(s); +} + + +int uv__stream_try_select(uv_stream_t* stream, int* fd) { + /* + * kqueue doesn't work with some files from /dev mount on osx. + * select(2) in separate thread for those fds + */ + + struct kevent filter[1]; + struct kevent events[1]; + struct timespec timeout; + uv__stream_select_t* s; + int fds[2]; + int err; + int ret; + int kq; + int old_fd; + int max_fd; + size_t sread_sz; + size_t swrite_sz; + + kq = kqueue(); + if (kq == -1) { + perror("(libuv) kqueue()"); + return -errno; + } + + EV_SET(&filter[0], *fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); + + /* Use small timeout, because we only want to capture EINVALs */ + timeout.tv_sec = 0; + timeout.tv_nsec = 1; + + do + ret = kevent(kq, filter, 1, events, 1, &timeout); + while (ret == -1 && errno == EINTR); + + uv__close(kq); + + if (ret == -1) + return -errno; + + if (ret == 0 || (events[0].flags & EV_ERROR) == 0 || events[0].data != EINVAL) + return 0; + + /* At this point we definitely know that this fd won't work with kqueue */ + + /* + * Create fds for io watcher and to interrupt the select() loop. + * NOTE: do it ahead of malloc below to allocate enough space for fd_sets + */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) + return -errno; + + max_fd = *fd; + if (fds[1] > max_fd) + max_fd = fds[1]; + + sread_sz = ROUND_UP(max_fd + 1, sizeof(uint32_t) * NBBY) / NBBY; + swrite_sz = sread_sz; + + s = uv__malloc(sizeof(*s) + sread_sz + swrite_sz); + if (s == NULL) { + err = -ENOMEM; + goto failed_malloc; + } + + s->events = 0; + s->fd = *fd; + s->sread = (fd_set*) ((char*) s + sizeof(*s)); + s->sread_sz = sread_sz; + s->swrite = (fd_set*) ((char*) s->sread + sread_sz); + s->swrite_sz = swrite_sz; + + err = uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb); + if (err) + goto failed_async_init; + + s->async.flags |= UV__HANDLE_INTERNAL; + uv__handle_unref(&s->async); + + err = uv_sem_init(&s->close_sem, 0); + if (err != 0) + goto failed_close_sem_init; + + err = uv_sem_init(&s->async_sem, 0); + if (err != 0) + goto failed_async_sem_init; + + s->fake_fd = fds[0]; + s->int_fd = fds[1]; + + old_fd = *fd; + s->stream = stream; + stream->select = s; + *fd = s->fake_fd; + + err = uv_thread_create(&s->thread, uv__stream_osx_select, stream); + if (err != 0) + goto failed_thread_create; + + return 0; + +failed_thread_create: + s->stream = NULL; + stream->select = NULL; + *fd = old_fd; + + uv_sem_destroy(&s->async_sem); + +failed_async_sem_init: + uv_sem_destroy(&s->close_sem); + +failed_close_sem_init: + uv__close(fds[0]); + uv__close(fds[1]); + uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close); + return err; + +failed_async_init: + uv__free(s); + +failed_malloc: + uv__close(fds[0]); + uv__close(fds[1]); + + return err; +} +#endif /* defined(__APPLE__) */ + + +int uv__stream_open(uv_stream_t* stream, int fd, int flags) { +#if defined(__APPLE__) + int enable; +#endif + + if (!(stream->io_watcher.fd == -1 || stream->io_watcher.fd == fd)) + return -EBUSY; + + assert(fd >= 0); + stream->flags |= flags; + + if (stream->type == UV_TCP) { + if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) + return -errno; + + /* TODO Use delay the user passed in. */ + if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60)) + return -errno; + } + +#if defined(__APPLE__) + enable = 1; + if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) && + errno != ENOTSOCK && + errno != EINVAL) { + return -errno; + } +#endif + + stream->io_watcher.fd = fd; + + return 0; +} + + +void uv__stream_flush_write_queue(uv_stream_t* stream, int error) { + uv_write_t* req; + QUEUE* q; + while (!QUEUE_EMPTY(&stream->write_queue)) { + q = QUEUE_HEAD(&stream->write_queue); + QUEUE_REMOVE(q); + + req = QUEUE_DATA(q, uv_write_t, queue); + req->error = error; + + QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue); + } +} + + +void uv__stream_destroy(uv_stream_t* stream) { + assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT)); + assert(stream->flags & UV_CLOSED); + + if (stream->connect_req) { + uv__req_unregister(stream->loop, stream->connect_req); + stream->connect_req->cb(stream->connect_req, -ECANCELED); + stream->connect_req = NULL; + } + + uv__stream_flush_write_queue(stream, -ECANCELED); + uv__write_callbacks(stream); + + if (stream->shutdown_req) { + /* The ECANCELED error code is a lie, the shutdown(2) syscall is a + * fait accompli at this point. Maybe we should revisit this in v0.11. + * A possible reason for leaving it unchanged is that it informs the + * callee that the handle has been destroyed. + */ + uv__req_unregister(stream->loop, stream->shutdown_req); + stream->shutdown_req->cb(stream->shutdown_req, -ECANCELED); + stream->shutdown_req = NULL; + } + + assert(stream->write_queue_size == 0); +} + + +/* Implements a best effort approach to mitigating accept() EMFILE errors. + * We have a spare file descriptor stashed away that we close to get below + * the EMFILE limit. Next, we accept all pending connections and close them + * immediately to signal the clients that we're overloaded - and we are, but + * we still keep on trucking. + * + * There is one caveat: it's not reliable in a multi-threaded environment. + * The file descriptor limit is per process. Our party trick fails if another + * thread opens a file or creates a socket in the time window between us + * calling close() and accept(). + */ +static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) { + int err; + int emfile_fd; + + if (loop->emfile_fd == -1) + return -EMFILE; + + uv__close(loop->emfile_fd); + loop->emfile_fd = -1; + + do { + err = uv__accept(accept_fd); + if (err >= 0) + uv__close(err); + } while (err >= 0 || err == -EINTR); + + emfile_fd = uv__open_cloexec("/", O_RDONLY); + if (emfile_fd >= 0) + loop->emfile_fd = emfile_fd; + + return err; +} + + +#if defined(UV_HAVE_KQUEUE) +# define UV_DEC_BACKLOG(w) w->rcount--; +#else +# define UV_DEC_BACKLOG(w) /* no-op */ +#endif /* defined(UV_HAVE_KQUEUE) */ + + +void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + uv_stream_t* stream; + int err; + + stream = container_of(w, uv_stream_t, io_watcher); + assert(events == POLLIN); + assert(stream->accepted_fd == -1); + assert(!(stream->flags & UV_CLOSING)); + + uv__io_start(stream->loop, &stream->io_watcher, POLLIN); + + /* connection_cb can close the server socket while we're + * in the loop so check it on each iteration. + */ + while (uv__stream_fd(stream) != -1) { + assert(stream->accepted_fd == -1); + +#if defined(UV_HAVE_KQUEUE) + if (w->rcount <= 0) + return; +#endif /* defined(UV_HAVE_KQUEUE) */ + + err = uv__accept(uv__stream_fd(stream)); + if (err < 0) { + if (err == -EAGAIN || err == -EWOULDBLOCK) + return; /* Not an error. */ + + if (err == -ECONNABORTED) + continue; /* Ignore. Nothing we can do about that. */ + + if (err == -EMFILE || err == -ENFILE) { + err = uv__emfile_trick(loop, uv__stream_fd(stream)); + if (err == -EAGAIN || err == -EWOULDBLOCK) + break; + } + + stream->connection_cb(stream, err); + continue; + } + + UV_DEC_BACKLOG(w) + stream->accepted_fd = err; + stream->connection_cb(stream, 0); + + if (stream->accepted_fd != -1) { + /* The user hasn't yet accepted called uv_accept() */ + uv__io_stop(loop, &stream->io_watcher, POLLIN); + return; + } + + if (stream->type == UV_TCP && (stream->flags & UV_TCP_SINGLE_ACCEPT)) { + /* Give other processes a chance to accept connections. */ + struct timespec timeout = { 0, 1 }; + nanosleep(&timeout, NULL); + } + } +} + + +#undef UV_DEC_BACKLOG + + +int uv_accept(uv_stream_t* server, uv_stream_t* client) { + int err; + + assert(server->loop == client->loop); + + if (server->accepted_fd == -1) + return -EAGAIN; + + switch (client->type) { + case UV_NAMED_PIPE: + case UV_TCP: + err = uv__stream_open(client, + server->accepted_fd, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); + if (err) { + /* TODO handle error */ + uv__close(server->accepted_fd); + goto done; + } + break; + + case UV_UDP: + err = uv_udp_open((uv_udp_t*) client, server->accepted_fd); + if (err) { + uv__close(server->accepted_fd); + goto done; + } + break; + + default: + return -EINVAL; + } + + client->flags |= UV_HANDLE_BOUND; + +done: + /* Process queued fds */ + if (server->queued_fds != NULL) { + uv__stream_queued_fds_t* queued_fds; + + queued_fds = server->queued_fds; + + /* Read first */ + server->accepted_fd = queued_fds->fds[0]; + + /* All read, free */ + assert(queued_fds->offset > 0); + if (--queued_fds->offset == 0) { + uv__free(queued_fds); + server->queued_fds = NULL; + } else { + /* Shift rest */ + memmove(queued_fds->fds, + queued_fds->fds + 1, + queued_fds->offset * sizeof(*queued_fds->fds)); + } + } else { + server->accepted_fd = -1; + if (err == 0) + uv__io_start(server->loop, &server->io_watcher, POLLIN); + } + return err; +} + + +int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { + int err; + + switch (stream->type) { + case UV_TCP: + err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb); + break; + + case UV_NAMED_PIPE: + err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb); + break; + + default: + err = -EINVAL; + } + + if (err == 0) + uv__handle_start(stream); + + return err; +} + + +static void uv__drain(uv_stream_t* stream) { + uv_shutdown_t* req; + int err; + + assert(QUEUE_EMPTY(&stream->write_queue)); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); + uv__stream_osx_interrupt_select(stream); + + /* Shutdown? */ + if ((stream->flags & UV_STREAM_SHUTTING) && + !(stream->flags & UV_CLOSING) && + !(stream->flags & UV_STREAM_SHUT)) { + assert(stream->shutdown_req); + + req = stream->shutdown_req; + stream->shutdown_req = NULL; + stream->flags &= ~UV_STREAM_SHUTTING; + uv__req_unregister(stream->loop, req); + + err = 0; + if (shutdown(uv__stream_fd(stream), SHUT_WR)) + err = -errno; + + if (err == 0) + stream->flags |= UV_STREAM_SHUT; + + if (req->cb != NULL) + req->cb(req, err); + } +} + + +static size_t uv__write_req_size(uv_write_t* req) { + size_t size; + + assert(req->bufs != NULL); + size = uv__count_bufs(req->bufs + req->write_index, + req->nbufs - req->write_index); + assert(req->handle->write_queue_size >= size); + + return size; +} + + +static void uv__write_req_finish(uv_write_t* req) { + uv_stream_t* stream = req->handle; + + /* Pop the req off tcp->write_queue. */ + QUEUE_REMOVE(&req->queue); + + /* Only free when there was no error. On error, we touch up write_queue_size + * right before making the callback. The reason we don't do that right away + * is that a write_queue_size > 0 is our only way to signal to the user that + * they should stop writing - which they should if we got an error. Something + * to revisit in future revisions of the libuv API. + */ + if (req->error == 0) { + if (req->bufs != req->bufsml) + uv__free(req->bufs); + req->bufs = NULL; + } + + /* Add it to the write_completed_queue where it will have its + * callback called in the near future. + */ + QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue); + uv__io_feed(stream->loop, &stream->io_watcher); +} + + +static int uv__handle_fd(uv_handle_t* handle) { + switch (handle->type) { + case UV_NAMED_PIPE: + case UV_TCP: + return ((uv_stream_t*) handle)->io_watcher.fd; + + case UV_UDP: + return ((uv_udp_t*) handle)->io_watcher.fd; + + default: + return -1; + } +} + +static void uv__write(uv_stream_t* stream) { + struct iovec* iov; + QUEUE* q; + uv_write_t* req; + int iovmax; + int iovcnt; + ssize_t n; + +start: + + assert(uv__stream_fd(stream) >= 0); + + if (QUEUE_EMPTY(&stream->write_queue)) + return; + + q = QUEUE_HEAD(&stream->write_queue); + req = QUEUE_DATA(q, uv_write_t, queue); + assert(req->handle == stream); + + /* + * Cast to iovec. We had to have our own uv_buf_t instead of iovec + * because Windows's WSABUF is not an iovec. + */ + assert(sizeof(uv_buf_t) == sizeof(struct iovec)); + iov = (struct iovec*) &(req->bufs[req->write_index]); + iovcnt = req->nbufs - req->write_index; + + iovmax = uv__getiovmax(); + + /* Limit iov count to avoid EINVALs from writev() */ + if (iovcnt > iovmax) + iovcnt = iovmax; + + /* + * Now do the actual writev. Note that we've been updating the pointers + * inside the iov each time we write. So there is no need to offset it. + */ + + if (req->send_handle) { + struct msghdr msg; + struct cmsghdr *cmsg; + int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); + char scratch[64] = {0}; + + assert(fd_to_send >= 0); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = iovcnt; + msg.msg_flags = 0; + + msg.msg_control = (void*) scratch; + msg.msg_controllen = CMSG_SPACE(sizeof(fd_to_send)); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send)); + + /* silence aliasing warning */ + { + void* pv = CMSG_DATA(cmsg); + int* pi = pv; + *pi = fd_to_send; + } + + do { + n = sendmsg(uv__stream_fd(stream), &msg, 0); + } +#if defined(__APPLE__) + /* + * Due to a possible kernel bug at least in OS X 10.10 "Yosemite", + * EPROTOTYPE can be returned while trying to write to a socket that is + * shutting down. If we retry the write, we should get the expected EPIPE + * instead. + */ + while (n == -1 && (errno == EINTR || errno == EPROTOTYPE)); +#else + while (n == -1 && errno == EINTR); +#endif + } else { + do { + if (iovcnt == 1) { + n = write(uv__stream_fd(stream), iov[0].iov_base, iov[0].iov_len); + } else { + n = writev(uv__stream_fd(stream), iov, iovcnt); + } + } +#if defined(__APPLE__) + /* + * Due to a possible kernel bug at least in OS X 10.10 "Yosemite", + * EPROTOTYPE can be returned while trying to write to a socket that is + * shutting down. If we retry the write, we should get the expected EPIPE + * instead. + */ + while (n == -1 && (errno == EINTR || errno == EPROTOTYPE)); +#else + while (n == -1 && errno == EINTR); +#endif + } + + if (n < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + /* Error */ + req->error = -errno; + uv__write_req_finish(req); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); + if (!uv__io_active(&stream->io_watcher, POLLIN)) + uv__handle_stop(stream); + uv__stream_osx_interrupt_select(stream); + return; + } else if (stream->flags & UV_STREAM_BLOCKING) { + /* If this is a blocking stream, try again. */ + goto start; + } + } else { + /* Successful write */ + + while (n >= 0) { + uv_buf_t* buf = &(req->bufs[req->write_index]); + size_t len = buf->len; + + assert(req->write_index < req->nbufs); + + if ((size_t)n < len) { + buf->base += n; + buf->len -= n; + stream->write_queue_size -= n; + n = 0; + + /* There is more to write. */ + if (stream->flags & UV_STREAM_BLOCKING) { + /* + * If we're blocking then we should not be enabling the write + * watcher - instead we need to try again. + */ + goto start; + } else { + /* Break loop and ensure the watcher is pending. */ + break; + } + + } else { + /* Finished writing the buf at index req->write_index. */ + req->write_index++; + + assert((size_t)n >= len); + n -= len; + + assert(stream->write_queue_size >= len); + stream->write_queue_size -= len; + + if (req->write_index == req->nbufs) { + /* Then we're done! */ + assert(n == 0); + uv__write_req_finish(req); + /* TODO: start trying to write the next request. */ + return; + } + } + } + } + + /* Either we've counted n down to zero or we've got EAGAIN. */ + assert(n == 0 || n == -1); + + /* Only non-blocking streams should use the write_watcher. */ + assert(!(stream->flags & UV_STREAM_BLOCKING)); + + /* We're not done. */ + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); + + /* Notify select() thread about state change */ + uv__stream_osx_interrupt_select(stream); +} + + +static void uv__write_callbacks(uv_stream_t* stream) { + uv_write_t* req; + QUEUE* q; + + while (!QUEUE_EMPTY(&stream->write_completed_queue)) { + /* Pop a req off write_completed_queue. */ + q = QUEUE_HEAD(&stream->write_completed_queue); + req = QUEUE_DATA(q, uv_write_t, queue); + QUEUE_REMOVE(q); + uv__req_unregister(stream->loop, req); + + if (req->bufs != NULL) { + stream->write_queue_size -= uv__write_req_size(req); + if (req->bufs != req->bufsml) + uv__free(req->bufs); + req->bufs = NULL; + } + + /* NOTE: call callback AFTER freeing the request data. */ + if (req->cb) + req->cb(req, req->error); + } + + assert(QUEUE_EMPTY(&stream->write_completed_queue)); +} + + +uv_handle_type uv__handle_type(int fd) { + struct sockaddr_storage ss; + socklen_t sslen; + socklen_t len; + int type; + + memset(&ss, 0, sizeof(ss)); + sslen = sizeof(ss); + + if (getsockname(fd, (struct sockaddr*)&ss, &sslen)) + return UV_UNKNOWN_HANDLE; + + len = sizeof type; + + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len)) + return UV_UNKNOWN_HANDLE; + + if (type == SOCK_STREAM) { +#if defined(_AIX) || defined(__DragonFly__) + /* on AIX/DragonFly the getsockname call returns an empty sa structure + * for sockets of type AF_UNIX. For all other types it will + * return a properly filled in structure. + */ + if (sslen == 0) + return UV_NAMED_PIPE; +#endif + switch (ss.ss_family) { + case AF_UNIX: + return UV_NAMED_PIPE; + case AF_INET: + case AF_INET6: + return UV_TCP; + } + } + + if (type == SOCK_DGRAM && + (ss.ss_family == AF_INET || ss.ss_family == AF_INET6)) + return UV_UDP; + + return UV_UNKNOWN_HANDLE; +} + + +static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) { + stream->flags |= UV_STREAM_READ_EOF; + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, POLLOUT)) + uv__handle_stop(stream); + uv__stream_osx_interrupt_select(stream); + stream->read_cb(stream, UV_EOF, buf); + stream->flags &= ~UV_STREAM_READING; +} + + +static int uv__stream_queue_fd(uv_stream_t* stream, int fd) { + uv__stream_queued_fds_t* queued_fds; + unsigned int queue_size; + + queued_fds = stream->queued_fds; + if (queued_fds == NULL) { + queue_size = 8; + queued_fds = uv__malloc((queue_size - 1) * sizeof(*queued_fds->fds) + + sizeof(*queued_fds)); + if (queued_fds == NULL) + return -ENOMEM; + queued_fds->size = queue_size; + queued_fds->offset = 0; + stream->queued_fds = queued_fds; + + /* Grow */ + } else if (queued_fds->size == queued_fds->offset) { + queue_size = queued_fds->size + 8; + queued_fds = uv__realloc(queued_fds, + (queue_size - 1) * sizeof(*queued_fds->fds) + + sizeof(*queued_fds)); + + /* + * Allocation failure, report back. + * NOTE: if it is fatal - sockets will be closed in uv__stream_close + */ + if (queued_fds == NULL) + return -ENOMEM; + queued_fds->size = queue_size; + stream->queued_fds = queued_fds; + } + + /* Put fd in a queue */ + queued_fds->fds[queued_fds->offset++] = fd; + + return 0; +} + + +#define UV__CMSG_FD_COUNT 64 +#define UV__CMSG_FD_SIZE (UV__CMSG_FD_COUNT * sizeof(int)) + + +static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) { + struct cmsghdr* cmsg; + + for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { + char* start; + char* end; + int err; + void* pv; + int* pi; + unsigned int i; + unsigned int count; + + if (cmsg->cmsg_type != SCM_RIGHTS) { + fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n", + cmsg->cmsg_type); + continue; + } + + /* silence aliasing warning */ + pv = CMSG_DATA(cmsg); + pi = pv; + + /* Count available fds */ + start = (char*) cmsg; + end = (char*) cmsg + cmsg->cmsg_len; + count = 0; + while (start + CMSG_LEN(count * sizeof(*pi)) < end) + count++; + assert(start + CMSG_LEN(count * sizeof(*pi)) == end); + + for (i = 0; i < count; i++) { + /* Already has accepted fd, queue now */ + if (stream->accepted_fd != -1) { + err = uv__stream_queue_fd(stream, pi[i]); + if (err != 0) { + /* Close rest */ + for (; i < count; i++) + uv__close(pi[i]); + return err; + } + } else { + stream->accepted_fd = pi[i]; + } + } + } + + return 0; +} + + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-folding-constant" +#endif + +static void uv__read(uv_stream_t* stream) { + uv_buf_t buf; + ssize_t nread; + struct msghdr msg; + char cmsg_space[CMSG_SPACE(UV__CMSG_FD_SIZE)]; + int count; + int err; + int is_ipc; + + stream->flags &= ~UV_STREAM_READ_PARTIAL; + + /* Prevent loop starvation when the data comes in as fast as (or faster than) + * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O. + */ + count = 32; + + is_ipc = stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) stream)->ipc; + + /* XXX: Maybe instead of having UV_STREAM_READING we just test if + * tcp->read_cb is NULL or not? + */ + while (stream->read_cb + && (stream->flags & UV_STREAM_READING) + && (count-- > 0)) { + assert(stream->alloc_cb != NULL); + + buf = uv_buf_init(NULL, 0); + stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf); + if (buf.base == NULL || buf.len == 0) { + /* User indicates it can't or won't handle the read. */ + stream->read_cb(stream, UV_ENOBUFS, &buf); + return; + } + + assert(buf.base != NULL); + assert(uv__stream_fd(stream) >= 0); + + if (!is_ipc) { + do { + nread = read(uv__stream_fd(stream), buf.base, buf.len); + } + while (nread < 0 && errno == EINTR); + } else { + /* ipc uses recvmsg */ + msg.msg_flags = 0; + msg.msg_iov = (struct iovec*) &buf; + msg.msg_iovlen = 1; + msg.msg_name = NULL; + msg.msg_namelen = 0; + /* Set up to receive a descriptor even if one isn't in the message */ + msg.msg_controllen = sizeof(cmsg_space); + msg.msg_control = cmsg_space; + + do { + nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0); + } + while (nread < 0 && errno == EINTR); + } + + if (nread < 0) { + /* Error */ + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* Wait for the next one. */ + if (stream->flags & UV_STREAM_READING) { + uv__io_start(stream->loop, &stream->io_watcher, POLLIN); + uv__stream_osx_interrupt_select(stream); + } + stream->read_cb(stream, 0, &buf); + } else { + /* Error. User should call uv_close(). */ + stream->read_cb(stream, -errno, &buf); + if (stream->flags & UV_STREAM_READING) { + stream->flags &= ~UV_STREAM_READING; + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, POLLOUT)) + uv__handle_stop(stream); + uv__stream_osx_interrupt_select(stream); + } + } + return; + } else if (nread == 0) { + uv__stream_eof(stream, &buf); + return; + } else { + /* Successful read */ + ssize_t buflen = buf.len; + + if (is_ipc) { + err = uv__stream_recv_cmsg(stream, &msg); + if (err != 0) { + stream->read_cb(stream, err, &buf); + return; + } + } + stream->read_cb(stream, nread, &buf); + + /* Return if we didn't fill the buffer, there is no more data to read. */ + if (nread < buflen) { + stream->flags |= UV_STREAM_READ_PARTIAL; + return; + } + } + } +} + + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + +#undef UV__CMSG_FD_COUNT +#undef UV__CMSG_FD_SIZE + + +int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { + assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE) && + "uv_shutdown (unix) only supports uv_handle_t right now"); + + if (!(stream->flags & UV_STREAM_WRITABLE) || + stream->flags & UV_STREAM_SHUT || + stream->flags & UV_STREAM_SHUTTING || + stream->flags & UV_CLOSED || + stream->flags & UV_CLOSING) { + return -ENOTCONN; + } + + assert(uv__stream_fd(stream) >= 0); + + /* Initialize request */ + uv__req_init(stream->loop, req, UV_SHUTDOWN); + req->handle = stream; + req->cb = cb; + stream->shutdown_req = req; + stream->flags |= UV_STREAM_SHUTTING; + + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); + uv__stream_osx_interrupt_select(stream); + + return 0; +} + + +static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + uv_stream_t* stream; + + stream = container_of(w, uv_stream_t, io_watcher); + + assert(stream->type == UV_TCP || + stream->type == UV_NAMED_PIPE || + stream->type == UV_TTY); + assert(!(stream->flags & UV_CLOSING)); + + if (stream->connect_req) { + uv__stream_connect(stream); + return; + } + + assert(uv__stream_fd(stream) >= 0); + + /* Ignore POLLHUP here. Even it it's set, there may still be data to read. */ + if (events & (POLLIN | POLLERR | POLLHUP)) + uv__read(stream); + + if (uv__stream_fd(stream) == -1) + return; /* read_cb closed stream. */ + + /* Short-circuit iff POLLHUP is set, the user is still interested in read + * events and uv__read() reported a partial read but not EOF. If the EOF + * flag is set, uv__read() called read_cb with err=UV_EOF and we don't + * have to do anything. If the partial read flag is not set, we can't + * report the EOF yet because there is still data to read. + */ + if ((events & POLLHUP) && + (stream->flags & UV_STREAM_READING) && + (stream->flags & UV_STREAM_READ_PARTIAL) && + !(stream->flags & UV_STREAM_READ_EOF)) { + uv_buf_t buf = { NULL, 0 }; + uv__stream_eof(stream, &buf); + } + + if (uv__stream_fd(stream) == -1) + return; /* read_cb closed stream. */ + + if (events & (POLLOUT | POLLERR | POLLHUP)) { + uv__write(stream); + uv__write_callbacks(stream); + + /* Write queue drained. */ + if (QUEUE_EMPTY(&stream->write_queue)) + uv__drain(stream); + } +} + + +/** + * We get called here from directly following a call to connect(2). + * In order to determine if we've errored out or succeeded must call + * getsockopt. + */ +static void uv__stream_connect(uv_stream_t* stream) { + int error; + uv_connect_t* req = stream->connect_req; + socklen_t errorsize = sizeof(int); + + assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE); + assert(req); + + if (stream->delayed_error) { + /* To smooth over the differences between unixes errors that + * were reported synchronously on the first connect can be delayed + * until the next tick--which is now. + */ + error = stream->delayed_error; + stream->delayed_error = 0; + } else { + /* Normal situation: we need to get the socket error from the kernel. */ + assert(uv__stream_fd(stream) >= 0); + getsockopt(uv__stream_fd(stream), + SOL_SOCKET, + SO_ERROR, + &error, + &errorsize); + error = -error; + } + + if (error == -EINPROGRESS) + return; + + stream->connect_req = NULL; + uv__req_unregister(stream->loop, req); + + if (error < 0 || QUEUE_EMPTY(&stream->write_queue)) { + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); + } + + if (req->cb) + req->cb(req, error); + + if (uv__stream_fd(stream) == -1) + return; + + if (error < 0) { + uv__stream_flush_write_queue(stream, -ECANCELED); + uv__write_callbacks(stream); + } +} + + +int uv_write2(uv_write_t* req, + uv_stream_t* stream, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb) { + int empty_queue; + + assert(nbufs > 0); + assert((stream->type == UV_TCP || + stream->type == UV_NAMED_PIPE || + stream->type == UV_TTY) && + "uv_write (unix) does not yet support other types of streams"); + + if (uv__stream_fd(stream) < 0) + return -EBADF; + + if (send_handle) { + if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) + return -EINVAL; + + /* XXX We abuse uv_write2() to send over UDP handles to child processes. + * Don't call uv__stream_fd() on those handles, it's a macro that on OS X + * evaluates to a function that operates on a uv_stream_t with a couple of + * OS X specific fields. On other Unices it does (handle)->io_watcher.fd, + * which works but only by accident. + */ + if (uv__handle_fd((uv_handle_t*) send_handle) < 0) + return -EBADF; + } + + /* It's legal for write_queue_size > 0 even when the write_queue is empty; + * it means there are error-state requests in the write_completed_queue that + * will touch up write_queue_size later, see also uv__write_req_finish(). + * We could check that write_queue is empty instead but that implies making + * a write() syscall when we know that the handle is in error mode. + */ + empty_queue = (stream->write_queue_size == 0); + + /* Initialize the req */ + uv__req_init(stream->loop, req, UV_WRITE); + req->cb = cb; + req->handle = stream; + req->error = 0; + req->send_handle = send_handle; + QUEUE_INIT(&req->queue); + + req->bufs = req->bufsml; + if (nbufs > ARRAY_SIZE(req->bufsml)) + req->bufs = uv__malloc(nbufs * sizeof(bufs[0])); + + if (req->bufs == NULL) + return -ENOMEM; + + memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); + req->nbufs = nbufs; + req->write_index = 0; + stream->write_queue_size += uv__count_bufs(bufs, nbufs); + + /* Append the request to write_queue. */ + QUEUE_INSERT_TAIL(&stream->write_queue, &req->queue); + + /* If the queue was empty when this function began, we should attempt to + * do the write immediately. Otherwise start the write_watcher and wait + * for the fd to become writable. + */ + if (stream->connect_req) { + /* Still connecting, do nothing. */ + } + else if (empty_queue) { + uv__write(stream); + } + else { + /* + * blocking streams should never have anything in the queue. + * if this assert fires then somehow the blocking stream isn't being + * sufficiently flushed in uv__write. + */ + assert(!(stream->flags & UV_STREAM_BLOCKING)); + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); + uv__stream_osx_interrupt_select(stream); + } + + return 0; +} + + +/* The buffers to be written must remain valid until the callback is called. + * This is not required for the uv_buf_t array. + */ +int uv_write(uv_write_t* req, + uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb) { + return uv_write2(req, handle, bufs, nbufs, NULL, cb); +} + + +void uv_try_write_cb(uv_write_t* req, int status) { + /* Should not be called */ + abort(); +} + + +int uv_try_write(uv_stream_t* stream, + const uv_buf_t bufs[], + unsigned int nbufs) { + int r; + int has_pollout; + size_t written; + size_t req_size; + uv_write_t req; + + /* Connecting or already writing some data */ + if (stream->connect_req != NULL || stream->write_queue_size != 0) + return -EAGAIN; + + has_pollout = uv__io_active(&stream->io_watcher, POLLOUT); + + r = uv_write(&req, stream, bufs, nbufs, uv_try_write_cb); + if (r != 0) + return r; + + /* Remove not written bytes from write queue size */ + written = uv__count_bufs(bufs, nbufs); + if (req.bufs != NULL) + req_size = uv__write_req_size(&req); + else + req_size = 0; + written -= req_size; + stream->write_queue_size -= req_size; + + /* Unqueue request, regardless of immediateness */ + QUEUE_REMOVE(&req.queue); + uv__req_unregister(stream->loop, &req); + if (req.bufs != req.bufsml) + uv__free(req.bufs); + req.bufs = NULL; + + /* Do not poll for writable, if we wasn't before calling this */ + if (!has_pollout) { + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); + uv__stream_osx_interrupt_select(stream); + } + + if (written == 0 && req_size != 0) + return -EAGAIN; + else + return written; +} + + +int uv_read_start(uv_stream_t* stream, + uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { + assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || + stream->type == UV_TTY); + + if (stream->flags & UV_CLOSING) + return -EINVAL; + + /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just + * expresses the desired state of the user. + */ + stream->flags |= UV_STREAM_READING; + + /* TODO: try to do the read inline? */ + /* TODO: keep track of tcp state. If we've gotten a EOF then we should + * not start the IO watcher. + */ + assert(uv__stream_fd(stream) >= 0); + assert(alloc_cb); + + stream->read_cb = read_cb; + stream->alloc_cb = alloc_cb; + + uv__io_start(stream->loop, &stream->io_watcher, POLLIN); + uv__handle_start(stream); + uv__stream_osx_interrupt_select(stream); + + return 0; +} + + +int uv_read_stop(uv_stream_t* stream) { + if (!(stream->flags & UV_STREAM_READING)) + return 0; + + stream->flags &= ~UV_STREAM_READING; + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, POLLOUT)) + uv__handle_stop(stream); + uv__stream_osx_interrupt_select(stream); + + stream->read_cb = NULL; + stream->alloc_cb = NULL; + return 0; +} + + +int uv_is_readable(const uv_stream_t* stream) { + return !!(stream->flags & UV_STREAM_READABLE); +} + + +int uv_is_writable(const uv_stream_t* stream) { + return !!(stream->flags & UV_STREAM_WRITABLE); +} + + +#if defined(__APPLE__) +int uv___stream_fd(const uv_stream_t* handle) { + const uv__stream_select_t* s; + + assert(handle->type == UV_TCP || + handle->type == UV_TTY || + handle->type == UV_NAMED_PIPE); + + s = handle->select; + if (s != NULL) + return s->fd; + + return handle->io_watcher.fd; +} +#endif /* defined(__APPLE__) */ + + +void uv__stream_close(uv_stream_t* handle) { + unsigned int i; + uv__stream_queued_fds_t* queued_fds; + +#if defined(__APPLE__) + /* Terminate select loop first */ + if (handle->select != NULL) { + uv__stream_select_t* s; + + s = handle->select; + + uv_sem_post(&s->close_sem); + uv_sem_post(&s->async_sem); + uv__stream_osx_interrupt_select(handle); + uv_thread_join(&s->thread); + uv_sem_destroy(&s->close_sem); + uv_sem_destroy(&s->async_sem); + uv__close(s->fake_fd); + uv__close(s->int_fd); + uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close); + + handle->select = NULL; + } +#endif /* defined(__APPLE__) */ + + uv__io_close(handle->loop, &handle->io_watcher); + uv_read_stop(handle); + uv__handle_stop(handle); + + if (handle->io_watcher.fd != -1) { + /* Don't close stdio file descriptors. Nothing good comes from it. */ + if (handle->io_watcher.fd > STDERR_FILENO) + uv__close(handle->io_watcher.fd); + handle->io_watcher.fd = -1; + } + + if (handle->accepted_fd != -1) { + uv__close(handle->accepted_fd); + handle->accepted_fd = -1; + } + + /* Close all queued fds */ + if (handle->queued_fds != NULL) { + queued_fds = handle->queued_fds; + for (i = 0; i < queued_fds->offset; i++) + uv__close(queued_fds->fds[i]); + uv__free(handle->queued_fds); + handle->queued_fds = NULL; + } + + assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT)); +} + + +int uv_stream_set_blocking(uv_stream_t* handle, int blocking) { + /* Don't need to check the file descriptor, uv__nonblock() + * will fail with EBADF if it's not valid. + */ + return uv__nonblock(uv__stream_fd(handle), !blocking); +} diff --git a/src/unix/sunos.c b/src/unix/sunos.c new file mode 100644 index 0000000..3e7a759 --- /dev/null +++ b/src/unix/sunos.c @@ -0,0 +1,821 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#ifndef SUNOS_NO_IFADDRS +# include +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#define PORT_FIRED 0x69 +#define PORT_UNUSED 0x0 +#define PORT_LOADED 0x99 +#define PORT_DELETED -1 + +#if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64) +#define PROCFS_FILE_OFFSET_BITS_HACK 1 +#undef _FILE_OFFSET_BITS +#else +#define PROCFS_FILE_OFFSET_BITS_HACK 0 +#endif + +#include + +#if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1) +#define _FILE_OFFSET_BITS 64 +#endif + + +int uv__platform_loop_init(uv_loop_t* loop) { + int err; + int fd; + + loop->fs_fd = -1; + loop->backend_fd = -1; + + fd = port_create(); + if (fd == -1) + return -errno; + + err = uv__cloexec(fd, 1); + if (err) { + uv__close(fd); + return err; + } + loop->backend_fd = fd; + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->fs_fd != -1) { + uv__close(loop->fs_fd); + loop->fs_fd = -1; + } + + if (loop->backend_fd != -1) { + uv__close(loop->backend_fd); + loop->backend_fd = -1; + } +} + + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct port_event* events; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + + events = (struct port_event*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + if (events == NULL) + return; + + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].portev_object == fd) + events[i].portev_object = -1; +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0)) + return -errno; + + if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) + abort(); + + return 0; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + struct port_event events[1024]; + struct port_event* pe; + struct timespec spec; + QUEUE* q; + uv__io_t* w; + sigset_t* pset; + sigset_t set; + uint64_t base; + uint64_t diff; + unsigned int nfds; + unsigned int i; + int saved_errno; + int have_signals; + int nevents; + int count; + int err; + int fd; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + + if (port_associate(loop->backend_fd, PORT_SOURCE_FD, w->fd, w->pevents, 0)) + abort(); + + w->events = w->pevents; + } + + pset = NULL; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + pset = &set; + sigemptyset(pset); + sigaddset(pset, SIGPROF); + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + + for (;;) { + if (timeout != -1) { + spec.tv_sec = timeout / 1000; + spec.tv_nsec = (timeout % 1000) * 1000000; + } + + /* Work around a kernel bug where nfds is not updated. */ + events[0].portev_source = 0; + + nfds = 1; + saved_errno = 0; + + if (pset != NULL) + pthread_sigmask(SIG_BLOCK, pset, NULL); + + err = port_getn(loop->backend_fd, + events, + ARRAY_SIZE(events), + &nfds, + timeout == -1 ? NULL : &spec); + + if (pset != NULL) + pthread_sigmask(SIG_UNBLOCK, pset, NULL); + + if (err) { + /* Work around another kernel bug: port_getn() may return events even + * on error. + */ + if (errno == EINTR || errno == ETIME) + saved_errno = errno; + else + abort(); + } + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (events[0].portev_source == 0) { + if (timeout == 0) + return; + + if (timeout == -1) + continue; + + goto update_timeout; + } + + if (nfds == 0) { + assert(timeout != -1); + return; + } + + have_signals = 0; + nevents = 0; + + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + for (i = 0; i < nfds; i++) { + pe = events + i; + fd = pe->portev_object; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (fd == -1) + continue; + + assert(fd >= 0); + assert((unsigned) fd < loop->nwatchers); + + w = loop->watchers[fd]; + + /* File descriptor that we've stopped watching, ignore. */ + if (w == NULL) + continue; + + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->portev_events); + + nevents++; + + if (w != loop->watchers[fd]) + continue; /* Disabled by callback. */ + + /* Events Ports operates in oneshot mode, rearm timer on next run. */ + if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) + QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (saved_errno == ETIME) { + assert(timeout != -1); + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + diff = loop->time - base; + if (diff >= (uint64_t) timeout) + return; + + timeout -= diff; + } +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + return gethrtime(); +} + + +/* + * We could use a static buffer for the path manipulations that we need outside + * of the function, but this function could be called by multiple consumers and + * we don't want to potentially create a race condition in the use of snprintf. + */ +int uv_exepath(char* buffer, size_t* size) { + ssize_t res; + char buf[128]; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid()); + + res = *size - 1; + if (res > 0) + res = readlink(buf, buffer, res); + + if (res == -1) + return -errno; + + buffer[res] = '\0'; + *size = res; + return 0; +} + + +uint64_t uv_get_free_memory(void) { + return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES); +} + + +uint64_t uv_get_total_memory(void) { + return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES); +} + + +void uv_loadavg(double avg[3]) { + (void) getloadavg(avg, 3); +} + + +#if defined(PORT_SOURCE_FILE) + +static int uv__fs_event_rearm(uv_fs_event_t *handle) { + if (handle->fd == -1) + return -EBADF; + + if (port_associate(handle->loop->fs_fd, + PORT_SOURCE_FILE, + (uintptr_t) &handle->fo, + FILE_ATTRIB | FILE_MODIFIED, + handle) == -1) { + return -errno; + } + handle->fd = PORT_LOADED; + + return 0; +} + + +static void uv__fs_event_read(uv_loop_t* loop, + uv__io_t* w, + unsigned int revents) { + uv_fs_event_t *handle = NULL; + timespec_t timeout; + port_event_t pe; + int events; + int r; + + (void) w; + (void) revents; + + do { + uint_t n = 1; + + /* + * Note that our use of port_getn() here (and not port_get()) is deliberate: + * there is a bug in event ports (Sun bug 6456558) whereby a zeroed timeout + * causes port_get() to return success instead of ETIME when there aren't + * actually any events (!); by using port_getn() in lieu of port_get(), + * we can at least workaround the bug by checking for zero returned events + * and treating it as we would ETIME. + */ + do { + memset(&timeout, 0, sizeof timeout); + r = port_getn(loop->fs_fd, &pe, 1, &n, &timeout); + } + while (r == -1 && errno == EINTR); + + if ((r == -1 && errno == ETIME) || n == 0) + break; + + handle = (uv_fs_event_t*) pe.portev_user; + assert((r == 0) && "unexpected port_get() error"); + + events = 0; + if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED)) + events |= UV_CHANGE; + if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED)) + events |= UV_RENAME; + assert(events != 0); + handle->fd = PORT_FIRED; + handle->cb(handle, NULL, events, 0); + + if (handle->fd != PORT_DELETED) { + r = uv__fs_event_rearm(handle); + if (r != 0) + handle->cb(handle, NULL, 0, r); + } + } + while (handle->fd != PORT_DELETED); +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + return 0; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* path, + unsigned int flags) { + int portfd; + int first_run; + int err; + + if (uv__is_active(handle)) + return -EINVAL; + + first_run = 0; + if (handle->loop->fs_fd == -1) { + portfd = port_create(); + if (portfd == -1) + return -errno; + handle->loop->fs_fd = portfd; + first_run = 1; + } + + uv__handle_start(handle); + handle->path = uv__strdup(path); + handle->fd = PORT_UNUSED; + handle->cb = cb; + + memset(&handle->fo, 0, sizeof handle->fo); + handle->fo.fo_name = handle->path; + err = uv__fs_event_rearm(handle); + if (err != 0) + return err; + + if (first_run) { + uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd); + uv__io_start(handle->loop, &handle->loop->fs_event_watcher, POLLIN); + } + + return 0; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + if (!uv__is_active(handle)) + return 0; + + if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) { + port_dissociate(handle->loop->fs_fd, + PORT_SOURCE_FILE, + (uintptr_t) &handle->fo); + } + + handle->fd = PORT_DELETED; + uv__free(handle->path); + handle->path = NULL; + handle->fo.fo_name = NULL; + uv__handle_stop(handle); + + return 0; +} + +void uv__fs_event_close(uv_fs_event_t* handle) { + uv_fs_event_stop(handle); +} + +#else /* !defined(PORT_SOURCE_FILE) */ + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + return -ENOSYS; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* filename, + unsigned int flags) { + return -ENOSYS; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + return -ENOSYS; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + UNREACHABLE(); +} + +#endif /* defined(PORT_SOURCE_FILE) */ + + +char** uv_setup_args(int argc, char** argv) { + return argv; +} + + +int uv_set_process_title(const char* title) { + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + if (buffer == NULL || size == 0) + return -EINVAL; + + buffer[0] = '\0'; + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + psinfo_t psinfo; + int err; + int fd; + + fd = open("/proc/self/psinfo", O_RDONLY); + if (fd == -1) + return -errno; + + /* FIXME(bnoordhuis) Handle EINTR. */ + err = -EINVAL; + if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) { + *rss = (size_t)psinfo.pr_rssize * 1024; + err = 0; + } + uv__close(fd); + + return err; +} + + +int uv_uptime(double* uptime) { + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *knp; + + long hz = sysconf(_SC_CLK_TCK); + + kc = kstat_open(); + if (kc == NULL) + return -EPERM; + + ksp = kstat_lookup(kc, (char*) "unix", 0, (char*) "system_misc"); + if (kstat_read(kc, ksp, NULL) == -1) { + *uptime = -1; + } else { + knp = (kstat_named_t*) kstat_data_lookup(ksp, (char*) "clk_intr"); + *uptime = knp->value.ul / hz; + } + kstat_close(kc); + + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + int lookup_instance; + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *knp; + uv_cpu_info_t* cpu_info; + + kc = kstat_open(); + if (kc == NULL) + return -EPERM; + + /* Get count of cpus */ + lookup_instance = 0; + while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) { + lookup_instance++; + } + + *cpu_infos = uv__malloc(lookup_instance * sizeof(**cpu_infos)); + if (!(*cpu_infos)) { + kstat_close(kc); + return -ENOMEM; + } + + *count = lookup_instance; + + cpu_info = *cpu_infos; + lookup_instance = 0; + while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) { + if (kstat_read(kc, ksp, NULL) == -1) { + cpu_info->speed = 0; + cpu_info->model = NULL; + } else { + knp = kstat_data_lookup(ksp, (char*) "clock_MHz"); + assert(knp->data_type == KSTAT_DATA_INT32 || + knp->data_type == KSTAT_DATA_INT64); + cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32 + : knp->value.i64; + + knp = kstat_data_lookup(ksp, (char*) "brand"); + assert(knp->data_type == KSTAT_DATA_STRING); + cpu_info->model = uv__strdup(KSTAT_NAMED_STR_PTR(knp)); + } + + lookup_instance++; + cpu_info++; + } + + cpu_info = *cpu_infos; + lookup_instance = 0; + for (;;) { + ksp = kstat_lookup(kc, (char*) "cpu", lookup_instance, (char*) "sys"); + + if (ksp == NULL) + break; + + if (kstat_read(kc, ksp, NULL) == -1) { + cpu_info->cpu_times.user = 0; + cpu_info->cpu_times.nice = 0; + cpu_info->cpu_times.sys = 0; + cpu_info->cpu_times.idle = 0; + cpu_info->cpu_times.irq = 0; + } else { + knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_user"); + assert(knp->data_type == KSTAT_DATA_UINT64); + cpu_info->cpu_times.user = knp->value.ui64; + + knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_kernel"); + assert(knp->data_type == KSTAT_DATA_UINT64); + cpu_info->cpu_times.sys = knp->value.ui64; + + knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_idle"); + assert(knp->data_type == KSTAT_DATA_UINT64); + cpu_info->cpu_times.idle = knp->value.ui64; + + knp = kstat_data_lookup(ksp, (char*) "intr"); + assert(knp->data_type == KSTAT_DATA_UINT64); + cpu_info->cpu_times.irq = knp->value.ui64; + cpu_info->cpu_times.nice = 0; + } + + lookup_instance++; + cpu_info++; + } + + kstat_close(kc); + + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + +/* + * Inspired By: + * https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris + * http://www.pauliesworld.org/project/getmac.c + */ +static int uv__set_phys_addr(uv_interface_address_t* address, + struct ifaddrs* ent) { + + struct sockaddr_dl* sa_addr; + int sockfd; + int i; + struct arpreq arpreq; + + /* This appears to only work as root */ + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + for (i = 0; i < sizeof(address->phys_addr); i++) { + if (address->phys_addr[i] != 0) + return 0; + } + memset(&arpreq, 0, sizeof(arpreq)); + if (address->address.address4.sin_family == AF_INET) { + struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa); + sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr; + } else if (address->address.address4.sin_family == AF_INET6) { + struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa); + memcpy(sin->sin6_addr.s6_addr, + address->address.address6.sin6_addr.s6_addr, + sizeof(address->address.address6.sin6_addr.s6_addr)); + } else { + return 0; + } + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + return -errno; + + if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) { + uv__close(sockfd); + return -errno; + } + memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr)); + uv__close(sockfd); + return 0; +} + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { +#ifdef SUNOS_NO_IFADDRS + return -ENOSYS; +#else + uv_interface_address_t* address; + struct ifaddrs* addrs; + struct ifaddrs* ent; + int i; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family == PF_PACKET)) { + continue; + } + + (*count)++; + } + + *addresses = uv__malloc(*count * sizeof(**addresses)); + if (!(*addresses)) { + freeifaddrs(addrs); + return -ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + address->name = uv__strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) || + (ent->ifa_flags & IFF_LOOPBACK)); + + uv__set_phys_addr(address, ent); + address++; + } + + freeifaddrs(addrs); + + return 0; +#endif /* SUNOS_NO_IFADDRS */ +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(addresses[i].name); + } + + uv__free(addresses); +} diff --git a/src/unix/tcp.c b/src/unix/tcp.c new file mode 100644 index 0000000..c423dcb --- /dev/null +++ b/src/unix/tcp.c @@ -0,0 +1,395 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include + + +static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) { + int sockfd; + int err; + + if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) { + handle->flags |= flags; + return 0; + } + + err = uv__socket(domain, SOCK_STREAM, 0); + if (err < 0) + return err; + sockfd = err; + + err = uv__stream_open((uv_stream_t*) handle, sockfd, flags); + if (err) { + uv__close(sockfd); + return err; + } + + return 0; +} + + +int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) { + int domain; + + /* Use the lower 8 bits for the domain */ + domain = flags & 0xFF; + if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) + return -EINVAL; + + if (flags & ~0xFF) + return -EINVAL; + + uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP); + + /* If anything fails beyond this point we need to remove the handle from + * the handle queue, since it was added by uv__handle_init in uv_stream_init. + */ + + if (domain != AF_UNSPEC) { + int err = maybe_new_socket(tcp, domain, 0); + if (err) { + QUEUE_REMOVE(&tcp->handle_queue); + return err; + } + } + + return 0; +} + + +int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) { + return uv_tcp_init_ex(loop, tcp, AF_UNSPEC); +} + + +int uv__tcp_bind(uv_tcp_t* tcp, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + int err; + int on; + + /* Cannot set IPv6-only mode on non-IPv6 socket. */ + if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6) + return -EINVAL; + + err = maybe_new_socket(tcp, + addr->sa_family, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); + if (err) + return err; + + on = 1; + if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) + return -errno; + +#ifdef IPV6_V6ONLY + if (addr->sa_family == AF_INET6) { + on = (flags & UV_TCP_IPV6ONLY) != 0; + if (setsockopt(tcp->io_watcher.fd, + IPPROTO_IPV6, + IPV6_V6ONLY, + &on, + sizeof on) == -1) { +#if defined(__MVS__) + if (errno == EOPNOTSUPP) + return -EINVAL; +#endif + return -errno; + } + } +#endif + + errno = 0; + if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) { + if (errno == EAFNOSUPPORT) + /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a + * socket created with AF_INET to an AF_INET6 address or vice versa. */ + return -EINVAL; + return -errno; + } + tcp->delayed_error = -errno; + + tcp->flags |= UV_HANDLE_BOUND; + if (addr->sa_family == AF_INET6) + tcp->flags |= UV_HANDLE_IPV6; + + return 0; +} + + +int uv__tcp_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + uv_connect_cb cb) { + int err; + int r; + + assert(handle->type == UV_TCP); + + if (handle->connect_req != NULL) + return -EALREADY; /* FIXME(bnoordhuis) -EINVAL or maybe -EBUSY. */ + + err = maybe_new_socket(handle, + addr->sa_family, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); + if (err) + return err; + + handle->delayed_error = 0; + + do { + errno = 0; + r = connect(uv__stream_fd(handle), addr, addrlen); + } while (r == -1 && errno == EINTR); + + /* We not only check the return value, but also check the errno != 0. + * Because in rare cases connect() will return -1 but the errno + * is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227) + * and actually the tcp three-way handshake is completed. + */ + if (r == -1 && errno != 0) { + if (errno == EINPROGRESS) + ; /* not an error */ + else if (errno == ECONNREFUSED) + /* If we get a ECONNREFUSED wait until the next tick to report the + * error. Solaris wants to report immediately--other unixes want to + * wait. + */ + handle->delayed_error = -errno; + else + return -errno; + } + + uv__req_init(handle->loop, req, UV_CONNECT); + req->cb = cb; + req->handle = (uv_stream_t*) handle; + QUEUE_INIT(&req->queue); + handle->connect_req = req; + + uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); + + if (handle->delayed_error) + uv__io_feed(handle->loop, &handle->io_watcher); + + return 0; +} + + +int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { + int err; + + err = uv__nonblock(sock, 1); + if (err) + return err; + + return uv__stream_open((uv_stream_t*)handle, + sock, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); +} + + +int uv_tcp_getsockname(const uv_tcp_t* handle, + struct sockaddr* name, + int* namelen) { + socklen_t socklen; + + if (handle->delayed_error) + return handle->delayed_error; + + if (uv__stream_fd(handle) < 0) + return -EINVAL; /* FIXME(bnoordhuis) -EBADF */ + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (getsockname(uv__stream_fd(handle), name, &socklen)) + return -errno; + + *namelen = (int) socklen; + return 0; +} + + +int uv_tcp_getpeername(const uv_tcp_t* handle, + struct sockaddr* name, + int* namelen) { + socklen_t socklen; + + if (handle->delayed_error) + return handle->delayed_error; + + if (uv__stream_fd(handle) < 0) + return -EINVAL; /* FIXME(bnoordhuis) -EBADF */ + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (getpeername(uv__stream_fd(handle), name, &socklen)) + return -errno; + + *namelen = (int) socklen; + return 0; +} + + +int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { + static int single_accept = -1; + int err; + + if (tcp->delayed_error) + return tcp->delayed_error; + + if (single_accept == -1) { + const char* val = getenv("UV_TCP_SINGLE_ACCEPT"); + single_accept = (val != NULL && atoi(val) != 0); /* Off by default. */ + } + + if (single_accept) + tcp->flags |= UV_TCP_SINGLE_ACCEPT; + + err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE); + if (err) + return err; + +#ifdef __MVS__ + /* on zOS the listen call does not bind automatically + if the socket is unbound. Hence the manual binding to + an arbitrary port is required to be done manually + */ + + if (!(tcp->flags & UV_HANDLE_BOUND)) { + struct sockaddr_storage saddr; + socklen_t slen = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + + if (getsockname(tcp->io_watcher.fd, (struct sockaddr*) &saddr, &slen)) + return -errno; + + if (bind(tcp->io_watcher.fd, (struct sockaddr*) &saddr, slen)) + return -errno; + + tcp->flags |= UV_HANDLE_BOUND; + } +#endif + + if (listen(tcp->io_watcher.fd, backlog)) + return -errno; + + tcp->connection_cb = cb; + tcp->flags |= UV_HANDLE_BOUND; + + /* Start listening for connections. */ + tcp->io_watcher.cb = uv__server_io; + uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN); + + return 0; +} + + +int uv__tcp_nodelay(int fd, int on) { + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on))) + return -errno; + return 0; +} + + +int uv__tcp_keepalive(int fd, int on, unsigned int delay) { + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on))) + return -errno; + +#ifdef TCP_KEEPIDLE + if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) + return -errno; +#endif + + /* Solaris/SmartOS, if you don't support keep-alive, + * then don't advertise it in your system headers... + */ + /* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */ +#if defined(TCP_KEEPALIVE) && !defined(__sun) + if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay))) + return -errno; +#endif + + return 0; +} + + +int uv_tcp_nodelay(uv_tcp_t* handle, int on) { + int err; + + if (uv__stream_fd(handle) != -1) { + err = uv__tcp_nodelay(uv__stream_fd(handle), on); + if (err) + return err; + } + + if (on) + handle->flags |= UV_TCP_NODELAY; + else + handle->flags &= ~UV_TCP_NODELAY; + + return 0; +} + + +int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { + int err; + + if (uv__stream_fd(handle) != -1) { + err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay); + if (err) + return err; + } + + if (on) + handle->flags |= UV_TCP_KEEPALIVE; + else + handle->flags &= ~UV_TCP_KEEPALIVE; + + /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge + * uv_tcp_t with an int that's almost never used... + */ + + return 0; +} + + +int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { + if (enable) + handle->flags &= ~UV_TCP_SINGLE_ACCEPT; + else + handle->flags |= UV_TCP_SINGLE_ACCEPT; + return 0; +} + + +void uv__tcp_close(uv_tcp_t* handle) { + uv__stream_close((uv_stream_t*)handle); +} diff --git a/src/unix/thread.c b/src/unix/thread.c new file mode 100644 index 0000000..52989f7 --- /dev/null +++ b/src/unix/thread.c @@ -0,0 +1,605 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + +#include +#include /* getrlimit() */ +#include /* getpagesize() */ + +#include + +#ifdef __MVS__ +#include +#include +#endif + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + +struct thread_ctx { + void (*entry)(void* arg); + void* arg; +}; + + +static void* uv__thread_start(void *arg) +{ + struct thread_ctx *ctx_p; + struct thread_ctx ctx; + + ctx_p = arg; + ctx = *ctx_p; + uv__free(ctx_p); + ctx.entry(ctx.arg); + + return 0; +} + + +int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { + struct thread_ctx* ctx; + int err; + pthread_attr_t* attr; +#if defined(__APPLE__) + pthread_attr_t attr_storage; + struct rlimit lim; +#endif + + ctx = uv__malloc(sizeof(*ctx)); + if (ctx == NULL) + return UV_ENOMEM; + + ctx->entry = entry; + ctx->arg = arg; + + /* On OSX threads other than the main thread are created with a reduced stack + * size by default, adjust it to RLIMIT_STACK. + */ +#if defined(__APPLE__) + if (getrlimit(RLIMIT_STACK, &lim)) + abort(); + + attr = &attr_storage; + if (pthread_attr_init(attr)) + abort(); + + if (lim.rlim_cur != RLIM_INFINITY) { + /* pthread_attr_setstacksize() expects page-aligned values. */ + lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize(); + + if (lim.rlim_cur >= PTHREAD_STACK_MIN) + if (pthread_attr_setstacksize(attr, lim.rlim_cur)) + abort(); + } +#else + attr = NULL; +#endif + + err = pthread_create(tid, attr, uv__thread_start, ctx); + + if (attr != NULL) + pthread_attr_destroy(attr); + + if (err) + uv__free(ctx); + + return -err; +} + + +uv_thread_t uv_thread_self(void) { + return pthread_self(); +} + +int uv_thread_join(uv_thread_t *tid) { + return -pthread_join(*tid, NULL); +} + + +int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { + return pthread_equal(*t1, *t2); +} + + +int uv_mutex_init(uv_mutex_t* mutex) { +#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK) + return -pthread_mutex_init(mutex, NULL); +#else + pthread_mutexattr_t attr; + int err; + + if (pthread_mutexattr_init(&attr)) + abort(); + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)) + abort(); + + err = pthread_mutex_init(mutex, &attr); + + if (pthread_mutexattr_destroy(&attr)) + abort(); + + return -err; +#endif +} + + +void uv_mutex_destroy(uv_mutex_t* mutex) { + if (pthread_mutex_destroy(mutex)) + abort(); +} + + +void uv_mutex_lock(uv_mutex_t* mutex) { + if (pthread_mutex_lock(mutex)) + abort(); +} + + +int uv_mutex_trylock(uv_mutex_t* mutex) { + int err; + + err = pthread_mutex_trylock(mutex); + if (err) { + if (err != EBUSY && err != EAGAIN) + abort(); + return -EBUSY; + } + + return 0; +} + + +void uv_mutex_unlock(uv_mutex_t* mutex) { + if (pthread_mutex_unlock(mutex)) + abort(); +} + + +int uv_rwlock_init(uv_rwlock_t* rwlock) { + return -pthread_rwlock_init(rwlock, NULL); +} + + +void uv_rwlock_destroy(uv_rwlock_t* rwlock) { + if (pthread_rwlock_destroy(rwlock)) + abort(); +} + + +void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { + if (pthread_rwlock_rdlock(rwlock)) + abort(); +} + + +int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { + int err; + + err = pthread_rwlock_tryrdlock(rwlock); + if (err) { + if (err != EBUSY && err != EAGAIN) + abort(); + return -EBUSY; + } + + return 0; +} + + +void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { + if (pthread_rwlock_unlock(rwlock)) + abort(); +} + + +void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { + if (pthread_rwlock_wrlock(rwlock)) + abort(); +} + + +int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { + int err; + + err = pthread_rwlock_trywrlock(rwlock); + if (err) { + if (err != EBUSY && err != EAGAIN) + abort(); + return -EBUSY; + } + + return 0; +} + + +void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { + if (pthread_rwlock_unlock(rwlock)) + abort(); +} + + +void uv_once(uv_once_t* guard, void (*callback)(void)) { + if (pthread_once(guard, callback)) + abort(); +} + +#if defined(__APPLE__) && defined(__MACH__) + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + kern_return_t err; + + err = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value); + if (err == KERN_SUCCESS) + return 0; + if (err == KERN_INVALID_ARGUMENT) + return -EINVAL; + if (err == KERN_RESOURCE_SHORTAGE) + return -ENOMEM; + + abort(); + return -EINVAL; /* Satisfy the compiler. */ +} + + +void uv_sem_destroy(uv_sem_t* sem) { + if (semaphore_destroy(mach_task_self(), *sem)) + abort(); +} + + +void uv_sem_post(uv_sem_t* sem) { + if (semaphore_signal(*sem)) + abort(); +} + + +void uv_sem_wait(uv_sem_t* sem) { + int r; + + do + r = semaphore_wait(*sem); + while (r == KERN_ABORTED); + + if (r != KERN_SUCCESS) + abort(); +} + + +int uv_sem_trywait(uv_sem_t* sem) { + mach_timespec_t interval; + kern_return_t err; + + interval.tv_sec = 0; + interval.tv_nsec = 0; + + err = semaphore_timedwait(*sem, interval); + if (err == KERN_SUCCESS) + return 0; + if (err == KERN_OPERATION_TIMED_OUT) + return -EAGAIN; + + abort(); + return -EINVAL; /* Satisfy the compiler. */ +} + +#elif defined(__MVS__) + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + uv_sem_t semid; + struct sembuf buf; + int err; + + buf.sem_num = 0; + buf.sem_op = value; + buf.sem_flg = 0; + + semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR); + if (semid == -1) + return -errno; + + if (-1 == semop(semid, &buf, 1)) { + err = errno; + if (-1 == semctl(*sem, 0, IPC_RMID)) + abort(); + return -err; + } + + *sem = semid; + return 0; +} + +void uv_sem_destroy(uv_sem_t* sem) { + if (-1 == semctl(*sem, 0, IPC_RMID)) + abort(); +} + +void uv_sem_post(uv_sem_t* sem) { + struct sembuf buf; + + buf.sem_num = 0; + buf.sem_op = 1; + buf.sem_flg = 0; + + if (-1 == semop(*sem, &buf, 1)) + abort(); +} + +void uv_sem_wait(uv_sem_t* sem) { + struct sembuf buf; + int op_status; + + buf.sem_num = 0; + buf.sem_op = -1; + buf.sem_flg = 0; + + do + op_status = semop(*sem, &buf, 1); + while (op_status == -1 && errno == EINTR); + + if (op_status) + abort(); +} + +int uv_sem_trywait(uv_sem_t* sem) { + struct sembuf buf; + int op_status; + + buf.sem_num = 0; + buf.sem_op = -1; + buf.sem_flg = IPC_NOWAIT; + + do + op_status = semop(*sem, &buf, 1); + while (op_status == -1 && errno == EINTR); + + if (op_status) { + if (errno == EAGAIN) + return -EAGAIN; + abort(); + } + + return 0; +} + +#else /* !(defined(__APPLE__) && defined(__MACH__)) */ + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + if (sem_init(sem, 0, value)) + return -errno; + return 0; +} + + +void uv_sem_destroy(uv_sem_t* sem) { + if (sem_destroy(sem)) + abort(); +} + + +void uv_sem_post(uv_sem_t* sem) { + if (sem_post(sem)) + abort(); +} + + +void uv_sem_wait(uv_sem_t* sem) { + int r; + + do + r = sem_wait(sem); + while (r == -1 && errno == EINTR); + + if (r) + abort(); +} + + +int uv_sem_trywait(uv_sem_t* sem) { + int r; + + do + r = sem_trywait(sem); + while (r == -1 && errno == EINTR); + + if (r) { + if (errno == EAGAIN) + return -EAGAIN; + abort(); + } + + return 0; +} + +#endif /* defined(__APPLE__) && defined(__MACH__) */ + + +#if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__) + +int uv_cond_init(uv_cond_t* cond) { + return -pthread_cond_init(cond, NULL); +} + +#else /* !(defined(__APPLE__) && defined(__MACH__)) */ + +int uv_cond_init(uv_cond_t* cond) { + pthread_condattr_t attr; + int err; + + err = pthread_condattr_init(&attr); + if (err) + return -err; + +#if !(defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)) + err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + if (err) + goto error2; +#endif + + err = pthread_cond_init(cond, &attr); + if (err) + goto error2; + + err = pthread_condattr_destroy(&attr); + if (err) + goto error; + + return 0; + +error: + pthread_cond_destroy(cond); +error2: + pthread_condattr_destroy(&attr); + return -err; +} + +#endif /* defined(__APPLE__) && defined(__MACH__) */ + +void uv_cond_destroy(uv_cond_t* cond) { +#if defined(__APPLE__) && defined(__MACH__) + /* It has been reported that destroying condition variables that have been + * signalled but not waited on can sometimes result in application crashes. + * See https://codereview.chromium.org/1323293005. + */ + pthread_mutex_t mutex; + struct timespec ts; + int err; + + if (pthread_mutex_init(&mutex, NULL)) + abort(); + + if (pthread_mutex_lock(&mutex)) + abort(); + + ts.tv_sec = 0; + ts.tv_nsec = 1; + + err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts); + if (err != 0 && err != ETIMEDOUT) + abort(); + + if (pthread_mutex_unlock(&mutex)) + abort(); + + if (pthread_mutex_destroy(&mutex)) + abort(); +#endif /* defined(__APPLE__) && defined(__MACH__) */ + + if (pthread_cond_destroy(cond)) + abort(); +} + +void uv_cond_signal(uv_cond_t* cond) { + if (pthread_cond_signal(cond)) + abort(); +} + +void uv_cond_broadcast(uv_cond_t* cond) { + if (pthread_cond_broadcast(cond)) + abort(); +} + +void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) { + if (pthread_cond_wait(cond, mutex)) + abort(); +} + + +int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { + int r; + struct timespec ts; + +#if defined(__APPLE__) && defined(__MACH__) + ts.tv_sec = timeout / NANOSEC; + ts.tv_nsec = timeout % NANOSEC; + r = pthread_cond_timedwait_relative_np(cond, mutex, &ts); +#else + timeout += uv__hrtime(UV_CLOCK_PRECISE); + ts.tv_sec = timeout / NANOSEC; + ts.tv_nsec = timeout % NANOSEC; +#if defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) + /* + * The bionic pthread implementation doesn't support CLOCK_MONOTONIC, + * but has this alternative function instead. + */ + r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts); +#else + r = pthread_cond_timedwait(cond, mutex, &ts); +#endif /* __ANDROID__ */ +#endif + + + if (r == 0) + return 0; + + if (r == ETIMEDOUT) + return -ETIMEDOUT; + + abort(); + return -EINVAL; /* Satisfy the compiler. */ +} + + +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + return -pthread_barrier_init(barrier, NULL, count); +} + + +void uv_barrier_destroy(uv_barrier_t* barrier) { + if (pthread_barrier_destroy(barrier)) + abort(); +} + + +int uv_barrier_wait(uv_barrier_t* barrier) { + int r = pthread_barrier_wait(barrier); + if (r && r != PTHREAD_BARRIER_SERIAL_THREAD) + abort(); + return r == PTHREAD_BARRIER_SERIAL_THREAD; +} + + +int uv_key_create(uv_key_t* key) { + return -pthread_key_create(key, NULL); +} + + +void uv_key_delete(uv_key_t* key) { + if (pthread_key_delete(*key)) + abort(); +} + + +void* uv_key_get(uv_key_t* key) { + return pthread_getspecific(*key); +} + + +void uv_key_set(uv_key_t* key, void* value) { + if (pthread_setspecific(*key, value)) + abort(); +} diff --git a/src/unix/timer.c b/src/unix/timer.c new file mode 100644 index 0000000..f46bdf4 --- /dev/null +++ b/src/unix/timer.c @@ -0,0 +1,172 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include "uv.h" +#include "internal.h" +#include "heap-inl.h" + +#include +#include + + +static int timer_less_than(const struct heap_node* ha, + const struct heap_node* hb) { + const uv_timer_t* a; + const uv_timer_t* b; + + a = container_of(ha, uv_timer_t, heap_node); + b = container_of(hb, uv_timer_t, heap_node); + + if (a->timeout < b->timeout) + return 1; + if (b->timeout < a->timeout) + return 0; + + /* Compare start_id when both have the same timeout. start_id is + * allocated with loop->timer_counter in uv_timer_start(). + */ + if (a->start_id < b->start_id) + return 1; + if (b->start_id < a->start_id) + return 0; + + return 0; +} + + +int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER); + handle->timer_cb = NULL; + handle->repeat = 0; + return 0; +} + + +int uv_timer_start(uv_timer_t* handle, + uv_timer_cb cb, + uint64_t timeout, + uint64_t repeat) { + uint64_t clamped_timeout; + + if (cb == NULL) + return -EINVAL; + + if (uv__is_active(handle)) + uv_timer_stop(handle); + + clamped_timeout = handle->loop->time + timeout; + if (clamped_timeout < timeout) + clamped_timeout = (uint64_t) -1; + + handle->timer_cb = cb; + handle->timeout = clamped_timeout; + handle->repeat = repeat; + /* start_id is the second index to be compared in uv__timer_cmp() */ + handle->start_id = handle->loop->timer_counter++; + + heap_insert((struct heap*) &handle->loop->timer_heap, + (struct heap_node*) &handle->heap_node, + timer_less_than); + uv__handle_start(handle); + + return 0; +} + + +int uv_timer_stop(uv_timer_t* handle) { + if (!uv__is_active(handle)) + return 0; + + heap_remove((struct heap*) &handle->loop->timer_heap, + (struct heap_node*) &handle->heap_node, + timer_less_than); + uv__handle_stop(handle); + + return 0; +} + + +int uv_timer_again(uv_timer_t* handle) { + if (handle->timer_cb == NULL) + return -EINVAL; + + if (handle->repeat) { + uv_timer_stop(handle); + uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat); + } + + return 0; +} + + +void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) { + handle->repeat = repeat; +} + + +uint64_t uv_timer_get_repeat(const uv_timer_t* handle) { + return handle->repeat; +} + + +int uv__next_timeout(const uv_loop_t* loop) { + const struct heap_node* heap_node; + const uv_timer_t* handle; + uint64_t diff; + + heap_node = heap_min((const struct heap*) &loop->timer_heap); + if (heap_node == NULL) + return -1; /* block indefinitely */ + + handle = container_of(heap_node, uv_timer_t, heap_node); + if (handle->timeout <= loop->time) + return 0; + + diff = handle->timeout - loop->time; + if (diff > INT_MAX) + diff = INT_MAX; + + return diff; +} + + +void uv__run_timers(uv_loop_t* loop) { + struct heap_node* heap_node; + uv_timer_t* handle; + + for (;;) { + heap_node = heap_min((struct heap*) &loop->timer_heap); + if (heap_node == NULL) + break; + + handle = container_of(heap_node, uv_timer_t, heap_node); + if (handle->timeout > loop->time) + break; + + uv_timer_stop(handle); + uv_timer_again(handle); + handle->timer_cb(handle); + } +} + + +void uv__timer_close(uv_timer_t* handle) { + uv_timer_stop(handle); +} diff --git a/src/unix/tty.c b/src/unix/tty.c new file mode 100644 index 0000000..b2d37f4 --- /dev/null +++ b/src/unix/tty.c @@ -0,0 +1,336 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" +#include "spinlock.h" + +#include +#include +#include +#include +#include +#include + +#if defined(__MVS__) && !defined(IMAXBEL) +#define IMAXBEL 0 +#endif + +static int orig_termios_fd = -1; +static struct termios orig_termios; +static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; + +static int uv__tty_is_slave(const int fd) { + int result; +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + int dummy; + + result = ioctl(fd, TIOCGPTN, &dummy) != 0; +#elif defined(__APPLE__) + char dummy[256]; + + result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0; +#else + /* Fallback to ptsname + */ + result = ptsname(fd) == NULL; +#endif + return result; +} + +int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { + uv_handle_type type; + int flags; + int newfd; + int r; + int saved_flags; + char path[256]; + + /* File descriptors that refer to files cannot be monitored with epoll. + * That restriction also applies to character devices like /dev/random + * (but obviously not /dev/tty.) + */ + type = uv_guess_handle(fd); + if (type == UV_FILE || type == UV_UNKNOWN_HANDLE) + return -EINVAL; + + flags = 0; + newfd = -1; + + /* Reopen the file descriptor when it refers to a tty. This lets us put the + * tty in non-blocking mode without affecting other processes that share it + * with us. + * + * Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also + * affects fd 1 of `cat` because both file descriptors refer to the same + * struct file in the kernel. When we reopen our fd 0, it points to a + * different struct file, hence changing its properties doesn't affect + * other processes. + */ + if (type == UV_TTY) { + /* Reopening a pty in master mode won't work either because the reopened + * pty will be in slave mode (*BSD) or reopening will allocate a new + * master/slave pair (Linux). Therefore check if the fd points to a + * slave device. + */ + if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0) + r = uv__open_cloexec(path, O_RDWR); + else + r = -1; + + if (r < 0) { + /* fallback to using blocking writes */ + if (!readable) + flags |= UV_STREAM_BLOCKING; + goto skip; + } + + newfd = r; + + r = uv__dup2_cloexec(newfd, fd); + if (r < 0 && r != -EINVAL) { + /* EINVAL means newfd == fd which could conceivably happen if another + * thread called close(fd) between our calls to isatty() and open(). + * That's a rather unlikely event but let's handle it anyway. + */ + uv__close(newfd); + return r; + } + + fd = newfd; + } + +#if defined(__APPLE__) + /* Save the fd flags in case we need to restore them due to an error. */ + do + saved_flags = fcntl(fd, F_GETFL); + while (saved_flags == -1 && errno == EINTR); + + if (saved_flags == -1) { + if (newfd != -1) + uv__close(newfd); + return -errno; + } +#endif + + /* Pacify the compiler. */ + (void) &saved_flags; + +skip: + uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY); + + /* If anything fails beyond this point we need to remove the handle from + * the handle queue, since it was added by uv__handle_init in uv_stream_init. + */ + + if (!(flags & UV_STREAM_BLOCKING)) + uv__nonblock(fd, 1); + +#if defined(__APPLE__) + r = uv__stream_try_select((uv_stream_t*) tty, &fd); + if (r) { + int rc = r; + if (newfd != -1) + uv__close(newfd); + QUEUE_REMOVE(&tty->handle_queue); + do + r = fcntl(fd, F_SETFL, saved_flags); + while (r == -1 && errno == EINTR); + return rc; + } +#endif + + if (readable) + flags |= UV_STREAM_READABLE; + else + flags |= UV_STREAM_WRITABLE; + + uv__stream_open((uv_stream_t*) tty, fd, flags); + tty->mode = UV_TTY_MODE_NORMAL; + + return 0; +} + +static void uv__tty_make_raw(struct termios* tio) { + assert(tio != NULL); + +#if defined __sun || defined __MVS__ + /* + * This implementation of cfmakeraw for Solaris and derivatives is taken from + * http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html. + */ + tio->c_iflag &= ~(IMAXBEL | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | + IGNCR | ICRNL | IXON); + tio->c_oflag &= ~OPOST; + tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + tio->c_cflag &= ~(CSIZE | PARENB); + tio->c_cflag |= CS8; +#else + cfmakeraw(tio); +#endif /* #ifdef __sun */ +} + +int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { + struct termios tmp; + int fd; + + if (tty->mode == (int) mode) + return 0; + + fd = uv__stream_fd(tty); + if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) { + if (tcgetattr(fd, &tty->orig_termios)) + return -errno; + + /* This is used for uv_tty_reset_mode() */ + uv_spinlock_lock(&termios_spinlock); + if (orig_termios_fd == -1) { + orig_termios = tty->orig_termios; + orig_termios_fd = fd; + } + uv_spinlock_unlock(&termios_spinlock); + } + + tmp = tty->orig_termios; + switch (mode) { + case UV_TTY_MODE_NORMAL: + break; + case UV_TTY_MODE_RAW: + tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + tmp.c_oflag |= (ONLCR); + tmp.c_cflag |= (CS8); + tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + tmp.c_cc[VMIN] = 1; + tmp.c_cc[VTIME] = 0; + break; + case UV_TTY_MODE_IO: + uv__tty_make_raw(&tmp); + break; + } + + /* Apply changes after draining */ + if (tcsetattr(fd, TCSADRAIN, &tmp)) + return -errno; + + tty->mode = mode; + return 0; +} + + +int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { + struct winsize ws; + int err; + + do + err = ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws); + while (err == -1 && errno == EINTR); + + if (err == -1) + return -errno; + + *width = ws.ws_col; + *height = ws.ws_row; + + return 0; +} + + +uv_handle_type uv_guess_handle(uv_file file) { + struct sockaddr sa; + struct stat s; + socklen_t len; + int type; + + if (file < 0) + return UV_UNKNOWN_HANDLE; + + if (isatty(file)) + return UV_TTY; + + if (fstat(file, &s)) + return UV_UNKNOWN_HANDLE; + + if (S_ISREG(s.st_mode)) + return UV_FILE; + + if (S_ISCHR(s.st_mode)) + return UV_FILE; /* XXX UV_NAMED_PIPE? */ + + if (S_ISFIFO(s.st_mode)) + return UV_NAMED_PIPE; + + if (!S_ISSOCK(s.st_mode)) + return UV_UNKNOWN_HANDLE; + + len = sizeof(type); + if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len)) + return UV_UNKNOWN_HANDLE; + + len = sizeof(sa); + if (getsockname(file, &sa, &len)) + return UV_UNKNOWN_HANDLE; + + if (type == SOCK_DGRAM) + if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) + return UV_UDP; + + if (type == SOCK_STREAM) { +#if defined(_AIX) || defined(__DragonFly__) + /* on AIX/DragonFly the getsockname call returns an empty sa structure + * for sockets of type AF_UNIX. For all other types it will + * return a properly filled in structure. + */ + if (len == 0) + return UV_NAMED_PIPE; +#endif /* defined(_AIX) || defined(__DragonFly__) */ + + if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) + return UV_TCP; + if (sa.sa_family == AF_UNIX) + return UV_NAMED_PIPE; + } + + return UV_UNKNOWN_HANDLE; +} + + +/* This function is async signal-safe, meaning that it's safe to call from + * inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s + * critical section when the signal was raised. + */ +int uv_tty_reset_mode(void) { + int saved_errno; + int err; + + saved_errno = errno; + if (!uv_spinlock_trylock(&termios_spinlock)) + return -EBUSY; /* In uv_tty_set_mode(). */ + + err = 0; + if (orig_termios_fd != -1) + if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios)) + err = -errno; + + uv_spinlock_unlock(&termios_spinlock); + errno = saved_errno; + + return err; +} diff --git a/src/unix/udp.c b/src/unix/udp.c new file mode 100644 index 0000000..1cd4925 --- /dev/null +++ b/src/unix/udp.c @@ -0,0 +1,895 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#if defined(__MVS__) +#include +#endif + +#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP) +# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#endif + +#if defined(IPV6_LEAVE_GROUP) && !defined(IPV6_DROP_MEMBERSHIP) +# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#endif + + +static void uv__udp_run_completed(uv_udp_t* handle); +static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents); +static void uv__udp_recvmsg(uv_udp_t* handle); +static void uv__udp_sendmsg(uv_udp_t* handle); +static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, + int domain, + unsigned int flags); + + +void uv__udp_close(uv_udp_t* handle) { + uv__io_close(handle->loop, &handle->io_watcher); + uv__handle_stop(handle); + + if (handle->io_watcher.fd != -1) { + uv__close(handle->io_watcher.fd); + handle->io_watcher.fd = -1; + } +} + + +void uv__udp_finish_close(uv_udp_t* handle) { + uv_udp_send_t* req; + QUEUE* q; + + assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT)); + assert(handle->io_watcher.fd == -1); + + while (!QUEUE_EMPTY(&handle->write_queue)) { + q = QUEUE_HEAD(&handle->write_queue); + QUEUE_REMOVE(q); + + req = QUEUE_DATA(q, uv_udp_send_t, queue); + req->status = -ECANCELED; + QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); + } + + uv__udp_run_completed(handle); + + assert(handle->send_queue_size == 0); + assert(handle->send_queue_count == 0); + + /* Now tear down the handle. */ + handle->recv_cb = NULL; + handle->alloc_cb = NULL; + /* but _do not_ touch close_cb */ +} + + +static void uv__udp_run_completed(uv_udp_t* handle) { + uv_udp_send_t* req; + QUEUE* q; + + assert(!(handle->flags & UV_UDP_PROCESSING)); + handle->flags |= UV_UDP_PROCESSING; + + while (!QUEUE_EMPTY(&handle->write_completed_queue)) { + q = QUEUE_HEAD(&handle->write_completed_queue); + QUEUE_REMOVE(q); + + req = QUEUE_DATA(q, uv_udp_send_t, queue); + uv__req_unregister(handle->loop, req); + + handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs); + handle->send_queue_count--; + + if (req->bufs != req->bufsml) + uv__free(req->bufs); + req->bufs = NULL; + + if (req->send_cb == NULL) + continue; + + /* req->status >= 0 == bytes written + * req->status < 0 == errno + */ + if (req->status >= 0) + req->send_cb(req, 0); + else + req->send_cb(req, req->status); + } + + if (QUEUE_EMPTY(&handle->write_queue)) { + /* Pending queue and completion queue empty, stop watcher. */ + uv__io_stop(handle->loop, &handle->io_watcher, POLLOUT); + if (!uv__io_active(&handle->io_watcher, POLLIN)) + uv__handle_stop(handle); + } + + handle->flags &= ~UV_UDP_PROCESSING; +} + + +static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { + uv_udp_t* handle; + + handle = container_of(w, uv_udp_t, io_watcher); + assert(handle->type == UV_UDP); + + if (revents & POLLIN) + uv__udp_recvmsg(handle); + + if (revents & POLLOUT) { + uv__udp_sendmsg(handle); + uv__udp_run_completed(handle); + } +} + + +static void uv__udp_recvmsg(uv_udp_t* handle) { + struct sockaddr_storage peer; + struct msghdr h; + ssize_t nread; + uv_buf_t buf; + int flags; + int count; + + assert(handle->recv_cb != NULL); + assert(handle->alloc_cb != NULL); + + /* Prevent loop starvation when the data comes in as fast as (or faster than) + * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O. + */ + count = 32; + + memset(&h, 0, sizeof(h)); + h.msg_name = &peer; + + do { + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf); + if (buf.base == NULL || buf.len == 0) { + handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); + return; + } + assert(buf.base != NULL); + + h.msg_namelen = sizeof(peer); + h.msg_iov = (void*) &buf; + h.msg_iovlen = 1; + + do { + nread = recvmsg(handle->io_watcher.fd, &h, 0); + } + while (nread == -1 && errno == EINTR); + + if (nread == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + handle->recv_cb(handle, 0, &buf, NULL, 0); + else + handle->recv_cb(handle, -errno, &buf, NULL, 0); + } + else { + const struct sockaddr *addr; + if (h.msg_namelen == 0) + addr = NULL; + else + addr = (const struct sockaddr*) &peer; + + flags = 0; + if (h.msg_flags & MSG_TRUNC) + flags |= UV_UDP_PARTIAL; + + handle->recv_cb(handle, nread, &buf, addr, flags); + } + } + /* recv_cb callback may decide to pause or close the handle */ + while (nread != -1 + && count-- > 0 + && handle->io_watcher.fd != -1 + && handle->recv_cb != NULL); +} + + +static void uv__udp_sendmsg(uv_udp_t* handle) { + uv_udp_send_t* req; + QUEUE* q; + struct msghdr h; + ssize_t size; + + while (!QUEUE_EMPTY(&handle->write_queue)) { + q = QUEUE_HEAD(&handle->write_queue); + assert(q != NULL); + + req = QUEUE_DATA(q, uv_udp_send_t, queue); + assert(req != NULL); + + memset(&h, 0, sizeof h); + h.msg_name = &req->addr; + h.msg_namelen = (req->addr.ss_family == AF_INET6 ? + sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); + h.msg_iov = (struct iovec*) req->bufs; + h.msg_iovlen = req->nbufs; + + do { + size = sendmsg(handle->io_watcher.fd, &h, 0); + } while (size == -1 && errno == EINTR); + + if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) + break; + + req->status = (size == -1 ? -errno : size); + + /* Sending a datagram is an atomic operation: either all data + * is written or nothing is (and EMSGSIZE is raised). That is + * why we don't handle partial writes. Just pop the request + * off the write queue and onto the completed queue, done. + */ + QUEUE_REMOVE(&req->queue); + QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); + uv__io_feed(handle->loop, &handle->io_watcher); + } +} + + +/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional + * refinements for programs that use multicast. + * + * Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that + * are different from the BSDs: it _shares_ the port rather than steal it + * from the current listener. While useful, it's not something we can emulate + * on other platforms so we don't enable it. + */ +static int uv__set_reuse(int fd) { + int yes; + +#if defined(SO_REUSEPORT) && !defined(__linux__) + yes = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) + return -errno; +#else + yes = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) + return -errno; +#endif + + return 0; +} + + +int uv__udp_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + int err; + int yes; + int fd; + + /* Check for bad flags. */ + if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR)) + return -EINVAL; + + /* Cannot set IPv6-only mode on non-IPv6 socket. */ + if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) + return -EINVAL; + + fd = handle->io_watcher.fd; + if (fd == -1) { + err = uv__socket(addr->sa_family, SOCK_DGRAM, 0); + if (err < 0) + return err; + fd = err; + handle->io_watcher.fd = fd; + } + + if (flags & UV_UDP_REUSEADDR) { + err = uv__set_reuse(fd); + if (err) + goto out; + } + + if (flags & UV_UDP_IPV6ONLY) { +#ifdef IPV6_V6ONLY + yes = 1; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) { + err = -errno; + goto out; + } +#else + err = -ENOTSUP; + goto out; +#endif + } + + if (bind(fd, addr, addrlen)) { + err = -errno; + if (errno == EAFNOSUPPORT) + /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a + * socket created with AF_INET to an AF_INET6 address or vice versa. */ + err = -EINVAL; + goto out; + } + + if (addr->sa_family == AF_INET6) + handle->flags |= UV_HANDLE_IPV6; + + handle->flags |= UV_HANDLE_BOUND; + + return 0; + +out: + uv__close(handle->io_watcher.fd); + handle->io_watcher.fd = -1; + return err; +} + + +static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, + int domain, + unsigned int flags) { + unsigned char taddr[sizeof(struct sockaddr_in6)]; + socklen_t addrlen; + + if (handle->io_watcher.fd != -1) + return 0; + + switch (domain) { + case AF_INET: + { + struct sockaddr_in* addr = (void*)&taddr; + memset(addr, 0, sizeof *addr); + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = INADDR_ANY; + addrlen = sizeof *addr; + break; + } + case AF_INET6: + { + struct sockaddr_in6* addr = (void*)&taddr; + memset(addr, 0, sizeof *addr); + addr->sin6_family = AF_INET6; + addr->sin6_addr = in6addr_any; + addrlen = sizeof *addr; + break; + } + default: + assert(0 && "unsupported address family"); + abort(); + } + + return uv__udp_bind(handle, (const struct sockaddr*) &taddr, addrlen, flags); +} + + +int uv__udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen, + uv_udp_send_cb send_cb) { + int err; + int empty_queue; + + assert(nbufs > 0); + + err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); + if (err) + return err; + + /* It's legal for send_queue_count > 0 even when the write_queue is empty; + * it means there are error-state requests in the write_completed_queue that + * will touch up send_queue_size/count later. + */ + empty_queue = (handle->send_queue_count == 0); + + uv__req_init(handle->loop, req, UV_UDP_SEND); + assert(addrlen <= sizeof(req->addr)); + memcpy(&req->addr, addr, addrlen); + req->send_cb = send_cb; + req->handle = handle; + req->nbufs = nbufs; + + req->bufs = req->bufsml; + if (nbufs > ARRAY_SIZE(req->bufsml)) + req->bufs = uv__malloc(nbufs * sizeof(bufs[0])); + + if (req->bufs == NULL) { + uv__req_unregister(handle->loop, req); + return -ENOMEM; + } + + memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); + handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs); + handle->send_queue_count++; + QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue); + uv__handle_start(handle); + + if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) { + uv__udp_sendmsg(handle); + } else { + uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); + } + + return 0; +} + + +int uv__udp_try_send(uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen) { + int err; + struct msghdr h; + ssize_t size; + + assert(nbufs > 0); + + /* already sending a message */ + if (handle->send_queue_count != 0) + return -EAGAIN; + + err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); + if (err) + return err; + + memset(&h, 0, sizeof h); + h.msg_name = (struct sockaddr*) addr; + h.msg_namelen = addrlen; + h.msg_iov = (struct iovec*) bufs; + h.msg_iovlen = nbufs; + + do { + size = sendmsg(handle->io_watcher.fd, &h, 0); + } while (size == -1 && errno == EINTR); + + if (size == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return -EAGAIN; + else + return -errno; + } + + return size; +} + + +static int uv__udp_set_membership4(uv_udp_t* handle, + const struct sockaddr_in* multicast_addr, + const char* interface_addr, + uv_membership membership) { + struct ip_mreq mreq; + int optname; + int err; + + memset(&mreq, 0, sizeof mreq); + + if (interface_addr) { + err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr); + if (err) + return err; + } else { + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + } + + mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr; + + switch (membership) { + case UV_JOIN_GROUP: + optname = IP_ADD_MEMBERSHIP; + break; + case UV_LEAVE_GROUP: + optname = IP_DROP_MEMBERSHIP; + break; + default: + return -EINVAL; + } + + if (setsockopt(handle->io_watcher.fd, + IPPROTO_IP, + optname, + &mreq, + sizeof(mreq))) { +#if defined(__MVS__) + if (errno == ENXIO) + return -ENODEV; +#endif + return -errno; + } + + return 0; +} + + +static int uv__udp_set_membership6(uv_udp_t* handle, + const struct sockaddr_in6* multicast_addr, + const char* interface_addr, + uv_membership membership) { + int optname; + struct ipv6_mreq mreq; + struct sockaddr_in6 addr6; + + memset(&mreq, 0, sizeof mreq); + + if (interface_addr) { + if (uv_ip6_addr(interface_addr, 0, &addr6)) + return -EINVAL; + mreq.ipv6mr_interface = addr6.sin6_scope_id; + } else { + mreq.ipv6mr_interface = 0; + } + + mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr; + + switch (membership) { + case UV_JOIN_GROUP: + optname = IPV6_ADD_MEMBERSHIP; + break; + case UV_LEAVE_GROUP: + optname = IPV6_DROP_MEMBERSHIP; + break; + default: + return -EINVAL; + } + + if (setsockopt(handle->io_watcher.fd, + IPPROTO_IPV6, + optname, + &mreq, + sizeof(mreq))) { +#if defined(__MVS__) + if (errno == ENXIO) + return -ENODEV; +#endif + return -errno; + } + + return 0; +} + + +int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) { + int domain; + int err; + int fd; + + /* Use the lower 8 bits for the domain */ + domain = flags & 0xFF; + if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) + return -EINVAL; + + if (flags & ~0xFF) + return -EINVAL; + + if (domain != AF_UNSPEC) { + err = uv__socket(domain, SOCK_DGRAM, 0); + if (err < 0) + return err; + fd = err; + } else { + fd = -1; + } + + uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP); + handle->alloc_cb = NULL; + handle->recv_cb = NULL; + handle->send_queue_size = 0; + handle->send_queue_count = 0; + uv__io_init(&handle->io_watcher, uv__udp_io, fd); + QUEUE_INIT(&handle->write_queue); + QUEUE_INIT(&handle->write_completed_queue); + return 0; +} + + +int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { + return uv_udp_init_ex(loop, handle, AF_UNSPEC); +} + + +int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { + int err; + + /* Check for already active socket. */ + if (handle->io_watcher.fd != -1) + return -EBUSY; + + err = uv__nonblock(sock, 1); + if (err) + return err; + + err = uv__set_reuse(sock); + if (err) + return err; + + handle->io_watcher.fd = sock; + return 0; +} + + +int uv_udp_set_membership(uv_udp_t* handle, + const char* multicast_addr, + const char* interface_addr, + uv_membership membership) { + int err; + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; + + if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0) { + err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR); + if (err) + return err; + return uv__udp_set_membership4(handle, &addr4, interface_addr, membership); + } else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0) { + err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR); + if (err) + return err; + return uv__udp_set_membership6(handle, &addr6, interface_addr, membership); + } else { + return -EINVAL; + } +} + +static int uv__setsockopt(uv_udp_t* handle, + int option4, + int option6, + const void* val, + size_t size) { + int r; + + if (handle->flags & UV_HANDLE_IPV6) + r = setsockopt(handle->io_watcher.fd, + IPPROTO_IPV6, + option6, + val, + size); + else + r = setsockopt(handle->io_watcher.fd, + IPPROTO_IP, + option4, + val, + size); + if (r) + return -errno; + + return 0; +} + +static int uv__setsockopt_maybe_char(uv_udp_t* handle, + int option4, + int option6, + int val) { +#if defined(__sun) || defined(_AIX) || defined(__MVS__) + char arg = val; +#elif defined(__OpenBSD__) + unsigned char arg = val; +#else + int arg = val; +#endif + + if (val < 0 || val > 255) + return -EINVAL; + + return uv__setsockopt(handle, option4, option6, &arg, sizeof(arg)); +} + + +int uv_udp_set_broadcast(uv_udp_t* handle, int on) { + if (setsockopt(handle->io_watcher.fd, + SOL_SOCKET, + SO_BROADCAST, + &on, + sizeof(on))) { + return -errno; + } + + return 0; +} + + +int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { + if (ttl < 1 || ttl > 255) + return -EINVAL; + +#if defined(__MVS__) + if (!(handle->flags & UV_HANDLE_IPV6)) + return -ENOTSUP; /* zOS does not support setting ttl for IPv4 */ +#endif + +/* + * On Solaris and derivatives such as SmartOS, the length of socket options + * is sizeof(int) for IP_TTL and IPV6_UNICAST_HOPS, + * so hardcode the size of these options on this platform, + * and use the general uv__setsockopt_maybe_char call on other platforms. + */ +#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ + defined(__MVS__) + + return uv__setsockopt(handle, + IP_TTL, + IPV6_UNICAST_HOPS, + &ttl, + sizeof(ttl)); +#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) || + defined(__MVS__) */ + + return uv__setsockopt_maybe_char(handle, + IP_TTL, + IPV6_UNICAST_HOPS, + ttl); +} + + +int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) { +/* + * On Solaris and derivatives such as SmartOS, the length of socket options + * is sizeof(int) for IPV6_MULTICAST_HOPS and sizeof(char) for + * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case, + * and use the general uv__setsockopt_maybe_char call otherwise. + */ +#if defined(__sun) || defined(_AIX) || defined(__MVS__) + if (handle->flags & UV_HANDLE_IPV6) + return uv__setsockopt(handle, + IP_MULTICAST_TTL, + IPV6_MULTICAST_HOPS, + &ttl, + sizeof(ttl)); +#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ + + return uv__setsockopt_maybe_char(handle, + IP_MULTICAST_TTL, + IPV6_MULTICAST_HOPS, + ttl); +} + + +int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) { +/* + * On Solaris and derivatives such as SmartOS, the length of socket options + * is sizeof(int) for IPV6_MULTICAST_LOOP and sizeof(char) for + * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case, + * and use the general uv__setsockopt_maybe_char call otherwise. + */ +#if defined(__sun) || defined(_AIX) || defined(__MVS__) + if (handle->flags & UV_HANDLE_IPV6) + return uv__setsockopt(handle, + IP_MULTICAST_LOOP, + IPV6_MULTICAST_LOOP, + &on, + sizeof(on)); +#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ + + return uv__setsockopt_maybe_char(handle, + IP_MULTICAST_LOOP, + IPV6_MULTICAST_LOOP, + on); +} + +int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) { + struct sockaddr_storage addr_st; + struct sockaddr_in* addr4; + struct sockaddr_in6* addr6; + + addr4 = (struct sockaddr_in*) &addr_st; + addr6 = (struct sockaddr_in6*) &addr_st; + + if (!interface_addr) { + memset(&addr_st, 0, sizeof addr_st); + if (handle->flags & UV_HANDLE_IPV6) { + addr_st.ss_family = AF_INET6; + addr6->sin6_scope_id = 0; + } else { + addr_st.ss_family = AF_INET; + addr4->sin_addr.s_addr = htonl(INADDR_ANY); + } + } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) { + /* nothing, address was parsed */ + } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) { + /* nothing, address was parsed */ + } else { + return -EINVAL; + } + + if (addr_st.ss_family == AF_INET) { + if (setsockopt(handle->io_watcher.fd, + IPPROTO_IP, + IP_MULTICAST_IF, + (void*) &addr4->sin_addr, + sizeof(addr4->sin_addr)) == -1) { + return -errno; + } + } else if (addr_st.ss_family == AF_INET6) { + if (setsockopt(handle->io_watcher.fd, + IPPROTO_IPV6, + IPV6_MULTICAST_IF, + &addr6->sin6_scope_id, + sizeof(addr6->sin6_scope_id)) == -1) { + return -errno; + } + } else { + assert(0 && "unexpected address family"); + abort(); + } + + return 0; +} + + +int uv_udp_getsockname(const uv_udp_t* handle, + struct sockaddr* name, + int* namelen) { + socklen_t socklen; + + if (handle->io_watcher.fd == -1) + return -EINVAL; /* FIXME(bnoordhuis) -EBADF */ + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (getsockname(handle->io_watcher.fd, name, &socklen)) + return -errno; + + *namelen = (int) socklen; + return 0; +} + + +int uv__udp_recv_start(uv_udp_t* handle, + uv_alloc_cb alloc_cb, + uv_udp_recv_cb recv_cb) { + int err; + + if (alloc_cb == NULL || recv_cb == NULL) + return -EINVAL; + + if (uv__io_active(&handle->io_watcher, POLLIN)) + return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */ + + err = uv__udp_maybe_deferred_bind(handle, AF_INET, 0); + if (err) + return err; + + handle->alloc_cb = alloc_cb; + handle->recv_cb = recv_cb; + + uv__io_start(handle->loop, &handle->io_watcher, POLLIN); + uv__handle_start(handle); + + return 0; +} + + +int uv__udp_recv_stop(uv_udp_t* handle) { + uv__io_stop(handle->loop, &handle->io_watcher, POLLIN); + + if (!uv__io_active(&handle->io_watcher, POLLOUT)) + uv__handle_stop(handle); + + handle->alloc_cb = NULL; + handle->recv_cb = NULL; + + return 0; +} diff --git a/src/uv-common.c b/src/uv-common.c new file mode 100644 index 0000000..434a502 --- /dev/null +++ b/src/uv-common.c @@ -0,0 +1,652 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "uv-common.h" + +#include +#include +#include +#include /* NULL */ +#include +#include /* malloc */ +#include /* memset */ + +#if defined(_WIN32) +# include /* malloc */ +#else +# include /* if_nametoindex */ +#endif + + +typedef struct { + uv_malloc_func local_malloc; + uv_realloc_func local_realloc; + uv_calloc_func local_calloc; + uv_free_func local_free; +} uv__allocator_t; + +static uv__allocator_t uv__allocator = { + malloc, + realloc, + calloc, + free, +}; + +char* uv__strdup(const char* s) { + size_t len = strlen(s) + 1; + char* m = uv__malloc(len); + if (m == NULL) + return NULL; + return memcpy(m, s, len); +} + +char* uv__strndup(const char* s, size_t n) { + char* m; + size_t len = strlen(s); + if (n < len) + len = n; + m = uv__malloc(len + 1); + if (m == NULL) + return NULL; + m[len] = '\0'; + return memcpy(m, s, len); +} + +void* uv__malloc(size_t size) { + return uv__allocator.local_malloc(size); +} + +void uv__free(void* ptr) { + int saved_errno; + + /* Libuv expects that free() does not clobber errno. The system allocator + * honors that assumption but custom allocators may not be so careful. + */ + saved_errno = errno; + uv__allocator.local_free(ptr); + errno = saved_errno; +} + +void* uv__calloc(size_t count, size_t size) { + return uv__allocator.local_calloc(count, size); +} + +void* uv__realloc(void* ptr, size_t size) { + return uv__allocator.local_realloc(ptr, size); +} + +int uv_replace_allocator(uv_malloc_func malloc_func, + uv_realloc_func realloc_func, + uv_calloc_func calloc_func, + uv_free_func free_func) { + if (malloc_func == NULL || realloc_func == NULL || + calloc_func == NULL || free_func == NULL) { + return UV_EINVAL; + } + + uv__allocator.local_malloc = malloc_func; + uv__allocator.local_realloc = realloc_func; + uv__allocator.local_calloc = calloc_func; + uv__allocator.local_free = free_func; + + return 0; +} + +#define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t); + +size_t uv_handle_size(uv_handle_type type) { + switch (type) { + UV_HANDLE_TYPE_MAP(XX) + default: + return -1; + } +} + +size_t uv_req_size(uv_req_type type) { + switch(type) { + UV_REQ_TYPE_MAP(XX) + default: + return -1; + } +} + +#undef XX + + +size_t uv_loop_size(void) { + return sizeof(uv_loop_t); +} + + +uv_buf_t uv_buf_init(char* base, unsigned int len) { + uv_buf_t buf; + buf.base = base; + buf.len = len; + return buf; +} + + +static const char* uv__unknown_err_code(int err) { + char buf[32]; + char* copy; + + snprintf(buf, sizeof(buf), "Unknown system error %d", err); + copy = uv__strdup(buf); + + return copy != NULL ? copy : "Unknown system error"; +} + + +#define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name; +const char* uv_err_name(int err) { + switch (err) { + UV_ERRNO_MAP(UV_ERR_NAME_GEN) + } + return uv__unknown_err_code(err); +} +#undef UV_ERR_NAME_GEN + + +#define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg; +const char* uv_strerror(int err) { + switch (err) { + UV_ERRNO_MAP(UV_STRERROR_GEN) + } + return uv__unknown_err_code(err); +} +#undef UV_STRERROR_GEN + + +int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) { + memset(addr, 0, sizeof(*addr)); + addr->sin_family = AF_INET; + addr->sin_port = htons(port); + return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr)); +} + + +int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) { + char address_part[40]; + size_t address_part_size; + const char* zone_index; + + memset(addr, 0, sizeof(*addr)); + addr->sin6_family = AF_INET6; + addr->sin6_port = htons(port); + + zone_index = strchr(ip, '%'); + if (zone_index != NULL) { + address_part_size = zone_index - ip; + if (address_part_size >= sizeof(address_part)) + address_part_size = sizeof(address_part) - 1; + + memcpy(address_part, ip, address_part_size); + address_part[address_part_size] = '\0'; + ip = address_part; + + zone_index++; /* skip '%' */ + /* NOTE: unknown interface (id=0) is silently ignored */ +#ifdef _WIN32 + addr->sin6_scope_id = atoi(zone_index); +#else + addr->sin6_scope_id = if_nametoindex(zone_index); +#endif + } + + return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr); +} + + +int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size) { + return uv_inet_ntop(AF_INET, &src->sin_addr, dst, size); +} + + +int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) { + return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size); +} + + +int uv_tcp_bind(uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int flags) { + unsigned int addrlen; + + if (handle->type != UV_TCP) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (addr->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return UV_EINVAL; + + return uv__tcp_bind(handle, addr, addrlen, flags); +} + + +int uv_udp_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int flags) { + unsigned int addrlen; + + if (handle->type != UV_UDP) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (addr->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return UV_EINVAL; + + return uv__udp_bind(handle, addr, addrlen, flags); +} + + +int uv_tcp_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + uv_connect_cb cb) { + unsigned int addrlen; + + if (handle->type != UV_TCP) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (addr->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return UV_EINVAL; + + return uv__tcp_connect(req, handle, addr, addrlen, cb); +} + + +int uv_udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + uv_udp_send_cb send_cb) { + unsigned int addrlen; + + if (handle->type != UV_UDP) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (addr->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return UV_EINVAL; + + return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb); +} + + +int uv_udp_try_send(uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr) { + unsigned int addrlen; + + if (handle->type != UV_UDP) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (addr->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return UV_EINVAL; + + return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen); +} + + +int uv_udp_recv_start(uv_udp_t* handle, + uv_alloc_cb alloc_cb, + uv_udp_recv_cb recv_cb) { + if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL) + return UV_EINVAL; + else + return uv__udp_recv_start(handle, alloc_cb, recv_cb); +} + + +int uv_udp_recv_stop(uv_udp_t* handle) { + if (handle->type != UV_UDP) + return UV_EINVAL; + else + return uv__udp_recv_stop(handle); +} + + +void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) { + QUEUE queue; + QUEUE* q; + uv_handle_t* h; + + QUEUE_MOVE(&loop->handle_queue, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + h = QUEUE_DATA(q, uv_handle_t, handle_queue); + + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&loop->handle_queue, q); + + if (h->flags & UV__HANDLE_INTERNAL) continue; + walk_cb(h, arg); + } +} + + +static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) { + const char* type; + QUEUE* q; + uv_handle_t* h; + + if (loop == NULL) + loop = uv_default_loop(); + + QUEUE_FOREACH(q, &loop->handle_queue) { + h = QUEUE_DATA(q, uv_handle_t, handle_queue); + + if (only_active && !uv__is_active(h)) + continue; + + switch (h->type) { +#define X(uc, lc) case UV_##uc: type = #lc; break; + UV_HANDLE_TYPE_MAP(X) +#undef X + default: type = ""; + } + + fprintf(stream, + "[%c%c%c] %-8s %p\n", + "R-"[!(h->flags & UV__HANDLE_REF)], + "A-"[!(h->flags & UV__HANDLE_ACTIVE)], + "I-"[!(h->flags & UV__HANDLE_INTERNAL)], + type, + (void*)h); + } +} + + +void uv_print_all_handles(uv_loop_t* loop, FILE* stream) { + uv__print_handles(loop, 0, stream); +} + + +void uv_print_active_handles(uv_loop_t* loop, FILE* stream) { + uv__print_handles(loop, 1, stream); +} + + +void uv_ref(uv_handle_t* handle) { + uv__handle_ref(handle); +} + + +void uv_unref(uv_handle_t* handle) { + uv__handle_unref(handle); +} + + +int uv_has_ref(const uv_handle_t* handle) { + return uv__has_ref(handle); +} + + +void uv_stop(uv_loop_t* loop) { + loop->stop_flag = 1; +} + + +uint64_t uv_now(const uv_loop_t* loop) { + return loop->time; +} + + + +size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) { + unsigned int i; + size_t bytes; + + bytes = 0; + for (i = 0; i < nbufs; i++) + bytes += (size_t) bufs[i].len; + + return bytes; +} + +int uv_recv_buffer_size(uv_handle_t* handle, int* value) { + return uv__socket_sockopt(handle, SO_RCVBUF, value); +} + +int uv_send_buffer_size(uv_handle_t* handle, int *value) { + return uv__socket_sockopt(handle, SO_SNDBUF, value); +} + +int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) { + size_t required_len; + + if (!uv__is_active(handle)) { + *size = 0; + return UV_EINVAL; + } + + required_len = strlen(handle->path); + if (required_len >= *size) { + *size = required_len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, handle->path, required_len); + *size = required_len; + buffer[required_len] = '\0'; + + return 0; +} + +/* The windows implementation does not have the same structure layout as + * the unix implementation (nbufs is not directly inside req but is + * contained in a nested union/struct) so this function locates it. +*/ +static unsigned int* uv__get_nbufs(uv_fs_t* req) { +#ifdef _WIN32 + return &req->fs.info.nbufs; +#else + return &req->nbufs; +#endif +} + +/* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows + * systems. So, the memory should be released using free(). On Windows, + * uv__malloc() is used, so use uv__free() to free memory. +*/ +#ifdef _WIN32 +# define uv__fs_scandir_free uv__free +#else +# define uv__fs_scandir_free free +#endif + +void uv__fs_scandir_cleanup(uv_fs_t* req) { + uv__dirent_t** dents; + + unsigned int* nbufs = uv__get_nbufs(req); + + dents = req->ptr; + if (*nbufs > 0 && *nbufs != (unsigned int) req->result) + (*nbufs)--; + for (; *nbufs < (unsigned int) req->result; (*nbufs)++) + uv__fs_scandir_free(dents[*nbufs]); + + uv__fs_scandir_free(req->ptr); + req->ptr = NULL; +} + + +int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) { + uv__dirent_t** dents; + uv__dirent_t* dent; + + unsigned int* nbufs = uv__get_nbufs(req); + + dents = req->ptr; + + /* Free previous entity */ + if (*nbufs > 0) + uv__fs_scandir_free(dents[*nbufs - 1]); + + /* End was already reached */ + if (*nbufs == (unsigned int) req->result) { + uv__fs_scandir_free(dents); + req->ptr = NULL; + return UV_EOF; + } + + dent = dents[(*nbufs)++]; + + ent->name = dent->d_name; +#ifdef HAVE_DIRENT_TYPES + switch (dent->d_type) { + case UV__DT_DIR: + ent->type = UV_DIRENT_DIR; + break; + case UV__DT_FILE: + ent->type = UV_DIRENT_FILE; + break; + case UV__DT_LINK: + ent->type = UV_DIRENT_LINK; + break; + case UV__DT_FIFO: + ent->type = UV_DIRENT_FIFO; + break; + case UV__DT_SOCKET: + ent->type = UV_DIRENT_SOCKET; + break; + case UV__DT_CHAR: + ent->type = UV_DIRENT_CHAR; + break; + case UV__DT_BLOCK: + ent->type = UV_DIRENT_BLOCK; + break; + default: + ent->type = UV_DIRENT_UNKNOWN; + } +#else + ent->type = UV_DIRENT_UNKNOWN; +#endif + + return 0; +} + + +int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) { + va_list ap; + int err; + + va_start(ap, option); + /* Any platform-agnostic options should be handled here. */ + err = uv__loop_configure(loop, option, ap); + va_end(ap); + + return err; +} + + +static uv_loop_t default_loop_struct; +static uv_loop_t* default_loop_ptr; + + +uv_loop_t* uv_default_loop(void) { + if (default_loop_ptr != NULL) + return default_loop_ptr; + + if (uv_loop_init(&default_loop_struct)) + return NULL; + + default_loop_ptr = &default_loop_struct; + return default_loop_ptr; +} + + +uv_loop_t* uv_loop_new(void) { + uv_loop_t* loop; + + loop = uv__malloc(sizeof(*loop)); + if (loop == NULL) + return NULL; + + if (uv_loop_init(loop)) { + uv__free(loop); + return NULL; + } + + return loop; +} + + +int uv_loop_close(uv_loop_t* loop) { + QUEUE* q; + uv_handle_t* h; + void* saved_data; + + if (!QUEUE_EMPTY(&(loop)->active_reqs)) + return UV_EBUSY; + + QUEUE_FOREACH(q, &loop->handle_queue) { + h = QUEUE_DATA(q, uv_handle_t, handle_queue); + if (!(h->flags & UV__HANDLE_INTERNAL)) + return UV_EBUSY; + } + + uv__loop_close(loop); + +#ifndef NDEBUG + saved_data = loop->data; + memset(loop, -1, sizeof(*loop)); + loop->data = saved_data; +#endif + if (loop == default_loop_ptr) + default_loop_ptr = NULL; + + return 0; +} + + +void uv_loop_delete(uv_loop_t* loop) { + uv_loop_t* default_loop; + int err; + + default_loop = default_loop_ptr; + + err = uv_loop_close(loop); + (void) err; /* Squelch compiler warnings. */ + assert(err == 0); + if (loop != default_loop) + uv__free(loop); +} diff --git a/src/uv-common.h b/src/uv-common.h new file mode 100644 index 0000000..27902fd --- /dev/null +++ b/src/uv-common.h @@ -0,0 +1,227 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +/* + * This file is private to libuv. It provides common functionality to both + * Windows and Unix backends. + */ + +#ifndef UV_COMMON_H_ +#define UV_COMMON_H_ + +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#include "uv.h" +#include "tree.h" +#include "queue.h" + +#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900 +extern int snprintf(char*, size_t, const char*, ...); +#endif + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#define container_of(ptr, type, member) \ + ((type *) ((char *) (ptr) - offsetof(type, member))) + +#define STATIC_ASSERT(expr) \ + void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)]) + +#ifndef _WIN32 +enum { + UV__HANDLE_INTERNAL = 0x8000, + UV__HANDLE_ACTIVE = 0x4000, + UV__HANDLE_REF = 0x2000, + UV__HANDLE_CLOSING = 0 /* no-op on unix */ +}; +#else +# define UV__HANDLE_INTERNAL 0x80 +# define UV__HANDLE_ACTIVE 0x40 +# define UV__HANDLE_REF 0x20 +# define UV__HANDLE_CLOSING 0x01 +#endif + +int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap); + +void uv__loop_close(uv_loop_t* loop); + +int uv__tcp_bind(uv_tcp_t* tcp, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags); + +int uv__tcp_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + uv_connect_cb cb); + +int uv__udp_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags); + +int uv__udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen, + uv_udp_send_cb send_cb); + +int uv__udp_try_send(uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen); + +int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb, + uv_udp_recv_cb recv_cb); + +int uv__udp_recv_stop(uv_udp_t* handle); + +void uv__fs_poll_close(uv_fs_poll_t* handle); + +int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */ + +void uv__work_submit(uv_loop_t* loop, + struct uv__work *w, + void (*work)(struct uv__work *w), + void (*done)(struct uv__work *w, int status)); + +void uv__work_done(uv_async_t* handle); + +size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs); + +int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value); + +void uv__fs_scandir_cleanup(uv_fs_t* req); + +#define uv__has_active_reqs(loop) \ + (QUEUE_EMPTY(&(loop)->active_reqs) == 0) + +#define uv__req_register(loop, req) \ + do { \ + QUEUE_INSERT_TAIL(&(loop)->active_reqs, &(req)->active_queue); \ + } \ + while (0) + +#define uv__req_unregister(loop, req) \ + do { \ + assert(uv__has_active_reqs(loop)); \ + QUEUE_REMOVE(&(req)->active_queue); \ + } \ + while (0) + +#define uv__has_active_handles(loop) \ + ((loop)->active_handles > 0) + +#define uv__active_handle_add(h) \ + do { \ + (h)->loop->active_handles++; \ + } \ + while (0) + +#define uv__active_handle_rm(h) \ + do { \ + (h)->loop->active_handles--; \ + } \ + while (0) + +#define uv__is_active(h) \ + (((h)->flags & UV__HANDLE_ACTIVE) != 0) + +#define uv__is_closing(h) \ + (((h)->flags & (UV_CLOSING | UV_CLOSED)) != 0) + +#define uv__handle_start(h) \ + do { \ + assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \ + if (((h)->flags & UV__HANDLE_ACTIVE) != 0) break; \ + (h)->flags |= UV__HANDLE_ACTIVE; \ + if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_add(h); \ + } \ + while (0) + +#define uv__handle_stop(h) \ + do { \ + assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \ + if (((h)->flags & UV__HANDLE_ACTIVE) == 0) break; \ + (h)->flags &= ~UV__HANDLE_ACTIVE; \ + if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_rm(h); \ + } \ + while (0) + +#define uv__handle_ref(h) \ + do { \ + if (((h)->flags & UV__HANDLE_REF) != 0) break; \ + (h)->flags |= UV__HANDLE_REF; \ + if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \ + if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \ + } \ + while (0) + +#define uv__handle_unref(h) \ + do { \ + if (((h)->flags & UV__HANDLE_REF) == 0) break; \ + (h)->flags &= ~UV__HANDLE_REF; \ + if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \ + if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \ + } \ + while (0) + +#define uv__has_ref(h) \ + (((h)->flags & UV__HANDLE_REF) != 0) + +#if defined(_WIN32) +# define uv__handle_platform_init(h) ((h)->u.fd = -1) +#else +# define uv__handle_platform_init(h) ((h)->next_closing = NULL) +#endif + +#define uv__handle_init(loop_, h, type_) \ + do { \ + (h)->loop = (loop_); \ + (h)->type = (type_); \ + (h)->flags = UV__HANDLE_REF; /* Ref the loop when active. */ \ + QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \ + uv__handle_platform_init(h); \ + } \ + while (0) + + +/* Allocator prototypes */ +void *uv__calloc(size_t count, size_t size); +char *uv__strdup(const char* s); +char *uv__strndup(const char* s, size_t n); +void* uv__malloc(size_t size); +void uv__free(void* ptr); +void* uv__realloc(void* ptr, size_t size); + +#endif /* UV_COMMON_H_ */ diff --git a/src/version.c b/src/version.c new file mode 100644 index 0000000..686dedd --- /dev/null +++ b/src/version.c @@ -0,0 +1,45 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" + +#define UV_STRINGIFY(v) UV_STRINGIFY_HELPER(v) +#define UV_STRINGIFY_HELPER(v) #v + +#define UV_VERSION_STRING_BASE UV_STRINGIFY(UV_VERSION_MAJOR) "." \ + UV_STRINGIFY(UV_VERSION_MINOR) "." \ + UV_STRINGIFY(UV_VERSION_PATCH) + +#if UV_VERSION_IS_RELEASE +# define UV_VERSION_STRING UV_VERSION_STRING_BASE +#else +# define UV_VERSION_STRING UV_VERSION_STRING_BASE "-" UV_VERSION_SUFFIX +#endif + + +unsigned int uv_version(void) { + return UV_VERSION_HEX; +} + + +const char* uv_version_string(void) { + return UV_VERSION_STRING; +} diff --git a/src/win/async.c b/src/win/async.c new file mode 100644 index 0000000..ad240ab --- /dev/null +++ b/src/win/async.c @@ -0,0 +1,99 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include + +#include "uv.h" +#include "internal.h" +#include "atomicops-inl.h" +#include "handle-inl.h" +#include "req-inl.h" + + +void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) { + if (handle->flags & UV__HANDLE_CLOSING && + !handle->async_sent) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); + } +} + + +int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { + uv_req_t* req; + + uv__handle_init(loop, (uv_handle_t*) handle, UV_ASYNC); + handle->async_sent = 0; + handle->async_cb = async_cb; + + req = &handle->async_req; + uv_req_init(loop, req); + req->type = UV_WAKEUP; + req->data = handle; + + uv__handle_start(handle); + + return 0; +} + + +void uv_async_close(uv_loop_t* loop, uv_async_t* handle) { + if (!((uv_async_t*)handle)->async_sent) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + + uv__handle_closing(handle); +} + + +int uv_async_send(uv_async_t* handle) { + uv_loop_t* loop = handle->loop; + + if (handle->type != UV_ASYNC) { + /* Can't set errno because that's not thread-safe. */ + return -1; + } + + /* The user should make sure never to call uv_async_send to a closing */ + /* or closed handle. */ + assert(!(handle->flags & UV__HANDLE_CLOSING)); + + if (!uv__atomic_exchange_set(&handle->async_sent)) { + POST_COMPLETION_FOR_REQ(loop, &handle->async_req); + } + + return 0; +} + + +void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, + uv_req_t* req) { + assert(handle->type == UV_ASYNC); + assert(req->type == UV_WAKEUP); + + handle->async_sent = 0; + + if (handle->flags & UV__HANDLE_CLOSING) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } else if (handle->async_cb != NULL) { + handle->async_cb(handle); + } +} diff --git a/src/win/atomicops-inl.h b/src/win/atomicops-inl.h new file mode 100644 index 0000000..61e0060 --- /dev/null +++ b/src/win/atomicops-inl.h @@ -0,0 +1,56 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_WIN_ATOMICOPS_INL_H_ +#define UV_WIN_ATOMICOPS_INL_H_ + +#include "uv.h" + + +/* Atomic set operation on char */ +#ifdef _MSC_VER /* MSVC */ + +/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */ +/* efficient than InterlockedExchange, but InterlockedExchange8 does not */ +/* exist, and interlocked operations on larger targets might require the */ +/* target to be aligned. */ +#pragma intrinsic(_InterlockedOr8) + +static char __declspec(inline) uv__atomic_exchange_set(char volatile* target) { + return _InterlockedOr8(target, 1); +} + +#else /* GCC */ + +/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */ +static inline char uv__atomic_exchange_set(char volatile* target) { + const char one = 1; + char old_value; + __asm__ __volatile__ ("lock xchgb %0, %1\n\t" + : "=r"(old_value), "=m"(*target) + : "0"(one), "m"(*target) + : "memory"); + return old_value; +} + +#endif + +#endif /* UV_WIN_ATOMICOPS_INL_H_ */ diff --git a/src/win/core.c b/src/win/core.c new file mode 100644 index 0000000..9d00afc --- /dev/null +++ b/src/win/core.c @@ -0,0 +1,602 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) +#include +#endif + +#include "uv.h" +#include "internal.h" +#include "queue.h" +#include "handle-inl.h" +#include "req-inl.h" + + +static uv_loop_t default_loop_struct; +static uv_loop_t* default_loop_ptr; + +/* uv_once initialization guards */ +static uv_once_t uv_init_guard_ = UV_ONCE_INIT; + + +#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)) +/* Our crt debug report handler allows us to temporarily disable asserts + * just for the current thread. + */ + +UV_THREAD_LOCAL int uv__crt_assert_enabled = TRUE; + +static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) { + if (uv__crt_assert_enabled || report_type != _CRT_ASSERT) + return FALSE; + + if (ret_val) { + /* Set ret_val to 0 to continue with normal execution. + * Set ret_val to 1 to trigger a breakpoint. + */ + + if(IsDebuggerPresent()) + *ret_val = 1; + else + *ret_val = 0; + } + + /* Don't call _CrtDbgReport. */ + return TRUE; +} +#else +UV_THREAD_LOCAL int uv__crt_assert_enabled = FALSE; +#endif + + +#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800 +static void uv__crt_invalid_parameter_handler(const wchar_t* expression, + const wchar_t* function, const wchar_t * file, unsigned int line, + uintptr_t reserved) { + /* No-op. */ +} +#endif + +static uv_loop_t** uv__loops; +static int uv__loops_size; +static int uv__loops_capacity; +#define UV__LOOPS_CHUNK_SIZE 8 +static uv_mutex_t uv__loops_lock; + +static void uv__loops_init() { + uv_mutex_init(&uv__loops_lock); + uv__loops = uv__calloc(UV__LOOPS_CHUNK_SIZE, sizeof(uv_loop_t*)); + if (!uv__loops) + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + uv__loops_size = 0; + uv__loops_capacity = UV__LOOPS_CHUNK_SIZE; +} + +static int uv__loops_add(uv_loop_t* loop) { + uv_loop_t** new_loops; + int new_capacity, i; + + uv_mutex_lock(&uv__loops_lock); + + if (uv__loops_size == uv__loops_capacity) { + new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE; + new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity); + if (!new_loops) + goto failed_loops_realloc; + uv__loops = new_loops; + for (i = uv__loops_capacity; i < new_capacity; ++i) + uv__loops[i] = NULL; + uv__loops_capacity = new_capacity; + } + uv__loops[uv__loops_size] = loop; + ++uv__loops_size; + + uv_mutex_unlock(&uv__loops_lock); + return 0; + +failed_loops_realloc: + uv_mutex_unlock(&uv__loops_lock); + return ERROR_OUTOFMEMORY; +} + +static void uv__loops_remove(uv_loop_t* loop) { + int loop_index; + int smaller_capacity; + uv_loop_t** new_loops; + + uv_mutex_lock(&uv__loops_lock); + + for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) { + if (uv__loops[loop_index] == loop) + break; + } + /* If loop was not found, ignore */ + if (loop_index == uv__loops_size) + goto loop_removed; + + uv__loops[loop_index] = uv__loops[uv__loops_size - 1]; + uv__loops[uv__loops_size - 1] = NULL; + --uv__loops_size; + + /* If we didn't grow to big skip downsizing */ + if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE) + goto loop_removed; + + /* Downsize only if more than half of buffer is free */ + smaller_capacity = uv__loops_capacity / 2; + if (uv__loops_size >= smaller_capacity) + goto loop_removed; + new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity); + if (!new_loops) + goto loop_removed; + uv__loops = new_loops; + uv__loops_capacity = smaller_capacity; + +loop_removed: + uv_mutex_unlock(&uv__loops_lock); +} + +void uv__wake_all_loops() { + int i; + uv_loop_t* loop; + + uv_mutex_lock(&uv__loops_lock); + for (i = 0; i < uv__loops_size; ++i) { + loop = uv__loops[i]; + assert(loop); + if (loop->iocp != INVALID_HANDLE_VALUE) + PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL); + } + uv_mutex_unlock(&uv__loops_lock); +} + +static void uv_init(void) { + /* Tell Windows that we will handle critical errors. */ + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX); + + /* Tell the CRT to not exit the application when an invalid parameter is + * passed. The main issue is that invalid FDs will trigger this behavior. + */ +#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800 + _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler); +#endif + + /* We also need to setup our debug report handler because some CRT + * functions (eg _get_osfhandle) raise an assert when called with invalid + * FDs even though they return the proper error code in the release build. + */ +#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)) + _CrtSetReportHook(uv__crt_dbg_report_handler); +#endif + + /* Initialize tracking of all uv loops */ + uv__loops_init(); + + /* Fetch winapi function pointers. This must be done first because other + * initialization code might need these function pointers to be loaded. + */ + uv_winapi_init(); + + /* Initialize winsock */ + uv_winsock_init(); + + /* Initialize FS */ + uv_fs_init(); + + /* Initialize signal stuff */ + uv_signals_init(); + + /* Initialize console */ + uv_console_init(); + + /* Initialize utilities */ + uv__util_init(); + + /* Initialize system wakeup detection */ + uv__init_detect_system_wakeup(); +} + + +int uv_loop_init(uv_loop_t* loop) { + int err; + + /* Initialize libuv itself first */ + uv__once_init(); + + /* Create an I/O completion port */ + loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); + if (loop->iocp == NULL) + return uv_translate_sys_error(GetLastError()); + + /* To prevent uninitialized memory access, loop->time must be initialized + * to zero before calling uv_update_time for the first time. + */ + loop->time = 0; + uv_update_time(loop); + + QUEUE_INIT(&loop->wq); + QUEUE_INIT(&loop->handle_queue); + QUEUE_INIT(&loop->active_reqs); + loop->active_handles = 0; + + loop->pending_reqs_tail = NULL; + + loop->endgame_handles = NULL; + + RB_INIT(&loop->timers); + + loop->check_handles = NULL; + loop->prepare_handles = NULL; + loop->idle_handles = NULL; + + loop->next_prepare_handle = NULL; + loop->next_check_handle = NULL; + loop->next_idle_handle = NULL; + + memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets); + + loop->active_tcp_streams = 0; + loop->active_udp_streams = 0; + + loop->timer_counter = 0; + loop->stop_flag = 0; + + err = uv_mutex_init(&loop->wq_mutex); + if (err) + goto fail_mutex_init; + + err = uv_async_init(loop, &loop->wq_async, uv__work_done); + if (err) + goto fail_async_init; + + uv__handle_unref(&loop->wq_async); + loop->wq_async.flags |= UV__HANDLE_INTERNAL; + + err = uv__loops_add(loop); + if (err) + goto fail_async_init; + + return 0; + +fail_async_init: + uv_mutex_destroy(&loop->wq_mutex); + +fail_mutex_init: + CloseHandle(loop->iocp); + loop->iocp = INVALID_HANDLE_VALUE; + + return err; +} + + +void uv__once_init(void) { + uv_once(&uv_init_guard_, uv_init); +} + + +void uv__loop_close(uv_loop_t* loop) { + size_t i; + + uv__loops_remove(loop); + + /* close the async handle without needing an extra loop iteration */ + assert(!loop->wq_async.async_sent); + loop->wq_async.close_cb = NULL; + uv__handle_closing(&loop->wq_async); + uv__handle_close(&loop->wq_async); + + for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) { + SOCKET sock = loop->poll_peer_sockets[i]; + if (sock != 0 && sock != INVALID_SOCKET) + closesocket(sock); + } + + uv_mutex_lock(&loop->wq_mutex); + assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!"); + assert(!uv__has_active_reqs(loop)); + uv_mutex_unlock(&loop->wq_mutex); + uv_mutex_destroy(&loop->wq_mutex); + + CloseHandle(loop->iocp); +} + + +int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) { + return UV_ENOSYS; +} + + +int uv_backend_fd(const uv_loop_t* loop) { + return -1; +} + + +int uv_backend_timeout(const uv_loop_t* loop) { + if (loop->stop_flag != 0) + return 0; + + if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop)) + return 0; + + if (loop->pending_reqs_tail) + return 0; + + if (loop->endgame_handles) + return 0; + + if (loop->idle_handles) + return 0; + + return uv__next_timeout(loop); +} + + +static void uv_poll(uv_loop_t* loop, DWORD timeout) { + DWORD bytes; + ULONG_PTR key; + OVERLAPPED* overlapped; + uv_req_t* req; + int repeat; + uint64_t timeout_time; + + timeout_time = loop->time + timeout; + + for (repeat = 0; ; repeat++) { + GetQueuedCompletionStatus(loop->iocp, + &bytes, + &key, + &overlapped, + timeout); + + if (overlapped) { + /* Package was dequeued */ + req = uv_overlapped_to_req(overlapped); + uv_insert_pending_req(loop, req); + + /* Some time might have passed waiting for I/O, + * so update the loop time here. + */ + uv_update_time(loop); + } else if (GetLastError() != WAIT_TIMEOUT) { + /* Serious error */ + uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); + } else if (timeout > 0) { + /* GetQueuedCompletionStatus can occasionally return a little early. + * Make sure that the desired timeout target time is reached. + */ + uv_update_time(loop); + if (timeout_time > loop->time) { + timeout = (DWORD)(timeout_time - loop->time); + /* The first call to GetQueuedCompletionStatus should return very + * close to the target time and the second should reach it, but + * this is not stated in the documentation. To make sure a busy + * loop cannot happen, the timeout is increased exponentially + * starting on the third round. + */ + timeout += repeat ? (1 << (repeat - 1)) : 0; + continue; + } + } + break; + } +} + + +static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { + BOOL success; + uv_req_t* req; + OVERLAPPED_ENTRY overlappeds[128]; + ULONG count; + ULONG i; + int repeat; + uint64_t timeout_time; + + timeout_time = loop->time + timeout; + + for (repeat = 0; ; repeat++) { + success = pGetQueuedCompletionStatusEx(loop->iocp, + overlappeds, + ARRAY_SIZE(overlappeds), + &count, + timeout, + FALSE); + + if (success) { + for (i = 0; i < count; i++) { + /* Package was dequeued, but see if it is not a empty package + * meant only to wake us up. + */ + if (overlappeds[i].lpOverlapped) { + req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); + uv_insert_pending_req(loop, req); + } + } + + /* Some time might have passed waiting for I/O, + * so update the loop time here. + */ + uv_update_time(loop); + } else if (GetLastError() != WAIT_TIMEOUT) { + /* Serious error */ + uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx"); + } else if (timeout > 0) { + /* GetQueuedCompletionStatus can occasionally return a little early. + * Make sure that the desired timeout target time is reached. + */ + uv_update_time(loop); + if (timeout_time > loop->time) { + timeout = (DWORD)(timeout_time - loop->time); + /* The first call to GetQueuedCompletionStatus should return very + * close to the target time and the second should reach it, but + * this is not stated in the documentation. To make sure a busy + * loop cannot happen, the timeout is increased exponentially + * starting on the third round. + */ + timeout += repeat ? (1 << (repeat - 1)) : 0; + continue; + } + } + break; + } +} + + +static int uv__loop_alive(const uv_loop_t* loop) { + return loop->active_handles > 0 || + !QUEUE_EMPTY(&loop->active_reqs) || + loop->endgame_handles != NULL; +} + + +int uv_loop_alive(const uv_loop_t* loop) { + return uv__loop_alive(loop); +} + + +int uv_run(uv_loop_t *loop, uv_run_mode mode) { + DWORD timeout; + int r; + int ran_pending; + void (*poll)(uv_loop_t* loop, DWORD timeout); + + if (pGetQueuedCompletionStatusEx) + poll = &uv_poll_ex; + else + poll = &uv_poll; + + r = uv__loop_alive(loop); + if (!r) + uv_update_time(loop); + + while (r != 0 && loop->stop_flag == 0) { + uv_update_time(loop); + uv_process_timers(loop); + + ran_pending = uv_process_reqs(loop); + uv_idle_invoke(loop); + uv_prepare_invoke(loop); + + timeout = 0; + if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) + timeout = uv_backend_timeout(loop); + + (*poll)(loop, timeout); + + uv_check_invoke(loop); + uv_process_endgames(loop); + + if (mode == UV_RUN_ONCE) { + /* UV_RUN_ONCE implies forward progress: at least one callback must have + * been invoked when it returns. uv__io_poll() can return without doing + * I/O (meaning: no callbacks) when its timeout expires - which means we + * have pending timers that satisfy the forward progress constraint. + * + * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from + * the check. + */ + uv_process_timers(loop); + } + + r = uv__loop_alive(loop); + if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT) + break; + } + + /* The if statement lets the compiler compile it to a conditional store. + * Avoids dirtying a cache line. + */ + if (loop->stop_flag != 0) + loop->stop_flag = 0; + + return r; +} + + +int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) { + uv_os_fd_t fd_out; + + switch (handle->type) { + case UV_TCP: + fd_out = (uv_os_fd_t)((uv_tcp_t*) handle)->socket; + break; + + case UV_NAMED_PIPE: + fd_out = ((uv_pipe_t*) handle)->handle; + break; + + case UV_TTY: + fd_out = ((uv_tty_t*) handle)->handle; + break; + + case UV_UDP: + fd_out = (uv_os_fd_t)((uv_udp_t*) handle)->socket; + break; + + case UV_POLL: + fd_out = (uv_os_fd_t)((uv_poll_t*) handle)->socket; + break; + + default: + return UV_EINVAL; + } + + if (uv_is_closing(handle) || fd_out == INVALID_HANDLE_VALUE) + return UV_EBADF; + + *fd = fd_out; + return 0; +} + + +int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { + int r; + int len; + SOCKET socket; + + if (handle == NULL || value == NULL) + return UV_EINVAL; + + if (handle->type == UV_TCP) + socket = ((uv_tcp_t*) handle)->socket; + else if (handle->type == UV_UDP) + socket = ((uv_udp_t*) handle)->socket; + else + return UV_ENOTSUP; + + len = sizeof(*value); + + if (*value == 0) + r = getsockopt(socket, SOL_SOCKET, optname, (char*) value, &len); + else + r = setsockopt(socket, SOL_SOCKET, optname, (const char*) value, len); + + if (r == SOCKET_ERROR) + return uv_translate_sys_error(WSAGetLastError()); + + return 0; +} diff --git a/src/win/detect-wakeup.c b/src/win/detect-wakeup.c new file mode 100644 index 0000000..a12179f --- /dev/null +++ b/src/win/detect-wakeup.c @@ -0,0 +1,35 @@ +#include "uv.h" +#include "internal.h" +#include "winapi.h" + +static void uv__register_system_resume_callback(); + +void uv__init_detect_system_wakeup() { + /* Try registering system power event callback. This is the cleanest + * method, but it will only work on Win8 and above. + */ + uv__register_system_resume_callback(); +} + +static ULONG CALLBACK uv__system_resume_callback(PVOID Context, + ULONG Type, + PVOID Setting) { + if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC) + uv__wake_all_loops(); + + return 0; +} + +static void uv__register_system_resume_callback() { + _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient; + _HPOWERNOTIFY registration_handle; + + if (pPowerRegisterSuspendResumeNotification == NULL) + return; + + recipient.Callback = uv__system_resume_callback; + recipient.Context = NULL; + (*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK, + &recipient, + ®istration_handle); +} diff --git a/src/win/dl.c b/src/win/dl.c new file mode 100644 index 0000000..39e400a --- /dev/null +++ b/src/win/dl.c @@ -0,0 +1,118 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include "uv.h" +#include "internal.h" + +static int uv__dlerror(uv_lib_t* lib, int errorno); + + +int uv_dlopen(const char* filename, uv_lib_t* lib) { + WCHAR filename_w[32768]; + + lib->handle = NULL; + lib->errmsg = NULL; + + if (!MultiByteToWideChar(CP_UTF8, + 0, + filename, + -1, + filename_w, + ARRAY_SIZE(filename_w))) { + return uv__dlerror(lib, GetLastError()); + } + + lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (lib->handle == NULL) { + return uv__dlerror(lib, GetLastError()); + } + + return 0; +} + + +void uv_dlclose(uv_lib_t* lib) { + if (lib->errmsg) { + LocalFree((void*)lib->errmsg); + lib->errmsg = NULL; + } + + if (lib->handle) { + /* Ignore errors. No good way to signal them without leaking memory. */ + FreeLibrary(lib->handle); + lib->handle = NULL; + } +} + + +int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) { + *ptr = (void*) GetProcAddress(lib->handle, name); + return uv__dlerror(lib, *ptr ? 0 : GetLastError()); +} + + +const char* uv_dlerror(const uv_lib_t* lib) { + return lib->errmsg ? lib->errmsg : "no error"; +} + + +static void uv__format_fallback_error(uv_lib_t* lib, int errorno){ + DWORD_PTR args[1] = { (DWORD_PTR) errorno }; + LPSTR fallback_error = "error: %1!d!"; + + FormatMessageA(FORMAT_MESSAGE_FROM_STRING | + FORMAT_MESSAGE_ARGUMENT_ARRAY | + FORMAT_MESSAGE_ALLOCATE_BUFFER, + fallback_error, 0, 0, + (LPSTR) &lib->errmsg, + 0, (va_list*) args); +} + + + +static int uv__dlerror(uv_lib_t* lib, int errorno) { + DWORD res; + + if (lib->errmsg) { + LocalFree((void*)lib->errmsg); + lib->errmsg = NULL; + } + + if (errorno) { + res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + (LPSTR) &lib->errmsg, 0, NULL); + if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) { + res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, + 0, (LPSTR) &lib->errmsg, 0, NULL); + } + + if (!res) { + uv__format_fallback_error(lib, errorno); + } + } + + return errorno ? -1 : 0; +} diff --git a/src/win/error.c b/src/win/error.c new file mode 100644 index 0000000..c512f35 --- /dev/null +++ b/src/win/error.c @@ -0,0 +1,170 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" + + +/* + * Display an error message and abort the event loop. + */ +void uv_fatal_error(const int errorno, const char* syscall) { + char* buf = NULL; + const char* errmsg; + + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL); + + if (buf) { + errmsg = buf; + } else { + errmsg = "Unknown error"; + } + + /* FormatMessage messages include a newline character already, */ + /* so don't add another. */ + if (syscall) { + fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg); + } else { + fprintf(stderr, "(%d) %s", errorno, errmsg); + } + + if (buf) { + LocalFree(buf); + } + + *((char*)NULL) = 0xff; /* Force debug break */ + abort(); +} + + +int uv_translate_sys_error(int sys_errno) { + if (sys_errno <= 0) { + return sys_errno; /* If < 0 then it's already a libuv error. */ + } + + switch (sys_errno) { + case ERROR_NOACCESS: return UV_EACCES; + case WSAEACCES: return UV_EACCES; + case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE; + case WSAEADDRINUSE: return UV_EADDRINUSE; + case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL; + case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT; + case WSAEWOULDBLOCK: return UV_EAGAIN; + case WSAEALREADY: return UV_EALREADY; + case ERROR_INVALID_FLAGS: return UV_EBADF; + case ERROR_INVALID_HANDLE: return UV_EBADF; + case ERROR_LOCK_VIOLATION: return UV_EBUSY; + case ERROR_PIPE_BUSY: return UV_EBUSY; + case ERROR_SHARING_VIOLATION: return UV_EBUSY; + case ERROR_OPERATION_ABORTED: return UV_ECANCELED; + case WSAEINTR: return UV_ECANCELED; + case ERROR_NO_UNICODE_TRANSLATION: return UV_ECHARSET; + case ERROR_CONNECTION_ABORTED: return UV_ECONNABORTED; + case WSAECONNABORTED: return UV_ECONNABORTED; + case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED; + case WSAECONNREFUSED: return UV_ECONNREFUSED; + case ERROR_NETNAME_DELETED: return UV_ECONNRESET; + case WSAECONNRESET: return UV_ECONNRESET; + case ERROR_ALREADY_EXISTS: return UV_EEXIST; + case ERROR_FILE_EXISTS: return UV_EEXIST; + case ERROR_BUFFER_OVERFLOW: return UV_EFAULT; + case WSAEFAULT: return UV_EFAULT; + case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH; + case WSAEHOSTUNREACH: return UV_EHOSTUNREACH; + case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL; + case ERROR_INVALID_DATA: return UV_EINVAL; + case ERROR_INVALID_PARAMETER: return UV_EINVAL; + case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL; + case WSAEINVAL: return UV_EINVAL; + case WSAEPFNOSUPPORT: return UV_EINVAL; + case WSAESOCKTNOSUPPORT: return UV_EINVAL; + case ERROR_BEGINNING_OF_MEDIA: return UV_EIO; + case ERROR_BUS_RESET: return UV_EIO; + case ERROR_CRC: return UV_EIO; + case ERROR_DEVICE_DOOR_OPEN: return UV_EIO; + case ERROR_DEVICE_REQUIRES_CLEANING: return UV_EIO; + case ERROR_DISK_CORRUPT: return UV_EIO; + case ERROR_EOM_OVERFLOW: return UV_EIO; + case ERROR_FILEMARK_DETECTED: return UV_EIO; + case ERROR_GEN_FAILURE: return UV_EIO; + case ERROR_INVALID_BLOCK_LENGTH: return UV_EIO; + case ERROR_IO_DEVICE: return UV_EIO; + case ERROR_NO_DATA_DETECTED: return UV_EIO; + case ERROR_NO_SIGNAL_SENT: return UV_EIO; + case ERROR_OPEN_FAILED: return UV_EIO; + case ERROR_SETMARK_DETECTED: return UV_EIO; + case ERROR_SIGNAL_REFUSED: return UV_EIO; + case WSAEISCONN: return UV_EISCONN; + case ERROR_CANT_RESOLVE_FILENAME: return UV_ELOOP; + case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE; + case WSAEMFILE: return UV_EMFILE; + case WSAEMSGSIZE: return UV_EMSGSIZE; + case ERROR_FILENAME_EXCED_RANGE: return UV_ENAMETOOLONG; + case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH; + case WSAENETUNREACH: return UV_ENETUNREACH; + case WSAENOBUFS: return UV_ENOBUFS; + case ERROR_BAD_PATHNAME: return UV_ENOENT; + case ERROR_DIRECTORY: return UV_ENOENT; + case ERROR_FILE_NOT_FOUND: return UV_ENOENT; + case ERROR_INVALID_NAME: return UV_ENOENT; + case ERROR_INVALID_DRIVE: return UV_ENOENT; + case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT; + case ERROR_MOD_NOT_FOUND: return UV_ENOENT; + case ERROR_PATH_NOT_FOUND: return UV_ENOENT; + case WSAHOST_NOT_FOUND: return UV_ENOENT; + case WSANO_DATA: return UV_ENOENT; + case ERROR_NOT_ENOUGH_MEMORY: return UV_ENOMEM; + case ERROR_OUTOFMEMORY: return UV_ENOMEM; + case ERROR_CANNOT_MAKE: return UV_ENOSPC; + case ERROR_DISK_FULL: return UV_ENOSPC; + case ERROR_EA_TABLE_FULL: return UV_ENOSPC; + case ERROR_END_OF_MEDIA: return UV_ENOSPC; + case ERROR_HANDLE_DISK_FULL: return UV_ENOSPC; + case ERROR_NOT_CONNECTED: return UV_ENOTCONN; + case WSAENOTCONN: return UV_ENOTCONN; + case ERROR_DIR_NOT_EMPTY: return UV_ENOTEMPTY; + case WSAENOTSOCK: return UV_ENOTSOCK; + case ERROR_NOT_SUPPORTED: return UV_ENOTSUP; + case ERROR_BROKEN_PIPE: return UV_EOF; + case ERROR_ACCESS_DENIED: return UV_EPERM; + case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM; + case ERROR_BAD_PIPE: return UV_EPIPE; + case ERROR_NO_DATA: return UV_EPIPE; + case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE; + case WSAESHUTDOWN: return UV_EPIPE; + case WSAEPROTONOSUPPORT: return UV_EPROTONOSUPPORT; + case ERROR_WRITE_PROTECT: return UV_EROFS; + case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT; + case WSAETIMEDOUT: return UV_ETIMEDOUT; + case ERROR_NOT_SAME_DEVICE: return UV_EXDEV; + case ERROR_INVALID_FUNCTION: return UV_EISDIR; + case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG; + default: return UV_UNKNOWN; + } +} diff --git a/src/win/fs-event.c b/src/win/fs-event.c new file mode 100644 index 0000000..03e4adc --- /dev/null +++ b/src/win/fs-event.c @@ -0,0 +1,545 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +const unsigned int uv_directory_watcher_buffer_size = 4096; + + +static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop, + uv_fs_event_t* handle) { + assert(handle->dir_handle != INVALID_HANDLE_VALUE); + assert(!handle->req_pending); + + memset(&(handle->req.u.io.overlapped), 0, + sizeof(handle->req.u.io.overlapped)); + if (!ReadDirectoryChangesW(handle->dir_handle, + handle->buffer, + uv_directory_watcher_buffer_size, + (handle->flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE, + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_SECURITY, + NULL, + &handle->req.u.io.overlapped, + NULL)) { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(&handle->req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)&handle->req); + } + + handle->req_pending = 1; +} + +static void uv_relative_path(const WCHAR* filename, + const WCHAR* dir, + WCHAR** relpath) { + size_t relpathlen; + size_t filenamelen = wcslen(filename); + size_t dirlen = wcslen(dir); + if (dirlen > 0 && dir[dirlen - 1] == '\\') + dirlen--; + relpathlen = filenamelen - dirlen - 1; + *relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR)); + if (!*relpath) + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + wcsncpy(*relpath, filename + dirlen + 1, relpathlen); + (*relpath)[relpathlen] = L'\0'; +} + +static int uv_split_path(const WCHAR* filename, WCHAR** dir, + WCHAR** file) { + int len = wcslen(filename); + int i = len; + while (i > 0 && filename[--i] != '\\' && filename[i] != '/'); + + if (i == 0) { + if (dir) { + *dir = (WCHAR*)uv__malloc((MAX_PATH + 1) * sizeof(WCHAR)); + if (!*dir) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (!GetCurrentDirectoryW(MAX_PATH, *dir)) { + uv__free(*dir); + *dir = NULL; + return -1; + } + } + + *file = wcsdup(filename); + } else { + if (dir) { + *dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR)); + if (!*dir) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + wcsncpy(*dir, filename, i + 1); + (*dir)[i + 1] = L'\0'; + } + + *file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR)); + if (!*file) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + wcsncpy(*file, filename + i + 1, len - i - 1); + (*file)[len - i - 1] = L'\0'; + } + + return 0; +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + uv__handle_init(loop, (uv_handle_t*) handle, UV_FS_EVENT); + handle->dir_handle = INVALID_HANDLE_VALUE; + handle->buffer = NULL; + handle->req_pending = 0; + handle->filew = NULL; + handle->short_filew = NULL; + handle->dirw = NULL; + + uv_req_init(loop, (uv_req_t*)&handle->req); + handle->req.type = UV_FS_EVENT_REQ; + handle->req.data = handle; + + return 0; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* path, + unsigned int flags) { + int name_size, is_path_dir; + DWORD attr, last_error; + WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL; + WCHAR short_path[MAX_PATH]; + + if (uv__is_active(handle)) + return UV_EINVAL; + + handle->cb = cb; + handle->path = uv__strdup(path); + if (!handle->path) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + uv__handle_start(handle); + + /* Convert name to UTF16. */ + + name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) * + sizeof(WCHAR); + pathw = (WCHAR*)uv__malloc(name_size); + if (!pathw) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + path, + -1, + pathw, + name_size / sizeof(WCHAR))) { + return uv_translate_sys_error(GetLastError()); + } + + /* Determine whether path is a file or a directory. */ + attr = GetFileAttributesW(pathw); + if (attr == INVALID_FILE_ATTRIBUTES) { + last_error = GetLastError(); + goto error; + } + + is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0; + + if (is_path_dir) { + /* path is a directory, so that's the directory that we will watch. */ + handle->dirw = pathw; + dir_to_watch = pathw; + } else { + /* + * path is a file. So we split path into dir & file parts, and + * watch the dir directory. + */ + + /* Convert to short path. */ + if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) { + last_error = GetLastError(); + goto error; + } + + if (uv_split_path(pathw, &dir, &handle->filew) != 0) { + last_error = GetLastError(); + goto error; + } + + if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) { + last_error = GetLastError(); + goto error; + } + + dir_to_watch = dir; + uv__free(pathw); + pathw = NULL; + } + + handle->dir_handle = CreateFileW(dir_to_watch, + FILE_LIST_DIRECTORY, + FILE_SHARE_READ | FILE_SHARE_DELETE | + FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OVERLAPPED, + NULL); + + if (dir) { + uv__free(dir); + dir = NULL; + } + + if (handle->dir_handle == INVALID_HANDLE_VALUE) { + last_error = GetLastError(); + goto error; + } + + if (CreateIoCompletionPort(handle->dir_handle, + handle->loop->iocp, + (ULONG_PTR)handle, + 0) == NULL) { + last_error = GetLastError(); + goto error; + } + + if (!handle->buffer) { + handle->buffer = (char*)uv__malloc(uv_directory_watcher_buffer_size); + } + if (!handle->buffer) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + memset(&(handle->req.u.io.overlapped), 0, + sizeof(handle->req.u.io.overlapped)); + + if (!ReadDirectoryChangesW(handle->dir_handle, + handle->buffer, + uv_directory_watcher_buffer_size, + (flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE, + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_SECURITY, + NULL, + &handle->req.u.io.overlapped, + NULL)) { + last_error = GetLastError(); + goto error; + } + + handle->req_pending = 1; + return 0; + +error: + if (handle->path) { + uv__free(handle->path); + handle->path = NULL; + } + + if (handle->filew) { + uv__free(handle->filew); + handle->filew = NULL; + } + + if (handle->short_filew) { + uv__free(handle->short_filew); + handle->short_filew = NULL; + } + + uv__free(pathw); + + if (handle->dir_handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle->dir_handle); + handle->dir_handle = INVALID_HANDLE_VALUE; + } + + if (handle->buffer) { + uv__free(handle->buffer); + handle->buffer = NULL; + } + + return uv_translate_sys_error(last_error); +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + if (!uv__is_active(handle)) + return 0; + + if (handle->dir_handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle->dir_handle); + handle->dir_handle = INVALID_HANDLE_VALUE; + } + + uv__handle_stop(handle); + + if (handle->filew) { + uv__free(handle->filew); + handle->filew = NULL; + } + + if (handle->short_filew) { + uv__free(handle->short_filew); + handle->short_filew = NULL; + } + + if (handle->path) { + uv__free(handle->path); + handle->path = NULL; + } + + if (handle->dirw) { + uv__free(handle->dirw); + handle->dirw = NULL; + } + + return 0; +} + + +static int file_info_cmp(WCHAR* str, WCHAR* file_name, int file_name_len) { + int str_len; + + str_len = wcslen(str); + + /* + Since we only care about equality, return early if the strings + aren't the same length + */ + if (str_len != (file_name_len / sizeof(WCHAR))) + return -1; + + return _wcsnicmp(str, file_name, str_len); +} + + +void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, + uv_fs_event_t* handle) { + FILE_NOTIFY_INFORMATION* file_info; + int err, sizew, size; + char* filename = NULL; + WCHAR* filenamew = NULL; + WCHAR* long_filenamew = NULL; + DWORD offset = 0; + + assert(req->type == UV_FS_EVENT_REQ); + assert(handle->req_pending); + handle->req_pending = 0; + + /* Don't report any callbacks if: + * - We're closing, just push the handle onto the endgame queue + * - We are not active, just ignore the callback + */ + if (!uv__is_active(handle)) { + if (handle->flags & UV__HANDLE_CLOSING) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + return; + } + + file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset); + + if (REQ_SUCCESS(req)) { + if (req->u.io.overlapped.InternalHigh > 0) { + do { + file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset); + assert(!filename); + assert(!filenamew); + assert(!long_filenamew); + + /* + * Fire the event only if we were asked to watch a directory, + * or if the filename filter matches. + */ + if (handle->dirw || + file_info_cmp(handle->filew, + file_info->FileName, + file_info->FileNameLength) == 0 || + file_info_cmp(handle->short_filew, + file_info->FileName, + file_info->FileNameLength) == 0) { + + if (handle->dirw) { + /* + * We attempt to resolve the long form of the file name explicitly. + * We only do this for file names that might still exist on disk. + * If this fails, we use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. + */ + if (file_info->Action != FILE_ACTION_REMOVED && + file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) { + /* Construct a full path to the file. */ + size = wcslen(handle->dirw) + + file_info->FileNameLength / sizeof(WCHAR) + 2; + + filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR)); + if (!filenamew) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + _snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw, + file_info->FileNameLength / (DWORD)sizeof(WCHAR), + file_info->FileName); + + filenamew[size - 1] = L'\0'; + + /* Convert to long name. */ + size = GetLongPathNameW(filenamew, NULL, 0); + + if (size) { + long_filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR)); + if (!long_filenamew) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + size = GetLongPathNameW(filenamew, long_filenamew, size); + if (size) { + long_filenamew[size] = '\0'; + } else { + uv__free(long_filenamew); + long_filenamew = NULL; + } + } + + uv__free(filenamew); + + if (long_filenamew) { + /* Get the file name out of the long path. */ + uv_relative_path(long_filenamew, + handle->dirw, + &filenamew); + uv__free(long_filenamew); + long_filenamew = filenamew; + sizew = -1; + } else { + /* We couldn't get the long filename, use the one reported. */ + filenamew = file_info->FileName; + sizew = file_info->FileNameLength / sizeof(WCHAR); + } + } else { + /* + * Removed or renamed events cannot be resolved to the long form. + * We therefore use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. + */ + filenamew = file_info->FileName; + sizew = file_info->FileNameLength / sizeof(WCHAR); + } + } else { + /* We already have the long name of the file, so just use it. */ + filenamew = handle->filew; + sizew = -1; + } + + /* Convert the filename to utf8. */ + uv__convert_utf16_to_utf8(filenamew, sizew, &filename); + + switch (file_info->Action) { + case FILE_ACTION_ADDED: + case FILE_ACTION_REMOVED: + case FILE_ACTION_RENAMED_OLD_NAME: + case FILE_ACTION_RENAMED_NEW_NAME: + handle->cb(handle, filename, UV_RENAME, 0); + break; + + case FILE_ACTION_MODIFIED: + handle->cb(handle, filename, UV_CHANGE, 0); + break; + } + + uv__free(filename); + filename = NULL; + uv__free(long_filenamew); + long_filenamew = NULL; + filenamew = NULL; + } + + offset = file_info->NextEntryOffset; + } while (offset && !(handle->flags & UV__HANDLE_CLOSING)); + } else { + handle->cb(handle, NULL, UV_CHANGE, 0); + } + } else { + err = GET_REQ_ERROR(req); + handle->cb(handle, NULL, 0, uv_translate_sys_error(err)); + } + + if (!(handle->flags & UV__HANDLE_CLOSING)) { + uv_fs_event_queue_readdirchanges(loop, handle); + } else { + uv_want_endgame(loop, (uv_handle_t*)handle); + } +} + + +void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) { + uv_fs_event_stop(handle); + + uv__handle_closing(handle); + + if (!handle->req_pending) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } + +} + + +void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) { + if ((handle->flags & UV__HANDLE_CLOSING) && !handle->req_pending) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + if (handle->buffer) { + uv__free(handle->buffer); + handle->buffer = NULL; + } + + uv__handle_close(handle); + } +} diff --git a/src/win/fs.c b/src/win/fs.c new file mode 100644 index 0000000..6a4157b --- /dev/null +++ b/src/win/fs.c @@ -0,0 +1,2491 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "req-inl.h" +#include "handle-inl.h" + +#include + + +#define UV_FS_FREE_PATHS 0x0002 +#define UV_FS_FREE_PTR 0x0008 +#define UV_FS_CLEANEDUP 0x0010 + + +#define QUEUE_FS_TP_JOB(loop, req) \ + do { \ + uv__req_register(loop, req); \ + uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \ + } while (0) + +#define SET_REQ_RESULT(req, result_value) \ + do { \ + req->result = (result_value); \ + if (req->result == -1) { \ + req->sys_errno_ = _doserrno; \ + req->result = uv_translate_sys_error(req->sys_errno_); \ + } \ + } while (0) + +#define SET_REQ_WIN32_ERROR(req, sys_errno) \ + do { \ + req->sys_errno_ = (sys_errno); \ + req->result = uv_translate_sys_error(req->sys_errno_); \ + } while (0) + +#define SET_REQ_UV_ERROR(req, uv_errno, sys_errno) \ + do { \ + req->result = (uv_errno); \ + req->sys_errno_ = (sys_errno); \ + } while (0) + +#define VERIFY_FD(fd, req) \ + if (fd == -1) { \ + req->result = UV_EBADF; \ + req->sys_errno_ = ERROR_INVALID_HANDLE; \ + return; \ + } + +#define FILETIME_TO_UINT(filetime) \ + (*((uint64_t*) &(filetime)) - 116444736000000000ULL) + +#define FILETIME_TO_TIME_T(filetime) \ + (FILETIME_TO_UINT(filetime) / 10000000ULL) + +#define FILETIME_TO_TIME_NS(filetime, secs) \ + ((FILETIME_TO_UINT(filetime) - (secs * 10000000ULL)) * 100) + +#define FILETIME_TO_TIMESPEC(ts, filetime) \ + do { \ + (ts).tv_sec = (long) FILETIME_TO_TIME_T(filetime); \ + (ts).tv_nsec = (long) FILETIME_TO_TIME_NS(filetime, (ts).tv_sec); \ + } while(0) + +#define TIME_T_TO_FILETIME(time, filetime_ptr) \ + do { \ + uint64_t bigtime = ((uint64_t) ((time) * 10000000ULL)) + \ + 116444736000000000ULL; \ + (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \ + (filetime_ptr)->dwHighDateTime = bigtime >> 32; \ + } while(0) + +#define IS_SLASH(c) ((c) == L'\\' || (c) == L'/') +#define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \ + ((c) >= L'A' && (c) <= L'Z')) + +const WCHAR JUNCTION_PREFIX[] = L"\\??\\"; +const WCHAR JUNCTION_PREFIX_LEN = 4; + +const WCHAR LONG_PATH_PREFIX[] = L"\\\\?\\"; +const WCHAR LONG_PATH_PREFIX_LEN = 4; + +const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\"; +const WCHAR UNC_PATH_PREFIX_LEN = 8; + + +void uv_fs_init() { + _fmode = _O_BINARY; +} + + +INLINE static int fs__capture_path(uv_fs_t* req, const char* path, + const char* new_path, const int copy_path) { + char* buf; + char* pos; + ssize_t buf_sz = 0, path_len, pathw_len = 0, new_pathw_len = 0; + + /* new_path can only be set if path is also set. */ + assert(new_path == NULL || path != NULL); + + if (path != NULL) { + pathw_len = MultiByteToWideChar(CP_UTF8, + 0, + path, + -1, + NULL, + 0); + if (pathw_len == 0) { + return GetLastError(); + } + + buf_sz += pathw_len * sizeof(WCHAR); + } + + if (path != NULL && copy_path) { + path_len = 1 + strlen(path); + buf_sz += path_len; + } + + if (new_path != NULL) { + new_pathw_len = MultiByteToWideChar(CP_UTF8, + 0, + new_path, + -1, + NULL, + 0); + if (new_pathw_len == 0) { + return GetLastError(); + } + + buf_sz += new_pathw_len * sizeof(WCHAR); + } + + + if (buf_sz == 0) { + req->file.pathw = NULL; + req->fs.info.new_pathw = NULL; + req->path = NULL; + return 0; + } + + buf = (char*) uv__malloc(buf_sz); + if (buf == NULL) { + return ERROR_OUTOFMEMORY; + } + + pos = buf; + + if (path != NULL) { + DWORD r = MultiByteToWideChar(CP_UTF8, + 0, + path, + -1, + (WCHAR*) pos, + pathw_len); + assert(r == (DWORD) pathw_len); + req->file.pathw = (WCHAR*) pos; + pos += r * sizeof(WCHAR); + } else { + req->file.pathw = NULL; + } + + if (new_path != NULL) { + DWORD r = MultiByteToWideChar(CP_UTF8, + 0, + new_path, + -1, + (WCHAR*) pos, + new_pathw_len); + assert(r == (DWORD) new_pathw_len); + req->fs.info.new_pathw = (WCHAR*) pos; + pos += r * sizeof(WCHAR); + } else { + req->fs.info.new_pathw = NULL; + } + + req->path = path; + if (path != NULL && copy_path) { + memcpy(pos, path, path_len); + assert(path_len == buf_sz - (pos - buf)); + req->path = pos; + } + + req->flags |= UV_FS_FREE_PATHS; + + return 0; +} + + + +INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, + uv_fs_type fs_type, const uv_fs_cb cb) { + uv_req_init(loop, (uv_req_t*) req); + + req->type = UV_FS; + req->loop = loop; + req->flags = 0; + req->fs_type = fs_type; + req->result = 0; + req->ptr = NULL; + req->path = NULL; + req->cb = cb; +} + + +static int fs__wide_to_utf8(WCHAR* w_source_ptr, + DWORD w_source_len, + char** target_ptr, + uint64_t* target_len_ptr) { + int r; + int target_len; + char* target; + target_len = WideCharToMultiByte(CP_UTF8, + 0, + w_source_ptr, + w_source_len, + NULL, + 0, + NULL, + NULL); + + if (target_len == 0) { + return -1; + } + + if (target_len_ptr != NULL) { + *target_len_ptr = target_len; + } + + if (target_ptr == NULL) { + return 0; + } + + target = uv__malloc(target_len + 1); + if (target == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return -1; + } + + r = WideCharToMultiByte(CP_UTF8, + 0, + w_source_ptr, + w_source_len, + target, + target_len, + NULL, + NULL); + assert(r == target_len); + target[target_len] = '\0'; + *target_ptr = target; + return 0; +} + + +INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, + uint64_t* target_len_ptr) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer; + WCHAR* w_target; + DWORD w_target_len; + DWORD bytes; + + if (!DeviceIoControl(handle, + FSCTL_GET_REPARSE_POINT, + NULL, + 0, + buffer, + sizeof buffer, + &bytes, + NULL)) { + return -1; + } + + if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + /* Real symlink */ + w_target = reparse_data->SymbolicLinkReparseBuffer.PathBuffer + + (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset / + sizeof(WCHAR)); + w_target_len = + reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / + sizeof(WCHAR); + + /* Real symlinks can contain pretty much everything, but the only thing */ + /* we really care about is undoing the implicit conversion to an NT */ + /* namespaced path that CreateSymbolicLink will perform on absolute */ + /* paths. If the path is win32-namespaced then the user must have */ + /* explicitly made it so, and we better just return the unmodified */ + /* reparse data. */ + if (w_target_len >= 4 && + w_target[0] == L'\\' && + w_target[1] == L'?' && + w_target[2] == L'?' && + w_target[3] == L'\\') { + /* Starts with \??\ */ + if (w_target_len >= 6 && + ((w_target[4] >= L'A' && w_target[4] <= L'Z') || + (w_target[4] >= L'a' && w_target[4] <= L'z')) && + w_target[5] == L':' && + (w_target_len == 6 || w_target[6] == L'\\')) { + /* \??\:\ */ + w_target += 4; + w_target_len -= 4; + + } else if (w_target_len >= 8 && + (w_target[4] == L'U' || w_target[4] == L'u') && + (w_target[5] == L'N' || w_target[5] == L'n') && + (w_target[6] == L'C' || w_target[6] == L'c') && + w_target[7] == L'\\') { + /* \??\UNC\\\ - make sure the final path looks like */ + /* \\\\ */ + w_target += 6; + w_target[0] = L'\\'; + w_target_len -= 6; + } + } + + } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + /* Junction. */ + w_target = reparse_data->MountPointReparseBuffer.PathBuffer + + (reparse_data->MountPointReparseBuffer.SubstituteNameOffset / + sizeof(WCHAR)); + w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength / + sizeof(WCHAR); + + /* Only treat junctions that look like \??\:\ as symlink. */ + /* Junctions can also be used as mount points, like \??\Volume{}, */ + /* but that's confusing for programs since they wouldn't be able to */ + /* actually understand such a path when returned by uv_readlink(). */ + /* UNC paths are never valid for junctions so we don't care about them. */ + if (!(w_target_len >= 6 && + w_target[0] == L'\\' && + w_target[1] == L'?' && + w_target[2] == L'?' && + w_target[3] == L'\\' && + ((w_target[4] >= L'A' && w_target[4] <= L'Z') || + (w_target[4] >= L'a' && w_target[4] <= L'z')) && + w_target[5] == L':' && + (w_target_len == 6 || w_target[6] == L'\\'))) { + SetLastError(ERROR_SYMLINK_NOT_SUPPORTED); + return -1; + } + + /* Remove leading \??\ */ + w_target += 4; + w_target_len -= 4; + + } else { + /* Reparse tag does not indicate a symlink. */ + SetLastError(ERROR_SYMLINK_NOT_SUPPORTED); + return -1; + } + + return fs__wide_to_utf8(w_target, w_target_len, target_ptr, target_len_ptr); +} + + +void fs__open(uv_fs_t* req) { + DWORD access; + DWORD share; + DWORD disposition; + DWORD attributes = 0; + HANDLE file; + int fd, current_umask; + int flags = req->fs.info.file_flags; + + /* Obtain the active umask. umask() never fails and returns the previous */ + /* umask. */ + current_umask = umask(0); + umask(current_umask); + + /* convert flags and mode to CreateFile parameters */ + switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { + case _O_RDONLY: + access = FILE_GENERIC_READ; + attributes |= FILE_FLAG_BACKUP_SEMANTICS; + break; + case _O_WRONLY: + access = FILE_GENERIC_WRITE; + break; + case _O_RDWR: + access = FILE_GENERIC_READ | FILE_GENERIC_WRITE; + break; + default: + goto einval; + } + + if (flags & _O_APPEND) { + access &= ~FILE_WRITE_DATA; + access |= FILE_APPEND_DATA; + attributes &= ~FILE_FLAG_BACKUP_SEMANTICS; + } + + /* + * Here is where we deviate significantly from what CRT's _open() + * does. We indiscriminately use all the sharing modes, to match + * UNIX semantics. In particular, this ensures that the file can + * be deleted even whilst it's open, fixing issue #1449. + */ + share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + + switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) { + case 0: + case _O_EXCL: + disposition = OPEN_EXISTING; + break; + case _O_CREAT: + disposition = OPEN_ALWAYS; + break; + case _O_CREAT | _O_EXCL: + case _O_CREAT | _O_TRUNC | _O_EXCL: + disposition = CREATE_NEW; + break; + case _O_TRUNC: + case _O_TRUNC | _O_EXCL: + disposition = TRUNCATE_EXISTING; + break; + case _O_CREAT | _O_TRUNC: + disposition = CREATE_ALWAYS; + break; + default: + goto einval; + } + + attributes |= FILE_ATTRIBUTE_NORMAL; + if (flags & _O_CREAT) { + if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) { + attributes |= FILE_ATTRIBUTE_READONLY; + } + } + + if (flags & _O_TEMPORARY ) { + attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY; + access |= DELETE; + } + + if (flags & _O_SHORT_LIVED) { + attributes |= FILE_ATTRIBUTE_TEMPORARY; + } + + switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) { + case 0: + break; + case _O_SEQUENTIAL: + attributes |= FILE_FLAG_SEQUENTIAL_SCAN; + break; + case _O_RANDOM: + attributes |= FILE_FLAG_RANDOM_ACCESS; + break; + default: + goto einval; + } + + /* Setting this flag makes it possible to open a directory. */ + attributes |= FILE_FLAG_BACKUP_SEMANTICS; + + file = CreateFileW(req->file.pathw, + access, + share, + NULL, + disposition, + attributes, + NULL); + if (file == INVALID_HANDLE_VALUE) { + DWORD error = GetLastError(); + if (error == ERROR_FILE_EXISTS && (flags & _O_CREAT) && + !(flags & _O_EXCL)) { + /* Special case: when ERROR_FILE_EXISTS happens and O_CREAT was */ + /* specified, it means the path referred to a directory. */ + SET_REQ_UV_ERROR(req, UV_EISDIR, error); + } else { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } + return; + } + + fd = _open_osfhandle((intptr_t) file, flags); + if (fd < 0) { + /* The only known failure mode for _open_osfhandle() is EMFILE, in which + * case GetLastError() will return zero. However we'll try to handle other + * errors as well, should they ever occur. + */ + if (errno == EMFILE) + SET_REQ_UV_ERROR(req, UV_EMFILE, ERROR_TOO_MANY_OPEN_FILES); + else if (GetLastError() != ERROR_SUCCESS) + SET_REQ_WIN32_ERROR(req, GetLastError()); + else + SET_REQ_WIN32_ERROR(req, UV_UNKNOWN); + CloseHandle(file); + return; + } + + SET_REQ_RESULT(req, fd); + return; + + einval: + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER); +} + +void fs__close(uv_fs_t* req) { + int fd = req->file.fd; + int result; + + VERIFY_FD(fd, req); + + if (fd > 2) + result = _close(fd); + else + result = 0; + + /* _close doesn't set _doserrno on failure, but it does always set errno + * to EBADF on failure. + */ + if (result == -1) { + assert(errno == EBADF); + SET_REQ_UV_ERROR(req, UV_EBADF, ERROR_INVALID_HANDLE); + } else { + req->result = 0; + } +} + + +void fs__read(uv_fs_t* req) { + int fd = req->file.fd; + int64_t offset = req->fs.info.offset; + HANDLE handle; + OVERLAPPED overlapped, *overlapped_ptr; + LARGE_INTEGER offset_; + DWORD bytes; + DWORD error; + int result; + unsigned int index; + + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); + return; + } + + if (offset != -1) { + memset(&overlapped, 0, sizeof overlapped); + overlapped_ptr = &overlapped; + } else { + overlapped_ptr = NULL; + } + + index = 0; + bytes = 0; + do { + DWORD incremental_bytes; + + if (offset != -1) { + offset_.QuadPart = offset + bytes; + overlapped.Offset = offset_.LowPart; + overlapped.OffsetHigh = offset_.HighPart; + } + + result = ReadFile(handle, + req->fs.info.bufs[index].base, + req->fs.info.bufs[index].len, + &incremental_bytes, + overlapped_ptr); + bytes += incremental_bytes; + ++index; + } while (result && index < req->fs.info.nbufs); + + if (result || bytes > 0) { + SET_REQ_RESULT(req, bytes); + } else { + error = GetLastError(); + if (error == ERROR_HANDLE_EOF) { + SET_REQ_RESULT(req, bytes); + } else { + SET_REQ_WIN32_ERROR(req, error); + } + } +} + + +void fs__write(uv_fs_t* req) { + int fd = req->file.fd; + int64_t offset = req->fs.info.offset; + HANDLE handle; + OVERLAPPED overlapped, *overlapped_ptr; + LARGE_INTEGER offset_; + DWORD bytes; + int result; + unsigned int index; + + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); + return; + } + + if (offset != -1) { + memset(&overlapped, 0, sizeof overlapped); + overlapped_ptr = &overlapped; + } else { + overlapped_ptr = NULL; + } + + index = 0; + bytes = 0; + do { + DWORD incremental_bytes; + + if (offset != -1) { + offset_.QuadPart = offset + bytes; + overlapped.Offset = offset_.LowPart; + overlapped.OffsetHigh = offset_.HighPart; + } + + result = WriteFile(handle, + req->fs.info.bufs[index].base, + req->fs.info.bufs[index].len, + &incremental_bytes, + overlapped_ptr); + bytes += incremental_bytes; + ++index; + } while (result && index < req->fs.info.nbufs); + + if (result || bytes > 0) { + SET_REQ_RESULT(req, bytes); + } else { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } +} + + +void fs__rmdir(uv_fs_t* req) { + int result = _wrmdir(req->file.pathw); + SET_REQ_RESULT(req, result); +} + + +void fs__unlink(uv_fs_t* req) { + const WCHAR* pathw = req->file.pathw; + HANDLE handle; + BY_HANDLE_FILE_INFORMATION info; + FILE_DISPOSITION_INFORMATION disposition; + IO_STATUS_BLOCK iosb; + NTSTATUS status; + + handle = CreateFileW(pathw, + FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (!GetFileInformationByHandle(handle, &info)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); + return; + } + + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + /* Do not allow deletion of directories, unless it is a symlink. When */ + /* the path refers to a non-symlink directory, report EPERM as mandated */ + /* by POSIX.1. */ + + /* Check if it is a reparse point. If it's not, it's a normal directory. */ + if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { + SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED); + CloseHandle(handle); + return; + } + + /* Read the reparse point and check if it is a valid symlink. */ + /* If not, don't unlink. */ + if (fs__readlink_handle(handle, NULL, NULL) < 0) { + DWORD error = GetLastError(); + if (error == ERROR_SYMLINK_NOT_SUPPORTED) + error = ERROR_ACCESS_DENIED; + SET_REQ_WIN32_ERROR(req, error); + CloseHandle(handle); + return; + } + } + + if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + /* Remove read-only attribute */ + FILE_BASIC_INFORMATION basic = { 0 }; + + basic.FileAttributes = info.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY); + + status = pNtSetInformationFile(handle, + &iosb, + &basic, + sizeof basic, + FileBasicInformation); + if (!NT_SUCCESS(status)) { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + CloseHandle(handle); + return; + } + } + + /* Try to set the delete flag. */ + disposition.DeleteFile = TRUE; + status = pNtSetInformationFile(handle, + &iosb, + &disposition, + sizeof disposition, + FileDispositionInformation); + if (NT_SUCCESS(status)) { + SET_REQ_SUCCESS(req); + } else { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + } + + CloseHandle(handle); +} + + +void fs__mkdir(uv_fs_t* req) { + /* TODO: use req->mode. */ + int result = _wmkdir(req->file.pathw); + SET_REQ_RESULT(req, result); +} + + +/* OpenBSD original: lib/libc/stdio/mktemp.c */ +void fs__mkdtemp(uv_fs_t* req) { + static const WCHAR *tempchars = + L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + static const size_t num_chars = 62; + static const size_t num_x = 6; + WCHAR *cp, *ep; + unsigned int tries, i; + size_t len; + HCRYPTPROV h_crypt_prov; + uint64_t v; + BOOL released; + + len = wcslen(req->file.pathw); + ep = req->file.pathw + len; + if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) { + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER); + return; + } + + if (!CryptAcquireContext(&h_crypt_prov, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + tries = TMP_MAX; + do { + if (!CryptGenRandom(h_crypt_prov, sizeof(v), (BYTE*) &v)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + break; + } + + cp = ep - num_x; + for (i = 0; i < num_x; i++) { + *cp++ = tempchars[v % num_chars]; + v /= num_chars; + } + + if (_wmkdir(req->file.pathw) == 0) { + len = strlen(req->path); + wcstombs((char*) req->path + len - num_x, ep - num_x, num_x); + SET_REQ_RESULT(req, 0); + break; + } else if (errno != EEXIST) { + SET_REQ_RESULT(req, -1); + break; + } + } while (--tries); + + released = CryptReleaseContext(h_crypt_prov, 0); + assert(released); + if (tries == 0) { + SET_REQ_RESULT(req, -1); + } +} + + +void fs__scandir(uv_fs_t* req) { + static const size_t dirents_initial_size = 32; + + HANDLE dir_handle = INVALID_HANDLE_VALUE; + + uv__dirent_t** dirents = NULL; + size_t dirents_size = 0; + size_t dirents_used = 0; + + IO_STATUS_BLOCK iosb; + NTSTATUS status; + + /* Buffer to hold directory entries returned by NtQueryDirectoryFile. + * It's important that this buffer can hold at least one entry, regardless + * of the length of the file names present in the enumerated directory. + * A file name is at most 256 WCHARs long. + * According to MSDN, the buffer must be aligned at an 8-byte boundary. + */ +#if _MSC_VER + __declspec(align(8)) char buffer[8192]; +#else + __attribute__ ((aligned (8))) char buffer[8192]; +#endif + + STATIC_ASSERT(sizeof buffer >= + sizeof(FILE_DIRECTORY_INFORMATION) + 256 * sizeof(WCHAR)); + + /* Open the directory. */ + dir_handle = + CreateFileW(req->file.pathw, + FILE_LIST_DIRECTORY | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (dir_handle == INVALID_HANDLE_VALUE) + goto win32_error; + + /* Read the first chunk. */ + status = pNtQueryDirectoryFile(dir_handle, + NULL, + NULL, + NULL, + &iosb, + &buffer, + sizeof buffer, + FileDirectoryInformation, + FALSE, + NULL, + TRUE); + + /* If the handle is not a directory, we'll get STATUS_INVALID_PARAMETER. + * This should be reported back as UV_ENOTDIR. + */ + if (status == STATUS_INVALID_PARAMETER) + goto not_a_directory_error; + + while (NT_SUCCESS(status)) { + char* position = buffer; + size_t next_entry_offset = 0; + + do { + FILE_DIRECTORY_INFORMATION* info; + uv__dirent_t* dirent; + + size_t wchar_len; + size_t utf8_len; + + /* Obtain a pointer to the current directory entry. */ + position += next_entry_offset; + info = (FILE_DIRECTORY_INFORMATION*) position; + + /* Fetch the offset to the next directory entry. */ + next_entry_offset = info->NextEntryOffset; + + /* Compute the length of the filename in WCHARs. */ + wchar_len = info->FileNameLength / sizeof info->FileName[0]; + + /* Skip over '.' and '..' entries. It has been reported that + * the SharePoint driver includes the terminating zero byte in + * the filename length. Strip those first. + */ + while (wchar_len > 0 && info->FileName[wchar_len - 1] == L'\0') + wchar_len -= 1; + + if (wchar_len == 0) + continue; + if (wchar_len == 1 && info->FileName[0] == L'.') + continue; + if (wchar_len == 2 && info->FileName[0] == L'.' && + info->FileName[1] == L'.') + continue; + + /* Compute the space required to store the filename as UTF-8. */ + utf8_len = WideCharToMultiByte( + CP_UTF8, 0, &info->FileName[0], wchar_len, NULL, 0, NULL, NULL); + if (utf8_len == 0) + goto win32_error; + + /* Resize the dirent array if needed. */ + if (dirents_used >= dirents_size) { + size_t new_dirents_size = + dirents_size == 0 ? dirents_initial_size : dirents_size << 1; + uv__dirent_t** new_dirents = + uv__realloc(dirents, new_dirents_size * sizeof *dirents); + + if (new_dirents == NULL) + goto out_of_memory_error; + + dirents_size = new_dirents_size; + dirents = new_dirents; + } + + /* Allocate space for the uv dirent structure. The dirent structure + * includes room for the first character of the filename, but `utf8_len` + * doesn't count the NULL terminator at this point. + */ + dirent = uv__malloc(sizeof *dirent + utf8_len); + if (dirent == NULL) + goto out_of_memory_error; + + dirents[dirents_used++] = dirent; + + /* Convert file name to UTF-8. */ + if (WideCharToMultiByte(CP_UTF8, + 0, + &info->FileName[0], + wchar_len, + &dirent->d_name[0], + utf8_len, + NULL, + NULL) == 0) + goto win32_error; + + /* Add a null terminator to the filename. */ + dirent->d_name[utf8_len] = '\0'; + + /* Fill out the type field. */ + if (info->FileAttributes & FILE_ATTRIBUTE_DEVICE) + dirent->d_type = UV__DT_CHAR; + else if (info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + dirent->d_type = UV__DT_LINK; + else if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + dirent->d_type = UV__DT_DIR; + else + dirent->d_type = UV__DT_FILE; + } while (next_entry_offset != 0); + + /* Read the next chunk. */ + status = pNtQueryDirectoryFile(dir_handle, + NULL, + NULL, + NULL, + &iosb, + &buffer, + sizeof buffer, + FileDirectoryInformation, + FALSE, + NULL, + FALSE); + + /* After the first pNtQueryDirectoryFile call, the function may return + * STATUS_SUCCESS even if the buffer was too small to hold at least one + * directory entry. + */ + if (status == STATUS_SUCCESS && iosb.Information == 0) + status = STATUS_BUFFER_OVERFLOW; + } + + if (status != STATUS_NO_MORE_FILES) + goto nt_error; + + CloseHandle(dir_handle); + + /* Store the result in the request object. */ + req->ptr = dirents; + if (dirents != NULL) + req->flags |= UV_FS_FREE_PTR; + + SET_REQ_RESULT(req, dirents_used); + + /* `nbufs` will be used as index by uv_fs_scandir_next. */ + req->fs.info.nbufs = 0; + + return; + +nt_error: + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + goto cleanup; + +win32_error: + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto cleanup; + +not_a_directory_error: + SET_REQ_UV_ERROR(req, UV_ENOTDIR, ERROR_DIRECTORY); + goto cleanup; + +out_of_memory_error: + SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); + goto cleanup; + +cleanup: + if (dir_handle != INVALID_HANDLE_VALUE) + CloseHandle(dir_handle); + while (dirents_used > 0) + uv__free(dirents[--dirents_used]); + if (dirents != NULL) + uv__free(dirents); +} + + +INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) { + FILE_ALL_INFORMATION file_info; + FILE_FS_VOLUME_INFORMATION volume_info; + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + + nt_status = pNtQueryInformationFile(handle, + &io_status, + &file_info, + sizeof file_info, + FileAllInformation); + + /* Buffer overflow (a warning status code) is expected here. */ + if (NT_ERROR(nt_status)) { + SetLastError(pRtlNtStatusToDosError(nt_status)); + return -1; + } + + nt_status = pNtQueryVolumeInformationFile(handle, + &io_status, + &volume_info, + sizeof volume_info, + FileFsVolumeInformation); + + /* Buffer overflow (a warning status code) is expected here. */ + if (io_status.Status == STATUS_NOT_IMPLEMENTED) { + statbuf->st_dev = 0; + } else if (NT_ERROR(nt_status)) { + SetLastError(pRtlNtStatusToDosError(nt_status)); + return -1; + } else { + statbuf->st_dev = volume_info.VolumeSerialNumber; + } + + /* Todo: st_mode should probably always be 0666 for everyone. We might also + * want to report 0777 if the file is a .exe or a directory. + * + * Currently it's based on whether the 'readonly' attribute is set, which + * makes little sense because the semantics are so different: the 'read-only' + * flag is just a way for a user to protect against accidental deletion, and + * serves no security purpose. Windows uses ACLs for that. + * + * Also people now use uv_fs_chmod() to take away the writable bit for good + * reasons. Windows however just makes the file read-only, which makes it + * impossible to delete the file afterwards, since read-only files can't be + * deleted. + * + * IOW it's all just a clusterfuck and we should think of something that + * makes slightly more sense. + * + * And uv_fs_chmod should probably just fail on windows or be a total no-op. + * There's nothing sensible it can do anyway. + */ + statbuf->st_mode = 0; + + if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + /* + * It is possible for a file to have FILE_ATTRIBUTE_REPARSE_POINT but not have + * any link data. In that case DeviceIoControl() in fs__readlink_handle() sets + * the last error to ERROR_NOT_A_REPARSE_POINT. Then the stat result mode + * calculated below will indicate a normal directory or file, as if + * FILE_ATTRIBUTE_REPARSE_POINT was not present. + */ + if (fs__readlink_handle(handle, NULL, &statbuf->st_size) == 0) { + statbuf->st_mode |= S_IFLNK; + } else if (GetLastError() != ERROR_NOT_A_REPARSE_POINT) { + return -1; + } + } + + if (statbuf->st_mode == 0) { + if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + statbuf->st_mode |= _S_IFDIR; + statbuf->st_size = 0; + } else { + statbuf->st_mode |= _S_IFREG; + statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart; + } + } + + if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY) + statbuf->st_mode |= _S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6); + else + statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) | + ((_S_IREAD | _S_IWRITE) >> 6); + + FILETIME_TO_TIMESPEC(statbuf->st_atim, file_info.BasicInformation.LastAccessTime); + FILETIME_TO_TIMESPEC(statbuf->st_ctim, file_info.BasicInformation.ChangeTime); + FILETIME_TO_TIMESPEC(statbuf->st_mtim, file_info.BasicInformation.LastWriteTime); + FILETIME_TO_TIMESPEC(statbuf->st_birthtim, file_info.BasicInformation.CreationTime); + + statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart; + + /* st_blocks contains the on-disk allocation size in 512-byte units. */ + statbuf->st_blocks = + file_info.StandardInformation.AllocationSize.QuadPart >> 9ULL; + + statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks; + + /* The st_blksize is supposed to be the 'optimal' number of bytes for reading + * and writing to the disk. That is, for any definition of 'optimal' - it's + * supposed to at least avoid read-update-write behavior when writing to the + * disk. + * + * However nobody knows this and even fewer people actually use this value, + * and in order to fill it out we'd have to make another syscall to query the + * volume for FILE_FS_SECTOR_SIZE_INFORMATION. + * + * Therefore we'll just report a sensible value that's quite commonly okay + * on modern hardware. + */ + statbuf->st_blksize = 2048; + + /* Todo: set st_flags to something meaningful. Also provide a wrapper for + * chattr(2). + */ + statbuf->st_flags = 0; + + /* Windows has nothing sensible to say about these values, so they'll just + * remain empty. + */ + statbuf->st_gid = 0; + statbuf->st_uid = 0; + statbuf->st_rdev = 0; + statbuf->st_gen = 0; + + return 0; +} + + +INLINE static void fs__stat_prepare_path(WCHAR* pathw) { + size_t len = wcslen(pathw); + + /* TODO: ignore namespaced paths. */ + if (len > 1 && pathw[len - 2] != L':' && + (pathw[len - 1] == L'\\' || pathw[len - 1] == L'/')) { + pathw[len - 1] = '\0'; + } +} + + +INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) { + HANDLE handle; + DWORD flags; + + flags = FILE_FLAG_BACKUP_SEMANTICS; + if (do_lstat) { + flags |= FILE_FLAG_OPEN_REPARSE_POINT; + } + + handle = CreateFileW(req->file.pathw, + FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + flags, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (fs__stat_handle(handle, &req->statbuf) != 0) { + DWORD error = GetLastError(); + if (do_lstat && error == ERROR_SYMLINK_NOT_SUPPORTED) { + /* We opened a reparse point but it was not a symlink. Try again. */ + fs__stat_impl(req, 0); + + } else { + /* Stat failed. */ + SET_REQ_WIN32_ERROR(req, GetLastError()); + } + + CloseHandle(handle); + return; + } + + req->ptr = &req->statbuf; + req->result = 0; + CloseHandle(handle); +} + + +static void fs__stat(uv_fs_t* req) { + fs__stat_prepare_path(req->file.pathw); + fs__stat_impl(req, 0); +} + + +static void fs__lstat(uv_fs_t* req) { + fs__stat_prepare_path(req->file.pathw); + fs__stat_impl(req, 1); +} + + +static void fs__fstat(uv_fs_t* req) { + int fd = req->file.fd; + HANDLE handle; + + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); + return; + } + + if (fs__stat_handle(handle, &req->statbuf) != 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + req->ptr = &req->statbuf; + req->result = 0; +} + + +static void fs__rename(uv_fs_t* req) { + if (!MoveFileExW(req->file.pathw, req->fs.info.new_pathw, MOVEFILE_REPLACE_EXISTING)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + SET_REQ_RESULT(req, 0); +} + + +INLINE static void fs__sync_impl(uv_fs_t* req) { + int fd = req->file.fd; + int result; + + VERIFY_FD(fd, req); + + result = FlushFileBuffers(uv__get_osfhandle(fd)) ? 0 : -1; + if (result == -1) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } else { + SET_REQ_RESULT(req, result); + } +} + + +static void fs__fsync(uv_fs_t* req) { + fs__sync_impl(req); +} + + +static void fs__fdatasync(uv_fs_t* req) { + fs__sync_impl(req); +} + + +static void fs__ftruncate(uv_fs_t* req) { + int fd = req->file.fd; + HANDLE handle; + NTSTATUS status; + IO_STATUS_BLOCK io_status; + FILE_END_OF_FILE_INFORMATION eof_info; + + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + + eof_info.EndOfFile.QuadPart = req->fs.info.offset; + + status = pNtSetInformationFile(handle, + &io_status, + &eof_info, + sizeof eof_info, + FileEndOfFileInformation); + + if (NT_SUCCESS(status)) { + SET_REQ_RESULT(req, 0); + } else { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + } +} + + +static void fs__sendfile(uv_fs_t* req) { + int fd_in = req->file.fd, fd_out = req->fs.info.fd_out; + size_t length = req->fs.info.bufsml[0].len; + int64_t offset = req->fs.info.offset; + const size_t max_buf_size = 65536; + size_t buf_size = length < max_buf_size ? length : max_buf_size; + int n, result = 0; + int64_t result_offset = 0; + char* buf = (char*) uv__malloc(buf_size); + if (!buf) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (offset != -1) { + result_offset = _lseeki64(fd_in, offset, SEEK_SET); + } + + if (result_offset == -1) { + result = -1; + } else { + while (length > 0) { + n = _read(fd_in, buf, length < buf_size ? length : buf_size); + if (n == 0) { + break; + } else if (n == -1) { + result = -1; + break; + } + + length -= n; + + n = _write(fd_out, buf, n); + if (n == -1) { + result = -1; + break; + } + + result += n; + } + } + + uv__free(buf); + + SET_REQ_RESULT(req, result); +} + + +static void fs__access(uv_fs_t* req) { + DWORD attr = GetFileAttributesW(req->file.pathw); + + if (attr == INVALID_FILE_ATTRIBUTES) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + /* + * Access is possible if + * - write access wasn't requested, + * - or the file isn't read-only, + * - or it's a directory. + * (Directories cannot be read-only on Windows.) + */ + if (!(req->flags & W_OK) || + !(attr & FILE_ATTRIBUTE_READONLY) || + (attr & FILE_ATTRIBUTE_DIRECTORY)) { + SET_REQ_RESULT(req, 0); + } else { + SET_REQ_WIN32_ERROR(req, UV_EPERM); + } + +} + + +static void fs__chmod(uv_fs_t* req) { + int result = _wchmod(req->file.pathw, req->fs.info.mode); + SET_REQ_RESULT(req, result); +} + + +static void fs__fchmod(uv_fs_t* req) { + int fd = req->file.fd; + HANDLE handle; + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_BASIC_INFORMATION file_info; + + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + + nt_status = pNtQueryInformationFile(handle, + &io_status, + &file_info, + sizeof file_info, + FileBasicInformation); + + if (!NT_SUCCESS(nt_status)) { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); + return; + } + + if (req->fs.info.mode & _S_IWRITE) { + file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; + } else { + file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; + } + + nt_status = pNtSetInformationFile(handle, + &io_status, + &file_info, + sizeof file_info, + FileBasicInformation); + + if (!NT_SUCCESS(nt_status)) { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); + return; + } + + SET_REQ_SUCCESS(req); +} + + +INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) { + FILETIME filetime_a, filetime_m; + + TIME_T_TO_FILETIME(atime, &filetime_a); + TIME_T_TO_FILETIME(mtime, &filetime_m); + + if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) { + return -1; + } + + return 0; +} + + +static void fs__utime(uv_fs_t* req) { + HANDLE handle; + + handle = CreateFileW(req->file.pathw, + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); + return; + } + + CloseHandle(handle); + + req->result = 0; +} + + +static void fs__futime(uv_fs_t* req) { + int fd = req->file.fd; + HANDLE handle; + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); + return; + } + + if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + req->result = 0; +} + + +static void fs__link(uv_fs_t* req) { + DWORD r = CreateHardLinkW(req->fs.info.new_pathw, req->file.pathw, NULL); + if (r == 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } else { + req->result = 0; + } +} + + +static void fs__create_junction(uv_fs_t* req, const WCHAR* path, + const WCHAR* new_path) { + HANDLE handle = INVALID_HANDLE_VALUE; + REPARSE_DATA_BUFFER *buffer = NULL; + int created = 0; + int target_len; + int is_absolute, is_long_path; + int needed_buf_size, used_buf_size, used_data_size, path_buf_len; + int start, len, i; + int add_slash; + DWORD bytes; + WCHAR* path_buf; + + target_len = wcslen(path); + is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0; + + if (is_long_path) { + is_absolute = 1; + } else { + is_absolute = target_len >= 3 && IS_LETTER(path[0]) && + path[1] == L':' && IS_SLASH(path[2]); + } + + if (!is_absolute) { + /* Not supporting relative paths */ + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_NOT_SUPPORTED); + return; + } + + /* Do a pessimistic calculation of the required buffer size */ + needed_buf_size = + FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) + + JUNCTION_PREFIX_LEN * sizeof(WCHAR) + + 2 * (target_len + 2) * sizeof(WCHAR); + + /* Allocate the buffer */ + buffer = (REPARSE_DATA_BUFFER*)uv__malloc(needed_buf_size); + if (!buffer) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + /* Grab a pointer to the part of the buffer where filenames go */ + path_buf = (WCHAR*)&(buffer->MountPointReparseBuffer.PathBuffer); + path_buf_len = 0; + + /* Copy the substitute (internal) target path */ + start = path_buf_len; + + wcsncpy((WCHAR*)&path_buf[path_buf_len], JUNCTION_PREFIX, + JUNCTION_PREFIX_LEN); + path_buf_len += JUNCTION_PREFIX_LEN; + + add_slash = 0; + for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) { + if (IS_SLASH(path[i])) { + add_slash = 1; + continue; + } + + if (add_slash) { + path_buf[path_buf_len++] = L'\\'; + add_slash = 0; + } + + path_buf[path_buf_len++] = path[i]; + } + path_buf[path_buf_len++] = L'\\'; + len = path_buf_len - start; + + /* Set the info about the substitute name */ + buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(WCHAR); + buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR); + + /* Insert null terminator */ + path_buf[path_buf_len++] = L'\0'; + + /* Copy the print name of the target path */ + start = path_buf_len; + add_slash = 0; + for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) { + if (IS_SLASH(path[i])) { + add_slash = 1; + continue; + } + + if (add_slash) { + path_buf[path_buf_len++] = L'\\'; + add_slash = 0; + } + + path_buf[path_buf_len++] = path[i]; + } + len = path_buf_len - start; + if (len == 2) { + path_buf[path_buf_len++] = L'\\'; + len++; + } + + /* Set the info about the print name */ + buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(WCHAR); + buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(WCHAR); + + /* Insert another null terminator */ + path_buf[path_buf_len++] = L'\0'; + + /* Calculate how much buffer space was actually used */ + used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) + + path_buf_len * sizeof(WCHAR); + used_data_size = used_buf_size - + FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer); + + /* Put general info in the data buffer */ + buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + buffer->ReparseDataLength = used_data_size; + buffer->Reserved = 0; + + /* Create a new directory */ + if (!CreateDirectoryW(new_path, NULL)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + created = 1; + + /* Open the directory */ + handle = CreateFileW(new_path, + GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + + /* Create the actual reparse point */ + if (!DeviceIoControl(handle, + FSCTL_SET_REPARSE_POINT, + buffer, + used_buf_size, + NULL, + 0, + &bytes, + NULL)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + + /* Clean up */ + CloseHandle(handle); + uv__free(buffer); + + SET_REQ_RESULT(req, 0); + return; + +error: + uv__free(buffer); + + if (handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle); + } + + if (created) { + RemoveDirectoryW(new_path); + } +} + + +static void fs__symlink(uv_fs_t* req) { + WCHAR* pathw = req->file.pathw; + WCHAR* new_pathw = req->fs.info.new_pathw; + int flags = req->fs.info.file_flags; + int result; + + + if (flags & UV_FS_SYMLINK_JUNCTION) { + fs__create_junction(req, pathw, new_pathw); + } else if (pCreateSymbolicLinkW) { + result = pCreateSymbolicLinkW(new_pathw, + pathw, + flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1; + if (result == -1) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } else { + SET_REQ_RESULT(req, result); + } + } else { + SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); + } +} + + +static void fs__readlink(uv_fs_t* req) { + HANDLE handle; + + handle = CreateFileW(req->file.pathw, + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); + return; + } + + req->flags |= UV_FS_FREE_PTR; + SET_REQ_RESULT(req, 0); + + CloseHandle(handle); +} + + +static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { + int r; + DWORD w_realpath_len; + WCHAR* w_realpath_ptr = NULL; + WCHAR* w_realpath_buf; + + w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); + if (w_realpath_len == 0) { + return -1; + } + + w_realpath_buf = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR)); + if (w_realpath_buf == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return -1; + } + w_realpath_ptr = w_realpath_buf; + + if (pGetFinalPathNameByHandleW(handle, + w_realpath_ptr, + w_realpath_len, + VOLUME_NAME_DOS) == 0) { + uv__free(w_realpath_buf); + SetLastError(ERROR_INVALID_HANDLE); + return -1; + } + + /* convert UNC path to long path */ + if (wcsncmp(w_realpath_ptr, + UNC_PATH_PREFIX, + UNC_PATH_PREFIX_LEN) == 0) { + w_realpath_ptr += 6; + *w_realpath_ptr = L'\\'; + w_realpath_len -= 6; + } else if (wcsncmp(w_realpath_ptr, + LONG_PATH_PREFIX, + LONG_PATH_PREFIX_LEN) == 0) { + w_realpath_ptr += 4; + w_realpath_len -= 4; + } else { + uv__free(w_realpath_buf); + SetLastError(ERROR_INVALID_HANDLE); + return -1; + } + + r = fs__wide_to_utf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL); + uv__free(w_realpath_buf); + return r; +} + +static void fs__realpath(uv_fs_t* req) { + HANDLE handle; + + if (!pGetFinalPathNameByHandleW) { + SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); + return; + } + + handle = CreateFileW(req->file.pathw, + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (fs__realpath_handle(handle, (char**) &req->ptr) == -1) { + CloseHandle(handle); + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + CloseHandle(handle); + req->flags |= UV_FS_FREE_PTR; + SET_REQ_RESULT(req, 0); +} + + +static void fs__chown(uv_fs_t* req) { + req->result = 0; +} + + +static void fs__fchown(uv_fs_t* req) { + req->result = 0; +} + + +static void uv__fs_work(struct uv__work* w) { + uv_fs_t* req; + + req = container_of(w, uv_fs_t, work_req); + assert(req->type == UV_FS); + +#define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break; + switch (req->fs_type) { + XX(OPEN, open) + XX(CLOSE, close) + XX(READ, read) + XX(WRITE, write) + XX(SENDFILE, sendfile) + XX(STAT, stat) + XX(LSTAT, lstat) + XX(FSTAT, fstat) + XX(FTRUNCATE, ftruncate) + XX(UTIME, utime) + XX(FUTIME, futime) + XX(ACCESS, access) + XX(CHMOD, chmod) + XX(FCHMOD, fchmod) + XX(FSYNC, fsync) + XX(FDATASYNC, fdatasync) + XX(UNLINK, unlink) + XX(RMDIR, rmdir) + XX(MKDIR, mkdir) + XX(MKDTEMP, mkdtemp) + XX(RENAME, rename) + XX(SCANDIR, scandir) + XX(LINK, link) + XX(SYMLINK, symlink) + XX(READLINK, readlink) + XX(REALPATH, realpath) + XX(CHOWN, chown) + XX(FCHOWN, fchown); + default: + assert(!"bad uv_fs_type"); + } +} + + +static void uv__fs_done(struct uv__work* w, int status) { + uv_fs_t* req; + + req = container_of(w, uv_fs_t, work_req); + uv__req_unregister(req->loop, req); + + if (status == UV_ECANCELED) { + assert(req->result == 0); + req->result = UV_ECANCELED; + } + + req->cb(req); +} + + +void uv_fs_req_cleanup(uv_fs_t* req) { + if (req->flags & UV_FS_CLEANEDUP) + return; + + if (req->flags & UV_FS_FREE_PATHS) + uv__free(req->file.pathw); + + if (req->flags & UV_FS_FREE_PTR) { + if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL) + uv__fs_scandir_cleanup(req); + else + uv__free(req->ptr); + } + + req->path = NULL; + req->file.pathw = NULL; + req->fs.info.new_pathw = NULL; + req->ptr = NULL; + + req->flags |= UV_FS_CLEANEDUP; +} + + +int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, + int mode, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_OPEN, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.file_flags = flags; + req->fs.info.mode = mode; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__open(req); + return req->result; + } +} + + +int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_CLOSE, cb); + req->file.fd = fd; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__close(req); + return req->result; + } +} + + +int uv_fs_read(uv_loop_t* loop, + uv_fs_t* req, + uv_file fd, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t offset, + uv_fs_cb cb) { + if (bufs == NULL || nbufs == 0) + return UV_EINVAL; + + uv_fs_req_init(loop, req, UV_FS_READ, cb); + + req->file.fd = fd; + + req->fs.info.nbufs = nbufs; + req->fs.info.bufs = req->fs.info.bufsml; + if (nbufs > ARRAY_SIZE(req->fs.info.bufsml)) + req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs)); + + if (req->fs.info.bufs == NULL) + return UV_ENOMEM; + + memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs)); + + req->fs.info.offset = offset; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__read(req); + return req->result; + } +} + + +int uv_fs_write(uv_loop_t* loop, + uv_fs_t* req, + uv_file fd, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t offset, + uv_fs_cb cb) { + if (bufs == NULL || nbufs == 0) + return UV_EINVAL; + + uv_fs_req_init(loop, req, UV_FS_WRITE, cb); + + req->file.fd = fd; + + req->fs.info.nbufs = nbufs; + req->fs.info.bufs = req->fs.info.bufsml; + if (nbufs > ARRAY_SIZE(req->fs.info.bufsml)) + req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs)); + + if (req->fs.info.bufs == NULL) + return UV_ENOMEM; + + memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs)); + + req->fs.info.offset = offset; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__write(req); + return req->result; + } +} + + +int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_UNLINK, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__unlink(req); + return req->result; + } +} + + +int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_MKDIR, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.mode = mode; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__mkdir(req); + return req->result; + } +} + + +int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_MKDTEMP, cb); + + err = fs__capture_path(req, tpl, NULL, TRUE); + if (err) + return uv_translate_sys_error(err); + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__mkdtemp(req); + return req->result; + } +} + + +int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_RMDIR, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__rmdir(req); + return req->result; + } +} + + +int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_SCANDIR, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.file_flags = flags; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__scandir(req); + return req->result; + } +} + + +int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, + const char* new_path, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_LINK, cb); + + err = fs__capture_path(req, path, new_path, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__link(req); + return req->result; + } +} + + +int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + const char* new_path, int flags, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_SYMLINK, cb); + + err = fs__capture_path(req, path, new_path, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.file_flags = flags; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__symlink(req); + return req->result; + } +} + + +int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_READLINK, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__readlink(req); + return req->result; + } +} + + +int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + if (!req || !path) { + return UV_EINVAL; + } + + uv_fs_req_init(loop, req, UV_FS_REALPATH, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__realpath(req); + return req->result; + } +} + + +int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, + uv_gid_t gid, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_CHOWN, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__chown(req); + return req->result; + } +} + + +int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid, + uv_gid_t gid, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FCHOWN, cb); + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__fchown(req); + return req->result; + } +} + + +int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_STAT, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__stat(req); + return req->result; + } +} + + +int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_LSTAT, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__lstat(req); + return req->result; + } +} + + +int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FSTAT, cb); + req->file.fd = fd; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__fstat(req); + return req->result; + } +} + + +int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, + const char* new_path, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_RENAME, cb); + + err = fs__capture_path(req, path, new_path, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__rename(req); + return req->result; + } +} + + +int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FSYNC, cb); + req->file.fd = fd; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__fsync(req); + return req->result; + } +} + + +int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FDATASYNC, cb); + req->file.fd = fd; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__fdatasync(req); + return req->result; + } +} + + +int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd, + int64_t offset, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FTRUNCATE, cb); + + req->file.fd = fd; + req->fs.info.offset = offset; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__ftruncate(req); + return req->result; + } +} + + + +int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out, + uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_SENDFILE, cb); + + req->file.fd = fd_in; + req->fs.info.fd_out = fd_out; + req->fs.info.offset = in_offset; + req->fs.info.bufsml[0].len = length; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__sendfile(req); + return req->result; + } +} + + +int uv_fs_access(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_ACCESS, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) + return uv_translate_sys_error(err); + + req->flags = flags; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } + + fs__access(req); + return req->result; +} + + +int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_CHMOD, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.mode = mode; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__chmod(req); + return req->result; + } +} + + +int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode, + uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FCHMOD, cb); + + req->file.fd = fd; + req->fs.info.mode = mode; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__fchmod(req); + return req->result; + } +} + + +int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, + double mtime, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_UTIME, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.time.atime = atime; + req->fs.time.mtime = mtime; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__utime(req); + return req->result; + } +} + + +int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime, + double mtime, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FUTIME, cb); + + req->file.fd = fd; + req->fs.time.atime = atime; + req->fs.time.mtime = mtime; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__futime(req); + return req->result; + } +} diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c new file mode 100644 index 0000000..744f8e0 --- /dev/null +++ b/src/win/getaddrinfo.c @@ -0,0 +1,385 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include + +#include "uv.h" +#include "internal.h" +#include "req-inl.h" + +/* EAI_* constants. */ +#include + + +int uv__getaddrinfo_translate_error(int sys_err) { + switch (sys_err) { + case 0: return 0; + case WSATRY_AGAIN: return UV_EAI_AGAIN; + case WSAEINVAL: return UV_EAI_BADFLAGS; + case WSANO_RECOVERY: return UV_EAI_FAIL; + case WSAEAFNOSUPPORT: return UV_EAI_FAMILY; + case WSA_NOT_ENOUGH_MEMORY: return UV_EAI_MEMORY; + case WSAHOST_NOT_FOUND: return UV_EAI_NONAME; + case WSATYPE_NOT_FOUND: return UV_EAI_SERVICE; + case WSAESOCKTNOSUPPORT: return UV_EAI_SOCKTYPE; + default: return uv_translate_sys_error(sys_err); + } +} + + +/* + * MinGW is missing this + */ +#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR) + typedef struct addrinfoW { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + WCHAR* ai_canonname; + struct sockaddr* ai_addr; + struct addrinfoW* ai_next; + } ADDRINFOW, *PADDRINFOW; + + DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node, + const WCHAR* service, + const ADDRINFOW* hints, + PADDRINFOW* result); + + DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo); +#endif + + +/* adjust size value to be multiple of 4. Use to keep pointer aligned */ +/* Do we need different versions of this for different architectures? */ +#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2) + + +static void uv__getaddrinfo_work(struct uv__work* w) { + uv_getaddrinfo_t* req; + struct addrinfoW* hints; + int err; + + req = container_of(w, uv_getaddrinfo_t, work_req); + hints = req->addrinfow; + req->addrinfow = NULL; + err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow); + req->retcode = uv__getaddrinfo_translate_error(err); +} + + +/* + * Called from uv_run when complete. Call user specified callback + * then free returned addrinfo + * Returned addrinfo strings are converted from UTF-16 to UTF-8. + * + * To minimize allocation we calculate total size required, + * and copy all structs and referenced strings into the one block. + * Each size calculation is adjusted to avoid unaligned pointers. + */ +static void uv__getaddrinfo_done(struct uv__work* w, int status) { + uv_getaddrinfo_t* req; + int addrinfo_len = 0; + int name_len = 0; + size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo)); + struct addrinfoW* addrinfow_ptr; + struct addrinfo* addrinfo_ptr; + char* alloc_ptr = NULL; + char* cur_ptr = NULL; + + req = container_of(w, uv_getaddrinfo_t, work_req); + + /* release input parameter memory */ + uv__free(req->alloc); + req->alloc = NULL; + + if (status == UV_ECANCELED) { + assert(req->retcode == 0); + req->retcode = UV_EAI_CANCELED; + goto complete; + } + + if (req->retcode == 0) { + /* convert addrinfoW to addrinfo */ + /* first calculate required length */ + addrinfow_ptr = req->addrinfow; + while (addrinfow_ptr != NULL) { + addrinfo_len += addrinfo_struct_len + + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); + if (addrinfow_ptr->ai_canonname != NULL) { + name_len = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + NULL, + 0, + NULL, + NULL); + if (name_len == 0) { + req->retcode = uv_translate_sys_error(GetLastError()); + goto complete; + } + addrinfo_len += ALIGNED_SIZE(name_len); + } + addrinfow_ptr = addrinfow_ptr->ai_next; + } + + /* allocate memory for addrinfo results */ + alloc_ptr = (char*)uv__malloc(addrinfo_len); + + /* do conversions */ + if (alloc_ptr != NULL) { + cur_ptr = alloc_ptr; + addrinfow_ptr = req->addrinfow; + + while (addrinfow_ptr != NULL) { + /* copy addrinfo struct data */ + assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len); + addrinfo_ptr = (struct addrinfo*)cur_ptr; + addrinfo_ptr->ai_family = addrinfow_ptr->ai_family; + addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype; + addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol; + addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags; + addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen; + addrinfo_ptr->ai_canonname = NULL; + addrinfo_ptr->ai_addr = NULL; + addrinfo_ptr->ai_next = NULL; + + cur_ptr += addrinfo_struct_len; + + /* copy sockaddr */ + if (addrinfo_ptr->ai_addrlen > 0) { + assert(cur_ptr + addrinfo_ptr->ai_addrlen <= + alloc_ptr + addrinfo_len); + memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen); + addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr; + cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen); + } + + /* convert canonical name to UTF-8 */ + if (addrinfow_ptr->ai_canonname != NULL) { + name_len = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + NULL, + 0, + NULL, + NULL); + assert(name_len > 0); + assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len); + name_len = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + cur_ptr, + name_len, + NULL, + NULL); + assert(name_len > 0); + addrinfo_ptr->ai_canonname = cur_ptr; + cur_ptr += ALIGNED_SIZE(name_len); + } + assert(cur_ptr <= alloc_ptr + addrinfo_len); + + /* set next ptr */ + addrinfow_ptr = addrinfow_ptr->ai_next; + if (addrinfow_ptr != NULL) { + addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr; + } + } + req->addrinfo = (struct addrinfo*)alloc_ptr; + } else { + req->retcode = UV_EAI_MEMORY; + } + } + + /* return memory to system */ + if (req->addrinfow != NULL) { + FreeAddrInfoW(req->addrinfow); + req->addrinfow = NULL; + } + +complete: + uv__req_unregister(req->loop, req); + + /* finally do callback with converted result */ + if (req->getaddrinfo_cb) + req->getaddrinfo_cb(req, req->retcode, req->addrinfo); +} + + +void uv_freeaddrinfo(struct addrinfo* ai) { + char* alloc_ptr = (char*)ai; + + /* release copied result memory */ + uv__free(alloc_ptr); +} + + +/* + * Entry point for getaddrinfo + * we convert the UTF-8 strings to UNICODE + * and save the UNICODE string pointers in the req + * We also copy hints so that caller does not need to keep memory until the + * callback. + * return 0 if a callback will be made + * return error code if validation fails + * + * To minimize allocation we calculate total size required, + * and copy all structs and referenced strings into the one block. + * Each size calculation is adjusted to avoid unaligned pointers. + */ +int uv_getaddrinfo(uv_loop_t* loop, + uv_getaddrinfo_t* req, + uv_getaddrinfo_cb getaddrinfo_cb, + const char* node, + const char* service, + const struct addrinfo* hints) { + int nodesize = 0; + int servicesize = 0; + int hintssize = 0; + char* alloc_ptr = NULL; + int err; + + if (req == NULL || (node == NULL && service == NULL)) { + err = WSAEINVAL; + goto error; + } + + uv_req_init(loop, (uv_req_t*)req); + + req->getaddrinfo_cb = getaddrinfo_cb; + req->addrinfo = NULL; + req->type = UV_GETADDRINFO; + req->loop = loop; + req->retcode = 0; + + /* calculate required memory size for all input values */ + if (node != NULL) { + nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) * + sizeof(WCHAR)); + if (nodesize == 0) { + err = GetLastError(); + goto error; + } + } + + if (service != NULL) { + servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, + 0, + service, + -1, + NULL, + 0) * + sizeof(WCHAR)); + if (servicesize == 0) { + err = GetLastError(); + goto error; + } + } + if (hints != NULL) { + hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW)); + } + + /* allocate memory for inputs, and partition it as needed */ + alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize); + if (!alloc_ptr) { + err = WSAENOBUFS; + goto error; + } + + /* save alloc_ptr now so we can free if error */ + req->alloc = (void*)alloc_ptr; + + /* convert node string to UTF16 into allocated memory and save pointer in */ + /* the request. */ + if (node != NULL) { + req->node = (WCHAR*)alloc_ptr; + if (MultiByteToWideChar(CP_UTF8, + 0, + node, + -1, + (WCHAR*) alloc_ptr, + nodesize / sizeof(WCHAR)) == 0) { + err = GetLastError(); + goto error; + } + alloc_ptr += nodesize; + } else { + req->node = NULL; + } + + /* convert service string to UTF16 into allocated memory and save pointer */ + /* in the req. */ + if (service != NULL) { + req->service = (WCHAR*)alloc_ptr; + if (MultiByteToWideChar(CP_UTF8, + 0, + service, + -1, + (WCHAR*) alloc_ptr, + servicesize / sizeof(WCHAR)) == 0) { + err = GetLastError(); + goto error; + } + alloc_ptr += servicesize; + } else { + req->service = NULL; + } + + /* copy hints to allocated memory and save pointer in req */ + if (hints != NULL) { + req->addrinfow = (struct addrinfoW*)alloc_ptr; + req->addrinfow->ai_family = hints->ai_family; + req->addrinfow->ai_socktype = hints->ai_socktype; + req->addrinfow->ai_protocol = hints->ai_protocol; + req->addrinfow->ai_flags = hints->ai_flags; + req->addrinfow->ai_addrlen = 0; + req->addrinfow->ai_canonname = NULL; + req->addrinfow->ai_addr = NULL; + req->addrinfow->ai_next = NULL; + } else { + req->addrinfow = NULL; + } + + uv__req_register(loop, req); + + if (getaddrinfo_cb) { + uv__work_submit(loop, + &req->work_req, + uv__getaddrinfo_work, + uv__getaddrinfo_done); + return 0; + } else { + uv__getaddrinfo_work(&req->work_req); + uv__getaddrinfo_done(&req->work_req, 0); + return req->retcode; + } + +error: + if (req != NULL) { + uv__free(req->alloc); + req->alloc = NULL; + } + return uv_translate_sys_error(err); +} diff --git a/src/win/getnameinfo.c b/src/win/getnameinfo.c new file mode 100644 index 0000000..66b64b8 --- /dev/null +++ b/src/win/getnameinfo.c @@ -0,0 +1,150 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. +* +* 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. +*/ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "req-inl.h" + +#ifndef GetNameInfo +int WSAAPI GetNameInfoW( + const SOCKADDR *pSockaddr, + socklen_t SockaddrLength, + PWCHAR pNodeBuffer, + DWORD NodeBufferSize, + PWCHAR pServiceBuffer, + DWORD ServiceBufferSize, + INT Flags +); +#endif + +static void uv__getnameinfo_work(struct uv__work* w) { + uv_getnameinfo_t* req; + WCHAR host[NI_MAXHOST]; + WCHAR service[NI_MAXSERV]; + int ret = 0; + + req = container_of(w, uv_getnameinfo_t, work_req); + if (GetNameInfoW((struct sockaddr*)&req->storage, + sizeof(req->storage), + host, + ARRAY_SIZE(host), + service, + ARRAY_SIZE(service), + req->flags)) { + ret = WSAGetLastError(); + } + req->retcode = uv__getaddrinfo_translate_error(ret); + + /* convert results to UTF-8 */ + WideCharToMultiByte(CP_UTF8, + 0, + host, + -1, + req->host, + sizeof(req->host), + NULL, + NULL); + + WideCharToMultiByte(CP_UTF8, + 0, + service, + -1, + req->service, + sizeof(req->service), + NULL, + NULL); +} + + +/* +* Called from uv_run when complete. +*/ +static void uv__getnameinfo_done(struct uv__work* w, int status) { + uv_getnameinfo_t* req; + char* host; + char* service; + + req = container_of(w, uv_getnameinfo_t, work_req); + uv__req_unregister(req->loop, req); + host = service = NULL; + + if (status == UV_ECANCELED) { + assert(req->retcode == 0); + req->retcode = UV_EAI_CANCELED; + } else if (req->retcode == 0) { + host = req->host; + service = req->service; + } + + if (req->getnameinfo_cb) + req->getnameinfo_cb(req, req->retcode, host, service); +} + + +/* +* Entry point for getnameinfo +* return 0 if a callback will be made +* return error code if validation fails +*/ +int uv_getnameinfo(uv_loop_t* loop, + uv_getnameinfo_t* req, + uv_getnameinfo_cb getnameinfo_cb, + const struct sockaddr* addr, + int flags) { + if (req == NULL || addr == NULL) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) { + memcpy(&req->storage, + addr, + sizeof(struct sockaddr_in)); + } else if (addr->sa_family == AF_INET6) { + memcpy(&req->storage, + addr, + sizeof(struct sockaddr_in6)); + } else { + return UV_EINVAL; + } + + uv_req_init(loop, (uv_req_t*)req); + uv__req_register(loop, req); + + req->getnameinfo_cb = getnameinfo_cb; + req->flags = flags; + req->type = UV_GETNAMEINFO; + req->loop = loop; + req->retcode = 0; + + if (getnameinfo_cb) { + uv__work_submit(loop, + &req->work_req, + uv__getnameinfo_work, + uv__getnameinfo_done); + return 0; + } else { + uv__getnameinfo_work(&req->work_req); + uv__getnameinfo_done(&req->work_req, 0); + return req->retcode; + } +} diff --git a/src/win/handle-inl.h b/src/win/handle-inl.h new file mode 100644 index 0000000..8d0334c --- /dev/null +++ b/src/win/handle-inl.h @@ -0,0 +1,179 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_WIN_HANDLE_INL_H_ +#define UV_WIN_HANDLE_INL_H_ + +#include +#include + +#include "uv.h" +#include "internal.h" + + +#define DECREASE_ACTIVE_COUNT(loop, handle) \ + do { \ + if (--(handle)->activecnt == 0 && \ + !((handle)->flags & UV__HANDLE_CLOSING)) { \ + uv__handle_stop((handle)); \ + } \ + assert((handle)->activecnt >= 0); \ + } while (0) + + +#define INCREASE_ACTIVE_COUNT(loop, handle) \ + do { \ + if ((handle)->activecnt++ == 0) { \ + uv__handle_start((handle)); \ + } \ + assert((handle)->activecnt > 0); \ + } while (0) + + +#define DECREASE_PENDING_REQ_COUNT(handle) \ + do { \ + assert(handle->reqs_pending > 0); \ + handle->reqs_pending--; \ + \ + if (handle->flags & UV__HANDLE_CLOSING && \ + handle->reqs_pending == 0) { \ + uv_want_endgame(loop, (uv_handle_t*)handle); \ + } \ + } while (0) + + +#define uv__handle_closing(handle) \ + do { \ + assert(!((handle)->flags & UV__HANDLE_CLOSING)); \ + \ + if (!(((handle)->flags & UV__HANDLE_ACTIVE) && \ + ((handle)->flags & UV__HANDLE_REF))) \ + uv__active_handle_add((uv_handle_t*) (handle)); \ + \ + (handle)->flags |= UV__HANDLE_CLOSING; \ + (handle)->flags &= ~UV__HANDLE_ACTIVE; \ + } while (0) + + +#define uv__handle_close(handle) \ + do { \ + QUEUE_REMOVE(&(handle)->handle_queue); \ + uv__active_handle_rm((uv_handle_t*) (handle)); \ + \ + (handle)->flags |= UV_HANDLE_CLOSED; \ + \ + if ((handle)->close_cb) \ + (handle)->close_cb((uv_handle_t*) (handle)); \ + } while (0) + + +INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) { + if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) { + handle->flags |= UV_HANDLE_ENDGAME_QUEUED; + + handle->endgame_next = loop->endgame_handles; + loop->endgame_handles = handle; + } +} + + +INLINE static void uv_process_endgames(uv_loop_t* loop) { + uv_handle_t* handle; + + while (loop->endgame_handles) { + handle = loop->endgame_handles; + loop->endgame_handles = handle->endgame_next; + + handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED; + + switch (handle->type) { + case UV_TCP: + uv_tcp_endgame(loop, (uv_tcp_t*) handle); + break; + + case UV_NAMED_PIPE: + uv_pipe_endgame(loop, (uv_pipe_t*) handle); + break; + + case UV_TTY: + uv_tty_endgame(loop, (uv_tty_t*) handle); + break; + + case UV_UDP: + uv_udp_endgame(loop, (uv_udp_t*) handle); + break; + + case UV_POLL: + uv_poll_endgame(loop, (uv_poll_t*) handle); + break; + + case UV_TIMER: + uv_timer_endgame(loop, (uv_timer_t*) handle); + break; + + case UV_PREPARE: + case UV_CHECK: + case UV_IDLE: + uv_loop_watcher_endgame(loop, handle); + break; + + case UV_ASYNC: + uv_async_endgame(loop, (uv_async_t*) handle); + break; + + case UV_SIGNAL: + uv_signal_endgame(loop, (uv_signal_t*) handle); + break; + + case UV_PROCESS: + uv_process_endgame(loop, (uv_process_t*) handle); + break; + + case UV_FS_EVENT: + uv_fs_event_endgame(loop, (uv_fs_event_t*) handle); + break; + + case UV_FS_POLL: + uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle); + break; + + default: + assert(0); + break; + } + } +} + +INLINE static HANDLE uv__get_osfhandle(int fd) +{ + /* _get_osfhandle() raises an assert in debug builds if the FD is invalid. */ + /* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE */ + /* for invalid FDs in release builds (or if you let the assert continue). */ + /* So this wrapper function disables asserts when calling _get_osfhandle. */ + + HANDLE handle; + UV_BEGIN_DISABLE_CRT_ASSERT(); + handle = (HANDLE) _get_osfhandle(fd); + UV_END_DISABLE_CRT_ASSERT(); + return handle; +} + +#endif /* UV_WIN_HANDLE_INL_H_ */ diff --git a/src/win/handle.c b/src/win/handle.c new file mode 100644 index 0000000..72b49d9 --- /dev/null +++ b/src/win/handle.c @@ -0,0 +1,154 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" + + +uv_handle_type uv_guess_handle(uv_file file) { + HANDLE handle; + DWORD mode; + + if (file < 0) { + return UV_UNKNOWN_HANDLE; + } + + handle = uv__get_osfhandle(file); + + switch (GetFileType(handle)) { + case FILE_TYPE_CHAR: + if (GetConsoleMode(handle, &mode)) { + return UV_TTY; + } else { + return UV_FILE; + } + + case FILE_TYPE_PIPE: + return UV_NAMED_PIPE; + + case FILE_TYPE_DISK: + return UV_FILE; + + default: + return UV_UNKNOWN_HANDLE; + } +} + + +int uv_is_active(const uv_handle_t* handle) { + return (handle->flags & UV__HANDLE_ACTIVE) && + !(handle->flags & UV__HANDLE_CLOSING); +} + + +void uv_close(uv_handle_t* handle, uv_close_cb cb) { + uv_loop_t* loop = handle->loop; + + if (handle->flags & UV__HANDLE_CLOSING) { + assert(0); + return; + } + + handle->close_cb = cb; + + /* Handle-specific close actions */ + switch (handle->type) { + case UV_TCP: + uv_tcp_close(loop, (uv_tcp_t*)handle); + return; + + case UV_NAMED_PIPE: + uv_pipe_close(loop, (uv_pipe_t*) handle); + return; + + case UV_TTY: + uv_tty_close((uv_tty_t*) handle); + return; + + case UV_UDP: + uv_udp_close(loop, (uv_udp_t*) handle); + return; + + case UV_POLL: + uv_poll_close(loop, (uv_poll_t*) handle); + return; + + case UV_TIMER: + uv_timer_stop((uv_timer_t*)handle); + uv__handle_closing(handle); + uv_want_endgame(loop, handle); + return; + + case UV_PREPARE: + uv_prepare_stop((uv_prepare_t*)handle); + uv__handle_closing(handle); + uv_want_endgame(loop, handle); + return; + + case UV_CHECK: + uv_check_stop((uv_check_t*)handle); + uv__handle_closing(handle); + uv_want_endgame(loop, handle); + return; + + case UV_IDLE: + uv_idle_stop((uv_idle_t*)handle); + uv__handle_closing(handle); + uv_want_endgame(loop, handle); + return; + + case UV_ASYNC: + uv_async_close(loop, (uv_async_t*) handle); + return; + + case UV_SIGNAL: + uv_signal_close(loop, (uv_signal_t*) handle); + return; + + case UV_PROCESS: + uv_process_close(loop, (uv_process_t*) handle); + return; + + case UV_FS_EVENT: + uv_fs_event_close(loop, (uv_fs_event_t*) handle); + return; + + case UV_FS_POLL: + uv__fs_poll_close((uv_fs_poll_t*) handle); + uv__handle_closing(handle); + uv_want_endgame(loop, handle); + return; + + default: + /* Not supported */ + abort(); + } +} + + +int uv_is_closing(const uv_handle_t* handle) { + return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED)); +} diff --git a/src/win/internal.h b/src/win/internal.h new file mode 100644 index 0000000..b8cfde9 --- /dev/null +++ b/src/win/internal.h @@ -0,0 +1,394 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_WIN_INTERNAL_H_ +#define UV_WIN_INTERNAL_H_ + +#include "uv.h" +#include "../uv-common.h" + +#include "tree.h" +#include "winapi.h" +#include "winsock.h" + +#ifdef _MSC_VER +# define INLINE __inline +# define UV_THREAD_LOCAL __declspec( thread ) +#else +# define INLINE inline +# define UV_THREAD_LOCAL __thread +#endif + + +#ifdef _DEBUG + +extern UV_THREAD_LOCAL int uv__crt_assert_enabled; + +#define UV_BEGIN_DISABLE_CRT_ASSERT() \ + { \ + int uv__saved_crt_assert_enabled = uv__crt_assert_enabled; \ + uv__crt_assert_enabled = FALSE; + + +#define UV_END_DISABLE_CRT_ASSERT() \ + uv__crt_assert_enabled = uv__saved_crt_assert_enabled; \ + } + +#else +#define UV_BEGIN_DISABLE_CRT_ASSERT() +#define UV_END_DISABLE_CRT_ASSERT() +#endif + +/* + * Handles + * (also see handle-inl.h) + */ + +/* Used by all handles. */ +#define UV_HANDLE_CLOSED 0x00000002 +#define UV_HANDLE_ENDGAME_QUEUED 0x00000008 + +/* uv-common.h: #define UV__HANDLE_CLOSING 0x00000001 */ +/* uv-common.h: #define UV__HANDLE_ACTIVE 0x00000040 */ +/* uv-common.h: #define UV__HANDLE_REF 0x00000020 */ +/* uv-common.h: #define UV_HANDLE_INTERNAL 0x00000080 */ + +/* Used by streams and UDP handles. */ +#define UV_HANDLE_READING 0x00000100 +#define UV_HANDLE_BOUND 0x00000200 +#define UV_HANDLE_LISTENING 0x00000800 +#define UV_HANDLE_CONNECTION 0x00001000 +#define UV_HANDLE_READABLE 0x00008000 +#define UV_HANDLE_WRITABLE 0x00010000 +#define UV_HANDLE_READ_PENDING 0x00020000 +#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00040000 +#define UV_HANDLE_ZERO_READ 0x00080000 +#define UV_HANDLE_EMULATE_IOCP 0x00100000 +#define UV_HANDLE_BLOCKING_WRITES 0x00200000 +#define UV_HANDLE_CANCELLATION_PENDING 0x00400000 + +/* Used by uv_tcp_t and uv_udp_t handles */ +#define UV_HANDLE_IPV6 0x01000000 + +/* Only used by uv_tcp_t handles. */ +#define UV_HANDLE_TCP_NODELAY 0x02000000 +#define UV_HANDLE_TCP_KEEPALIVE 0x04000000 +#define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000 +#define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000 +#define UV_HANDLE_TCP_SOCKET_CLOSED 0x20000000 +#define UV_HANDLE_SHARED_TCP_SOCKET 0x40000000 + +/* Only used by uv_pipe_t handles. */ +#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000 +#define UV_HANDLE_PIPESERVER 0x02000000 +#define UV_HANDLE_PIPE_READ_CANCELABLE 0x04000000 + +/* Only used by uv_tty_t handles. */ +#define UV_HANDLE_TTY_READABLE 0x01000000 +#define UV_HANDLE_TTY_RAW 0x02000000 +#define UV_HANDLE_TTY_SAVED_POSITION 0x04000000 +#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x08000000 + +/* Only used by uv_poll_t handles. */ +#define UV_HANDLE_POLL_SLOW 0x02000000 + + +/* + * Requests: see req-inl.h + */ + + +/* + * Streams: see stream-inl.h + */ + + +/* + * TCP + */ + +typedef struct { + WSAPROTOCOL_INFOW socket_info; + int delayed_error; +} uv__ipc_socket_info_ex; + +int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb); +int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client); +int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb); +int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle, + const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); +int uv__tcp_try_write(uv_tcp_t* handle, const uv_buf_t bufs[], + unsigned int nbufs); + +void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req); +void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_write_t* req); +void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_req_t* req); +void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_connect_t* req); + +void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp); +void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); + +int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex, + int tcp_connection); + +int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, + LPWSAPROTOCOL_INFOW protocol_info); + + +/* + * UDP + */ +void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req); +void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, + uv_udp_send_t* req); + +void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle); +void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle); + + +/* + * Pipes + */ +int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, + char* name, size_t nameSize); + +int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); +int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client); +int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb); +int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle, + const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); +int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle, + const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, + uv_write_cb cb); +void uv__pipe_pause_read(uv_pipe_t* handle); +void uv__pipe_unpause_read(uv_pipe_t* handle); +void uv__pipe_stop_read(uv_pipe_t* handle); + +void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_req_t* req); +void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_write_t* req); +void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_req_t* raw_req); +void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_connect_t* req); +void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_shutdown_t* req); + +void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle); +void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle); +void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle); + + +/* + * TTY + */ +void uv_console_init(); + +int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb); +int uv_tty_read_stop(uv_tty_t* handle); +int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle, + const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); +int uv__tty_try_write(uv_tty_t* handle, const uv_buf_t bufs[], + unsigned int nbufs); +void uv_tty_close(uv_tty_t* handle); + +void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* req); +void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, + uv_write_t* req); +/* TODO: remove me */ +void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* raw_req); +/* TODO: remove me */ +void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, + uv_connect_t* req); + +void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle); + + +/* + * Poll watchers + */ +void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, + uv_req_t* req); + +int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle); +void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle); + + +/* + * Timers + */ +void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); + +DWORD uv__next_timeout(const uv_loop_t* loop); +void uv_process_timers(uv_loop_t* loop); + + +/* + * Loop watchers + */ +void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle); + +void uv_prepare_invoke(uv_loop_t* loop); +void uv_check_invoke(uv_loop_t* loop); +void uv_idle_invoke(uv_loop_t* loop); + +void uv__once_init(); + + +/* + * Async watcher + */ +void uv_async_close(uv_loop_t* loop, uv_async_t* handle); +void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle); + +void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, + uv_req_t* req); + + +/* + * Signal watcher + */ +void uv_signals_init(); +int uv__signal_dispatch(int signum); + +void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle); +void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle); + +void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, + uv_req_t* req); + + +/* + * Spawn + */ +void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle); +void uv_process_close(uv_loop_t* loop, uv_process_t* handle); +void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle); + + +/* + * Error + */ +int uv_translate_sys_error(int sys_errno); + + +/* + * FS + */ +void uv_fs_init(); + + +/* + * FS Event + */ +void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, + uv_fs_event_t* handle); +void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle); +void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle); + + +/* + * Stat poller. + */ +void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle); + + +/* + * Utilities. + */ +void uv__util_init(); + +uint64_t uv__hrtime(double scale); +int uv_parent_pid(); +int uv_current_pid(); +__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); +int uv__getpwuid_r(uv_passwd_t* pwd); +int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8); + + +/* + * Process stdio handles. + */ +int uv__stdio_create(uv_loop_t* loop, + const uv_process_options_t* options, + BYTE** buffer_ptr); +void uv__stdio_destroy(BYTE* buffer); +void uv__stdio_noinherit(BYTE* buffer); +int uv__stdio_verify(BYTE* buffer, WORD size); +WORD uv__stdio_size(BYTE* buffer); +HANDLE uv__stdio_handle(BYTE* buffer, int fd); + + +/* + * Winapi and ntapi utility functions + */ +void uv_winapi_init(); + + +/* + * Winsock utility functions + */ +void uv_winsock_init(); + +int uv_ntstatus_to_winsock_error(NTSTATUS status); + +BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target); +BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target); + +int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers, + DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); +int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, + DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr, + int* addr_len, WSAOVERLAPPED *overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); + +int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, + AFD_POLL_INFO* info_out, OVERLAPPED* overlapped); + +/* Whether there are any non-IFS LSPs stacked on TCP */ +extern int uv_tcp_non_ifs_lsp_ipv4; +extern int uv_tcp_non_ifs_lsp_ipv6; + +/* Ip address used to bind to any port at any interface */ +extern struct sockaddr_in uv_addr_ip4_any_; +extern struct sockaddr_in6 uv_addr_ip6_any_; + +/* + * Wake all loops with fake message + */ +void uv__wake_all_loops(); + +/* + * Init system wake-up detection + */ +void uv__init_detect_system_wakeup(); + +#endif /* UV_WIN_INTERNAL_H_ */ diff --git a/src/win/loop-watcher.c b/src/win/loop-watcher.c new file mode 100644 index 0000000..20e4509 --- /dev/null +++ b/src/win/loop-watcher.c @@ -0,0 +1,122 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" + + +void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { + if (handle->flags & UV__HANDLE_CLOSING) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + handle->flags |= UV_HANDLE_CLOSED; + uv__handle_close(handle); + } +} + + +#define UV_LOOP_WATCHER_DEFINE(name, NAME) \ + int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \ + uv__handle_init(loop, (uv_handle_t*) handle, UV_##NAME); \ + \ + return 0; \ + } \ + \ + \ + int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \ + uv_loop_t* loop = handle->loop; \ + uv_##name##_t* old_head; \ + \ + assert(handle->type == UV_##NAME); \ + \ + if (uv__is_active(handle)) \ + return 0; \ + \ + if (cb == NULL) \ + return UV_EINVAL; \ + \ + old_head = loop->name##_handles; \ + \ + handle->name##_next = old_head; \ + handle->name##_prev = NULL; \ + \ + if (old_head) { \ + old_head->name##_prev = handle; \ + } \ + \ + loop->name##_handles = handle; \ + \ + handle->name##_cb = cb; \ + uv__handle_start(handle); \ + \ + return 0; \ + } \ + \ + \ + int uv_##name##_stop(uv_##name##_t* handle) { \ + uv_loop_t* loop = handle->loop; \ + \ + assert(handle->type == UV_##NAME); \ + \ + if (!uv__is_active(handle)) \ + return 0; \ + \ + /* Update loop head if needed */ \ + if (loop->name##_handles == handle) { \ + loop->name##_handles = handle->name##_next; \ + } \ + \ + /* Update the iterator-next pointer of needed */ \ + if (loop->next_##name##_handle == handle) { \ + loop->next_##name##_handle = handle->name##_next; \ + } \ + \ + if (handle->name##_prev) { \ + handle->name##_prev->name##_next = handle->name##_next; \ + } \ + if (handle->name##_next) { \ + handle->name##_next->name##_prev = handle->name##_prev; \ + } \ + \ + uv__handle_stop(handle); \ + \ + return 0; \ + } \ + \ + \ + void uv_##name##_invoke(uv_loop_t* loop) { \ + uv_##name##_t* handle; \ + \ + (loop)->next_##name##_handle = (loop)->name##_handles; \ + \ + while ((loop)->next_##name##_handle != NULL) { \ + handle = (loop)->next_##name##_handle; \ + (loop)->next_##name##_handle = handle->name##_next; \ + \ + handle->name##_cb(handle); \ + } \ + } + +UV_LOOP_WATCHER_DEFINE(prepare, PREPARE) +UV_LOOP_WATCHER_DEFINE(check, CHECK) +UV_LOOP_WATCHER_DEFINE(idle, IDLE) diff --git a/src/win/pipe.c b/src/win/pipe.c new file mode 100644 index 0000000..2442be7 --- /dev/null +++ b/src/win/pipe.c @@ -0,0 +1,2130 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" + +typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t; + +struct uv__ipc_queue_item_s { + /* + * NOTE: It is important for socket_info_ex to be the first field, + * because we will we assigning it to the pending_ipc_info.socket_info + */ + uv__ipc_socket_info_ex socket_info_ex; + QUEUE member; + int tcp_connection; +}; + +/* A zero-size buffer for use by uv_pipe_read */ +static char uv_zero_[] = ""; + +/* Null uv_buf_t */ +static const uv_buf_t uv_null_buf_ = { 0, NULL }; + +/* The timeout that the pipe will wait for the remote end to write data */ +/* when the local ends wants to shut it down. */ +static const int64_t eof_timeout = 50; /* ms */ + +static const int default_pending_pipe_instances = 4; + +/* Pipe prefix */ +static char pipe_prefix[] = "\\\\?\\pipe"; +static const int pipe_prefix_len = sizeof(pipe_prefix) - 1; + +/* IPC protocol flags. */ +#define UV_IPC_RAW_DATA 0x0001 +#define UV_IPC_TCP_SERVER 0x0002 +#define UV_IPC_TCP_CONNECTION 0x0004 + +/* IPC frame header. */ +typedef struct { + int flags; + uint64_t raw_data_length; +} uv_ipc_frame_header_t; + +/* IPC frame, which contains an imported TCP socket stream. */ +typedef struct { + uv_ipc_frame_header_t header; + uv__ipc_socket_info_ex socket_info_ex; +} uv_ipc_frame_uv_stream; + +static void eof_timer_init(uv_pipe_t* pipe); +static void eof_timer_start(uv_pipe_t* pipe); +static void eof_timer_stop(uv_pipe_t* pipe); +static void eof_timer_cb(uv_timer_t* timer); +static void eof_timer_destroy(uv_pipe_t* pipe); +static void eof_timer_close_cb(uv_handle_t* handle); + + +static void uv_unique_pipe_name(char* ptr, char* name, size_t size) { + snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId()); +} + + +int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { + uv_stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); + + handle->reqs_pending = 0; + handle->handle = INVALID_HANDLE_VALUE; + handle->name = NULL; + handle->pipe.conn.ipc_pid = 0; + handle->pipe.conn.remaining_ipc_rawdata_bytes = 0; + QUEUE_INIT(&handle->pipe.conn.pending_ipc_info.queue); + handle->pipe.conn.pending_ipc_info.queue_len = 0; + handle->ipc = ipc; + handle->pipe.conn.non_overlapped_writes_tail = NULL; + handle->pipe.conn.readfile_thread = NULL; + + uv_req_init(loop, (uv_req_t*) &handle->pipe.conn.ipc_header_write_req); + + return 0; +} + + +static void uv_pipe_connection_init(uv_pipe_t* handle) { + uv_connection_init((uv_stream_t*) handle); + handle->read_req.data = handle; + handle->pipe.conn.eof_timer = NULL; + assert(!(handle->flags & UV_HANDLE_PIPESERVER)); + if (pCancelSynchronousIo && + handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + uv_mutex_init(&handle->pipe.conn.readfile_mutex); + handle->flags |= UV_HANDLE_PIPE_READ_CANCELABLE; + } +} + + +static HANDLE open_named_pipe(const WCHAR* name, DWORD* duplex_flags) { + HANDLE pipeHandle; + + /* + * Assume that we have a duplex pipe first, so attempt to + * connect with GENERIC_READ | GENERIC_WRITE. + */ + pipeHandle = CreateFileW(name, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + if (pipeHandle != INVALID_HANDLE_VALUE) { + *duplex_flags = UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + return pipeHandle; + } + + /* + * If the pipe is not duplex CreateFileW fails with + * ERROR_ACCESS_DENIED. In that case try to connect + * as a read-only or write-only. + */ + if (GetLastError() == ERROR_ACCESS_DENIED) { + pipeHandle = CreateFileW(name, + GENERIC_READ | FILE_WRITE_ATTRIBUTES, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + + if (pipeHandle != INVALID_HANDLE_VALUE) { + *duplex_flags = UV_HANDLE_READABLE; + return pipeHandle; + } + } + + if (GetLastError() == ERROR_ACCESS_DENIED) { + pipeHandle = CreateFileW(name, + GENERIC_WRITE | FILE_READ_ATTRIBUTES, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + + if (pipeHandle != INVALID_HANDLE_VALUE) { + *duplex_flags = UV_HANDLE_WRITABLE; + return pipeHandle; + } + } + + return INVALID_HANDLE_VALUE; +} + + +static void close_pipe(uv_pipe_t* pipe) { + assert(pipe->u.fd == -1 || pipe->u.fd > 2); + if (pipe->u.fd == -1) + CloseHandle(pipe->handle); + else + close(pipe->u.fd); + + pipe->u.fd = -1; + pipe->handle = INVALID_HANDLE_VALUE; +} + + +int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, + char* name, size_t nameSize) { + HANDLE pipeHandle; + int err; + char* ptr = (char*)handle; + + for (;;) { + uv_unique_pipe_name(ptr, name, nameSize); + + pipeHandle = CreateNamedPipeA(name, + access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0, + NULL); + + if (pipeHandle != INVALID_HANDLE_VALUE) { + /* No name collisions. We're done. */ + break; + } + + err = GetLastError(); + if (err != ERROR_PIPE_BUSY && err != ERROR_ACCESS_DENIED) { + goto error; + } + + /* Pipe name collision. Increment the pointer and try again. */ + ptr++; + } + + if (CreateIoCompletionPort(pipeHandle, + loop->iocp, + (ULONG_PTR)handle, + 0) == NULL) { + err = GetLastError(); + goto error; + } + + uv_pipe_connection_init(handle); + handle->handle = pipeHandle; + + return 0; + + error: + if (pipeHandle != INVALID_HANDLE_VALUE) { + CloseHandle(pipeHandle); + } + + return err; +} + + +static int uv_set_pipe_handle(uv_loop_t* loop, + uv_pipe_t* handle, + HANDLE pipeHandle, + int fd, + DWORD duplex_flags) { + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_MODE_INFORMATION mode_info; + DWORD mode = PIPE_READMODE_BYTE | PIPE_WAIT; + DWORD current_mode = 0; + DWORD err = 0; + + if (!(handle->flags & UV_HANDLE_PIPESERVER) && + handle->handle != INVALID_HANDLE_VALUE) + return UV_EBUSY; + + if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) { + err = GetLastError(); + if (err == ERROR_ACCESS_DENIED) { + /* + * SetNamedPipeHandleState can fail if the handle doesn't have either + * GENERIC_WRITE or FILE_WRITE_ATTRIBUTES. + * But if the handle already has the desired wait and blocking modes + * we can continue. + */ + if (!GetNamedPipeHandleState(pipeHandle, ¤t_mode, NULL, NULL, + NULL, NULL, 0)) { + return -1; + } else if (current_mode & PIPE_NOWAIT) { + SetLastError(ERROR_ACCESS_DENIED); + return -1; + } + } else { + /* If this returns ERROR_INVALID_PARAMETER we probably opened + * something that is not a pipe. */ + if (err == ERROR_INVALID_PARAMETER) { + SetLastError(WSAENOTSOCK); + } + return -1; + } + } + + /* Check if the pipe was created with FILE_FLAG_OVERLAPPED. */ + nt_status = pNtQueryInformationFile(pipeHandle, + &io_status, + &mode_info, + sizeof(mode_info), + FileModeInformation); + if (nt_status != STATUS_SUCCESS) { + return -1; + } + + if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT || + mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) { + /* Non-overlapped pipe. */ + handle->flags |= UV_HANDLE_NON_OVERLAPPED_PIPE; + } else { + /* Overlapped pipe. Try to associate with IOCP. */ + if (CreateIoCompletionPort(pipeHandle, + loop->iocp, + (ULONG_PTR)handle, + 0) == NULL) { + handle->flags |= UV_HANDLE_EMULATE_IOCP; + } + } + + handle->handle = pipeHandle; + handle->u.fd = fd; + handle->flags |= duplex_flags; + + return 0; +} + + +static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) { + uv_loop_t* loop; + uv_pipe_t* handle; + uv_shutdown_t* req; + + req = (uv_shutdown_t*) parameter; + assert(req); + handle = (uv_pipe_t*) req->handle; + assert(handle); + loop = handle->loop; + assert(loop); + + FlushFileBuffers(handle->handle); + + /* Post completed */ + POST_COMPLETION_FOR_REQ(loop, req); + + return 0; +} + + +void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { + int err; + DWORD result; + uv_shutdown_t* req; + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_PIPE_LOCAL_INFORMATION pipe_info; + uv__ipc_queue_item_t* item; + + if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + handle->flags &= ~UV_HANDLE_PIPE_READ_CANCELABLE; + uv_mutex_destroy(&handle->pipe.conn.readfile_mutex); + } + + if ((handle->flags & UV_HANDLE_CONNECTION) && + handle->stream.conn.shutdown_req != NULL && + handle->stream.conn.write_reqs_pending == 0) { + req = handle->stream.conn.shutdown_req; + + /* Clear the shutdown_req field so we don't go here again. */ + handle->stream.conn.shutdown_req = NULL; + + if (handle->flags & UV__HANDLE_CLOSING) { + UNREGISTER_HANDLE_REQ(loop, handle, req); + + /* Already closing. Cancel the shutdown. */ + if (req->cb) { + req->cb(req, UV_ECANCELED); + } + + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + /* Try to avoid flushing the pipe buffer in the thread pool. */ + nt_status = pNtQueryInformationFile(handle->handle, + &io_status, + &pipe_info, + sizeof pipe_info, + FilePipeLocalInformation); + + if (nt_status != STATUS_SUCCESS) { + /* Failure */ + UNREGISTER_HANDLE_REQ(loop, handle, req); + + handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */ + if (req->cb) { + err = pRtlNtStatusToDosError(nt_status); + req->cb(req, uv_translate_sys_error(err)); + } + + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) { + /* Short-circuit, no need to call FlushFileBuffers. */ + uv_insert_pending_req(loop, (uv_req_t*) req); + return; + } + + /* Run FlushFileBuffers in the thread pool. */ + result = QueueUserWorkItem(pipe_shutdown_thread_proc, + req, + WT_EXECUTELONGFUNCTION); + if (result) { + return; + + } else { + /* Failure. */ + UNREGISTER_HANDLE_REQ(loop, handle, req); + + handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */ + if (req->cb) { + err = GetLastError(); + req->cb(req, uv_translate_sys_error(err)); + } + + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + } + + if (handle->flags & UV__HANDLE_CLOSING && + handle->reqs_pending == 0) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + if (handle->flags & UV_HANDLE_CONNECTION) { + /* Free pending sockets */ + while (!QUEUE_EMPTY(&handle->pipe.conn.pending_ipc_info.queue)) { + QUEUE* q; + SOCKET socket; + + q = QUEUE_HEAD(&handle->pipe.conn.pending_ipc_info.queue); + QUEUE_REMOVE(q); + item = QUEUE_DATA(q, uv__ipc_queue_item_t, member); + + /* Materialize socket and close it */ + socket = WSASocketW(FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + &item->socket_info_ex.socket_info, + 0, + WSA_FLAG_OVERLAPPED); + uv__free(item); + + if (socket != INVALID_SOCKET) + closesocket(socket); + } + handle->pipe.conn.pending_ipc_info.queue_len = 0; + + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(handle->read_req.wait_handle); + handle->read_req.wait_handle = INVALID_HANDLE_VALUE; + } + if (handle->read_req.event_handle) { + CloseHandle(handle->read_req.event_handle); + handle->read_req.event_handle = NULL; + } + } + } + + if (handle->flags & UV_HANDLE_PIPESERVER) { + assert(handle->pipe.serv.accept_reqs); + uv__free(handle->pipe.serv.accept_reqs); + handle->pipe.serv.accept_reqs = NULL; + } + + uv__handle_close(handle); + } +} + + +void uv_pipe_pending_instances(uv_pipe_t* handle, int count) { + if (handle->flags & UV_HANDLE_BOUND) + return; + handle->pipe.serv.pending_instances = count; + handle->flags |= UV_HANDLE_PIPESERVER; +} + + +/* Creates a pipe server. */ +int uv_pipe_bind(uv_pipe_t* handle, const char* name) { + uv_loop_t* loop = handle->loop; + int i, err, nameSize; + uv_pipe_accept_t* req; + + if (handle->flags & UV_HANDLE_BOUND) { + return UV_EINVAL; + } + + if (!name) { + return UV_EINVAL; + } + + if (!(handle->flags & UV_HANDLE_PIPESERVER)) { + handle->pipe.serv.pending_instances = default_pending_pipe_instances; + } + + handle->pipe.serv.accept_reqs = (uv_pipe_accept_t*) + uv__malloc(sizeof(uv_pipe_accept_t) * handle->pipe.serv.pending_instances); + if (!handle->pipe.serv.accept_reqs) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + for (i = 0; i < handle->pipe.serv.pending_instances; i++) { + req = &handle->pipe.serv.accept_reqs[i]; + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_ACCEPT; + req->data = handle; + req->pipeHandle = INVALID_HANDLE_VALUE; + req->next_pending = NULL; + } + + /* Convert name to UTF16. */ + nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); + handle->name = (WCHAR*)uv__malloc(nameSize); + if (!handle->name) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + name, + -1, + handle->name, + nameSize / sizeof(WCHAR))) { + err = GetLastError(); + goto error; + } + + /* + * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE. + * If this fails then there's already a pipe server for the given pipe name. + */ + handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | + FILE_FLAG_FIRST_PIPE_INSTANCE, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL); + + if (handle->pipe.serv.accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) { + err = GetLastError(); + if (err == ERROR_ACCESS_DENIED) { + err = WSAEADDRINUSE; /* Translates to UV_EADDRINUSE. */ + } else if (err == ERROR_PATH_NOT_FOUND || err == ERROR_INVALID_NAME) { + err = WSAEACCES; /* Translates to UV_EACCES. */ + } + goto error; + } + + if (uv_set_pipe_handle(loop, + handle, + handle->pipe.serv.accept_reqs[0].pipeHandle, + -1, + 0)) { + err = GetLastError(); + goto error; + } + + handle->pipe.serv.pending_accepts = NULL; + handle->flags |= UV_HANDLE_PIPESERVER; + handle->flags |= UV_HANDLE_BOUND; + + return 0; + +error: + if (handle->name) { + uv__free(handle->name); + handle->name = NULL; + } + + if (handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) { + CloseHandle(handle->pipe.serv.accept_reqs[0].pipeHandle); + handle->pipe.serv.accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE; + } + + return uv_translate_sys_error(err); +} + + +static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { + uv_loop_t* loop; + uv_pipe_t* handle; + uv_connect_t* req; + HANDLE pipeHandle = INVALID_HANDLE_VALUE; + DWORD duplex_flags; + + req = (uv_connect_t*) parameter; + assert(req); + handle = (uv_pipe_t*) req->handle; + assert(handle); + loop = handle->loop; + assert(loop); + + /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */ + /* We wait for the pipe to become available with WaitNamedPipe. */ + while (WaitNamedPipeW(handle->name, 30000)) { + /* The pipe is now available, try to connect. */ + pipeHandle = open_named_pipe(handle->name, &duplex_flags); + if (pipeHandle != INVALID_HANDLE_VALUE) { + break; + } + + SwitchToThread(); + } + + if (pipeHandle != INVALID_HANDLE_VALUE && + !uv_set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) { + SET_REQ_SUCCESS(req); + } else { + SET_REQ_ERROR(req, GetLastError()); + } + + /* Post completed */ + POST_COMPLETION_FOR_REQ(loop, req); + + return 0; +} + + +void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, + const char* name, uv_connect_cb cb) { + uv_loop_t* loop = handle->loop; + int err, nameSize; + HANDLE pipeHandle = INVALID_HANDLE_VALUE; + DWORD duplex_flags; + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_CONNECT; + req->handle = (uv_stream_t*) handle; + req->cb = cb; + + /* Convert name to UTF16. */ + nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); + handle->name = (WCHAR*)uv__malloc(nameSize); + if (!handle->name) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + name, + -1, + handle->name, + nameSize / sizeof(WCHAR))) { + err = GetLastError(); + goto error; + } + + pipeHandle = open_named_pipe(handle->name, &duplex_flags); + if (pipeHandle == INVALID_HANDLE_VALUE) { + if (GetLastError() == ERROR_PIPE_BUSY) { + /* Wait for the server to make a pipe instance available. */ + if (!QueueUserWorkItem(&pipe_connect_thread_proc, + req, + WT_EXECUTELONGFUNCTION)) { + err = GetLastError(); + goto error; + } + + REGISTER_HANDLE_REQ(loop, handle, req); + handle->reqs_pending++; + + return; + } + + err = GetLastError(); + goto error; + } + + assert(pipeHandle != INVALID_HANDLE_VALUE); + + if (uv_set_pipe_handle(loop, + (uv_pipe_t*) req->handle, + pipeHandle, + -1, + duplex_flags)) { + err = GetLastError(); + goto error; + } + + SET_REQ_SUCCESS(req); + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + return; + +error: + if (handle->name) { + uv__free(handle->name); + handle->name = NULL; + } + + if (pipeHandle != INVALID_HANDLE_VALUE) { + CloseHandle(pipeHandle); + } + + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, err); + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + return; +} + + +void uv__pipe_pause_read(uv_pipe_t* handle) { + if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + /* Pause the ReadFile task briefly, to work + around the Windows kernel bug that causes + any access to a NamedPipe to deadlock if + any process has called ReadFile */ + HANDLE h; + uv_mutex_lock(&handle->pipe.conn.readfile_mutex); + h = handle->pipe.conn.readfile_thread; + while (h) { + /* spinlock: we expect this to finish quickly, + or we are probably about to deadlock anyways + (in the kernel), so it doesn't matter */ + pCancelSynchronousIo(h); + SwitchToThread(); /* yield thread control briefly */ + h = handle->pipe.conn.readfile_thread; + } + } +} + + +void uv__pipe_unpause_read(uv_pipe_t* handle) { + if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + uv_mutex_unlock(&handle->pipe.conn.readfile_mutex); + } +} + + +void uv__pipe_stop_read(uv_pipe_t* handle) { + handle->flags &= ~UV_HANDLE_READING; + uv__pipe_pause_read((uv_pipe_t*)handle); + uv__pipe_unpause_read((uv_pipe_t*)handle); +} + + +/* Cleans up uv_pipe_t (server or connection) and all resources associated */ +/* with it. */ +void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) { + int i; + HANDLE pipeHandle; + + uv__pipe_stop_read(handle); + + if (handle->name) { + uv__free(handle->name); + handle->name = NULL; + } + + if (handle->flags & UV_HANDLE_PIPESERVER) { + for (i = 0; i < handle->pipe.serv.pending_instances; i++) { + pipeHandle = handle->pipe.serv.accept_reqs[i].pipeHandle; + if (pipeHandle != INVALID_HANDLE_VALUE) { + CloseHandle(pipeHandle); + handle->pipe.serv.accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE; + } + } + handle->handle = INVALID_HANDLE_VALUE; + } + + if (handle->flags & UV_HANDLE_CONNECTION) { + handle->flags &= ~UV_HANDLE_WRITABLE; + eof_timer_destroy(handle); + } + + if ((handle->flags & UV_HANDLE_CONNECTION) + && handle->handle != INVALID_HANDLE_VALUE) + close_pipe(handle); +} + + +void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) { + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + if (handle->flags & UV_HANDLE_LISTENING) { + handle->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + uv_pipe_cleanup(loop, handle); + + if (handle->reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + + handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); + uv__handle_closing(handle); +} + + +static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, + uv_pipe_accept_t* req, BOOL firstInstance) { + assert(handle->flags & UV_HANDLE_LISTENING); + + if (!firstInstance) { + assert(req->pipeHandle == INVALID_HANDLE_VALUE); + + req->pipeHandle = CreateNamedPipeW(handle->name, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL); + + if (req->pipeHandle == INVALID_HANDLE_VALUE) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + return; + } + + if (uv_set_pipe_handle(loop, handle, req->pipeHandle, -1, 0)) { + CloseHandle(req->pipeHandle); + req->pipeHandle = INVALID_HANDLE_VALUE; + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + return; + } + } + + assert(req->pipeHandle != INVALID_HANDLE_VALUE); + + /* Prepare the overlapped structure. */ + memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); + + if (!ConnectNamedPipe(req->pipeHandle, &req->u.io.overlapped) && + GetLastError() != ERROR_IO_PENDING) { + if (GetLastError() == ERROR_PIPE_CONNECTED) { + SET_REQ_SUCCESS(req); + } else { + CloseHandle(req->pipeHandle); + req->pipeHandle = INVALID_HANDLE_VALUE; + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, GetLastError()); + } + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + return; + } + + handle->reqs_pending++; +} + + +int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { + uv_loop_t* loop = server->loop; + uv_pipe_t* pipe_client; + uv_pipe_accept_t* req; + QUEUE* q; + uv__ipc_queue_item_t* item; + int err; + + if (server->ipc) { + if (QUEUE_EMPTY(&server->pipe.conn.pending_ipc_info.queue)) { + /* No valid pending sockets. */ + return WSAEWOULDBLOCK; + } + + q = QUEUE_HEAD(&server->pipe.conn.pending_ipc_info.queue); + QUEUE_REMOVE(q); + server->pipe.conn.pending_ipc_info.queue_len--; + item = QUEUE_DATA(q, uv__ipc_queue_item_t, member); + + err = uv_tcp_import((uv_tcp_t*)client, + &item->socket_info_ex, + item->tcp_connection); + if (err != 0) + return err; + + uv__free(item); + + } else { + pipe_client = (uv_pipe_t*)client; + + /* Find a connection instance that has been connected, but not yet */ + /* accepted. */ + req = server->pipe.serv.pending_accepts; + + if (!req) { + /* No valid connections found, so we error out. */ + return WSAEWOULDBLOCK; + } + + /* Initialize the client handle and copy the pipeHandle to the client */ + uv_pipe_connection_init(pipe_client); + pipe_client->handle = req->pipeHandle; + pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + + /* Prepare the req to pick up a new connection */ + server->pipe.serv.pending_accepts = req->next_pending; + req->next_pending = NULL; + req->pipeHandle = INVALID_HANDLE_VALUE; + + if (!(server->flags & UV__HANDLE_CLOSING)) { + uv_pipe_queue_accept(loop, server, req, FALSE); + } + } + + return 0; +} + + +/* Starts listening for connections for the given pipe. */ +int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { + uv_loop_t* loop = handle->loop; + int i; + + if (handle->flags & UV_HANDLE_LISTENING) { + handle->stream.serv.connection_cb = cb; + } + + if (!(handle->flags & UV_HANDLE_BOUND)) { + return WSAEINVAL; + } + + if (handle->flags & UV_HANDLE_READING) { + return WSAEISCONN; + } + + if (!(handle->flags & UV_HANDLE_PIPESERVER)) { + return ERROR_NOT_SUPPORTED; + } + + handle->flags |= UV_HANDLE_LISTENING; + INCREASE_ACTIVE_COUNT(loop, handle); + handle->stream.serv.connection_cb = cb; + + /* First pipe handle should have already been created in uv_pipe_bind */ + assert(handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE); + + for (i = 0; i < handle->pipe.serv.pending_instances; i++) { + uv_pipe_queue_accept(loop, handle, &handle->pipe.serv.accept_reqs[i], i == 0); + } + + return 0; +} + + +static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) { + int result; + DWORD bytes; + uv_read_t* req = (uv_read_t*) parameter; + uv_pipe_t* handle = (uv_pipe_t*) req->data; + uv_loop_t* loop = handle->loop; + HANDLE hThread = NULL; + DWORD err; + uv_mutex_t *m = &handle->pipe.conn.readfile_mutex; + + assert(req != NULL); + assert(req->type == UV_READ); + assert(handle->type == UV_NAMED_PIPE); + + if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + uv_mutex_lock(m); /* mutex controls *setting* of readfile_thread */ + if (DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), + GetCurrentProcess(), &hThread, + 0, TRUE, DUPLICATE_SAME_ACCESS)) { + handle->pipe.conn.readfile_thread = hThread; + } else { + hThread = NULL; + } + uv_mutex_unlock(m); + } +restart_readfile: + result = ReadFile(handle->handle, + &uv_zero_, + 0, + &bytes, + NULL); + if (!result) { + err = GetLastError(); + if (err == ERROR_OPERATION_ABORTED && + handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + if (handle->flags & UV_HANDLE_READING) { + /* just a brief break to do something else */ + handle->pipe.conn.readfile_thread = NULL; + /* resume after it is finished */ + uv_mutex_lock(m); + handle->pipe.conn.readfile_thread = hThread; + uv_mutex_unlock(m); + goto restart_readfile; + } else { + result = 1; /* successfully stopped reading */ + } + } + } + if (hThread) { + assert(hThread == handle->pipe.conn.readfile_thread); + /* mutex does not control clearing readfile_thread */ + handle->pipe.conn.readfile_thread = NULL; + uv_mutex_lock(m); + /* only when we hold the mutex lock is it safe to + open or close the handle */ + CloseHandle(hThread); + uv_mutex_unlock(m); + } + + if (!result) { + SET_REQ_ERROR(req, err); + } + + POST_COMPLETION_FOR_REQ(loop, req); + return 0; +} + + +static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) { + int result; + DWORD bytes; + uv_write_t* req = (uv_write_t*) parameter; + uv_pipe_t* handle = (uv_pipe_t*) req->handle; + uv_loop_t* loop = handle->loop; + + assert(req != NULL); + assert(req->type == UV_WRITE); + assert(handle->type == UV_NAMED_PIPE); + assert(req->write_buffer.base); + + result = WriteFile(handle->handle, + req->write_buffer.base, + req->write_buffer.len, + &bytes, + NULL); + + if (!result) { + SET_REQ_ERROR(req, GetLastError()); + } + + POST_COMPLETION_FOR_REQ(loop, req); + return 0; +} + + +static void CALLBACK post_completion_read_wait(void* context, BOOLEAN timed_out) { + uv_read_t* req; + uv_tcp_t* handle; + + req = (uv_read_t*) context; + assert(req != NULL); + handle = (uv_tcp_t*)req->data; + assert(handle != NULL); + assert(!timed_out); + + if (!PostQueuedCompletionStatus(handle->loop->iocp, + req->u.io.overlapped.InternalHigh, + 0, + &req->u.io.overlapped)) { + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); + } +} + + +static void CALLBACK post_completion_write_wait(void* context, BOOLEAN timed_out) { + uv_write_t* req; + uv_tcp_t* handle; + + req = (uv_write_t*) context; + assert(req != NULL); + handle = (uv_tcp_t*)req->handle; + assert(handle != NULL); + assert(!timed_out); + + if (!PostQueuedCompletionStatus(handle->loop->iocp, + req->u.io.overlapped.InternalHigh, + 0, + &req->u.io.overlapped)) { + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); + } +} + + +static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) { + uv_read_t* req; + int result; + + assert(handle->flags & UV_HANDLE_READING); + assert(!(handle->flags & UV_HANDLE_READ_PENDING)); + + assert(handle->handle != INVALID_HANDLE_VALUE); + + req = &handle->read_req; + + if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + if (!QueueUserWorkItem(&uv_pipe_zero_readfile_thread_proc, + req, + WT_EXECUTELONGFUNCTION)) { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, GetLastError()); + goto error; + } + } else { + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1); + } + + /* Do 0-read */ + result = ReadFile(handle->handle, + &uv_zero_, + 0, + NULL, + &req->u.io.overlapped); + + if (!result && GetLastError() != ERROR_IO_PENDING) { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, GetLastError()); + goto error; + } + + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (!req->event_handle) { + req->event_handle = CreateEvent(NULL, 0, 0, NULL); + if (!req->event_handle) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + } + if (req->wait_handle == INVALID_HANDLE_VALUE) { + if (!RegisterWaitForSingleObject(&req->wait_handle, + req->u.io.overlapped.hEvent, post_completion_read_wait, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD)) { + SET_REQ_ERROR(req, GetLastError()); + goto error; + } + } + } + } + + /* Start the eof timer if there is one */ + eof_timer_start(handle); + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + return; + +error: + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; +} + + +int uv_pipe_read_start(uv_pipe_t* handle, + uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { + uv_loop_t* loop = handle->loop; + + handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb = read_cb; + handle->alloc_cb = alloc_cb; + + /* If reading was stopped and then started again, there could still be a */ + /* read request pending. */ + if (!(handle->flags & UV_HANDLE_READ_PENDING)) + uv_pipe_queue_read(loop, handle); + + return 0; +} + + +static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle, + uv_write_t* req) { + req->next_req = NULL; + if (handle->pipe.conn.non_overlapped_writes_tail) { + req->next_req = + handle->pipe.conn.non_overlapped_writes_tail->next_req; + handle->pipe.conn.non_overlapped_writes_tail->next_req = (uv_req_t*)req; + handle->pipe.conn.non_overlapped_writes_tail = req; + } else { + req->next_req = (uv_req_t*)req; + handle->pipe.conn.non_overlapped_writes_tail = req; + } +} + + +static uv_write_t* uv_remove_non_overlapped_write_req(uv_pipe_t* handle) { + uv_write_t* req; + + if (handle->pipe.conn.non_overlapped_writes_tail) { + req = (uv_write_t*)handle->pipe.conn.non_overlapped_writes_tail->next_req; + + if (req == handle->pipe.conn.non_overlapped_writes_tail) { + handle->pipe.conn.non_overlapped_writes_tail = NULL; + } else { + handle->pipe.conn.non_overlapped_writes_tail->next_req = + req->next_req; + } + + return req; + } else { + /* queue empty */ + return NULL; + } +} + + +static void uv_queue_non_overlapped_write(uv_pipe_t* handle) { + uv_write_t* req = uv_remove_non_overlapped_write_req(handle); + if (req) { + if (!QueueUserWorkItem(&uv_pipe_writefile_thread_proc, + req, + WT_EXECUTELONGFUNCTION)) { + uv_fatal_error(GetLastError(), "QueueUserWorkItem"); + } + } +} + + +static int uv_pipe_write_impl(uv_loop_t* loop, + uv_write_t* req, + uv_pipe_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb) { + int err; + int result; + uv_tcp_t* tcp_send_handle; + uv_write_t* ipc_header_req = NULL; + uv_ipc_frame_uv_stream ipc_frame; + + if (nbufs != 1 && (nbufs != 0 || !send_handle)) { + return ERROR_NOT_SUPPORTED; + } + + /* Only TCP handles are supported for sharing. */ + if (send_handle && ((send_handle->type != UV_TCP) || + (!(send_handle->flags & UV_HANDLE_BOUND) && + !(send_handle->flags & UV_HANDLE_CONNECTION)))) { + return ERROR_NOT_SUPPORTED; + } + + assert(handle->handle != INVALID_HANDLE_VALUE); + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_WRITE; + req->handle = (uv_stream_t*) handle; + req->cb = cb; + req->ipc_header = 0; + req->event_handle = NULL; + req->wait_handle = INVALID_HANDLE_VALUE; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + + if (handle->ipc) { + assert(!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); + ipc_frame.header.flags = 0; + + /* Use the IPC framing protocol. */ + if (send_handle) { + tcp_send_handle = (uv_tcp_t*)send_handle; + + if (handle->pipe.conn.ipc_pid == 0) { + handle->pipe.conn.ipc_pid = uv_current_pid(); + } + + err = uv_tcp_duplicate_socket(tcp_send_handle, handle->pipe.conn.ipc_pid, + &ipc_frame.socket_info_ex.socket_info); + if (err) { + return err; + } + + ipc_frame.socket_info_ex.delayed_error = tcp_send_handle->delayed_error; + + ipc_frame.header.flags |= UV_IPC_TCP_SERVER; + + if (tcp_send_handle->flags & UV_HANDLE_CONNECTION) { + ipc_frame.header.flags |= UV_IPC_TCP_CONNECTION; + } + } + + if (nbufs == 1) { + ipc_frame.header.flags |= UV_IPC_RAW_DATA; + ipc_frame.header.raw_data_length = bufs[0].len; + } + + /* + * Use the provided req if we're only doing a single write. + * If we're doing multiple writes, use ipc_header_write_req to do + * the first write, and then use the provided req for the second write. + */ + if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) { + ipc_header_req = req; + } else { + /* + * Try to use the preallocated write req if it's available. + * Otherwise allocate a new one. + */ + if (handle->pipe.conn.ipc_header_write_req.type != UV_WRITE) { + ipc_header_req = (uv_write_t*)&handle->pipe.conn.ipc_header_write_req; + } else { + ipc_header_req = (uv_write_t*)uv__malloc(sizeof(uv_write_t)); + if (!ipc_header_req) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + } + + uv_req_init(loop, (uv_req_t*) ipc_header_req); + ipc_header_req->type = UV_WRITE; + ipc_header_req->handle = (uv_stream_t*) handle; + ipc_header_req->cb = NULL; + ipc_header_req->ipc_header = 1; + } + + /* Write the header or the whole frame. */ + memset(&ipc_header_req->u.io.overlapped, 0, + sizeof(ipc_header_req->u.io.overlapped)); + + /* Using overlapped IO, but wait for completion before returning. + This write is blocking because ipc_frame is on stack. */ + ipc_header_req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL); + if (!ipc_header_req->u.io.overlapped.hEvent) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + + result = WriteFile(handle->handle, + &ipc_frame, + ipc_frame.header.flags & UV_IPC_TCP_SERVER ? + sizeof(ipc_frame) : sizeof(ipc_frame.header), + NULL, + &ipc_header_req->u.io.overlapped); + if (!result && GetLastError() != ERROR_IO_PENDING) { + err = GetLastError(); + CloseHandle(ipc_header_req->u.io.overlapped.hEvent); + return err; + } + + if (!result) { + /* Request not completed immediately. Wait for it.*/ + if (WaitForSingleObject(ipc_header_req->u.io.overlapped.hEvent, INFINITE) != + WAIT_OBJECT_0) { + err = GetLastError(); + CloseHandle(ipc_header_req->u.io.overlapped.hEvent); + return err; + } + } + ipc_header_req->u.io.queued_bytes = 0; + CloseHandle(ipc_header_req->u.io.overlapped.hEvent); + ipc_header_req->u.io.overlapped.hEvent = NULL; + + REGISTER_HANDLE_REQ(loop, handle, ipc_header_req); + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + + /* If we don't have any raw data to write - we're done. */ + if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) { + return 0; + } + } + + if ((handle->flags & + (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) == + (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) { + DWORD bytes; + result = WriteFile(handle->handle, + bufs[0].base, + bufs[0].len, + &bytes, + NULL); + + if (!result) { + err = GetLastError(); + return err; + } else { + /* Request completed immediately. */ + req->u.io.queued_bytes = 0; + } + + REGISTER_HANDLE_REQ(loop, handle, req); + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + POST_COMPLETION_FOR_REQ(loop, req); + return 0; + } else if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + req->write_buffer = bufs[0]; + uv_insert_non_overlapped_write_req(handle, req); + if (handle->stream.conn.write_reqs_pending == 0) { + uv_queue_non_overlapped_write(handle); + } + + /* Request queued by the kernel. */ + req->u.io.queued_bytes = bufs[0].len; + handle->write_queue_size += req->u.io.queued_bytes; + } else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) { + /* Using overlapped IO, but wait for completion before returning */ + req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL); + if (!req->u.io.overlapped.hEvent) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + + result = WriteFile(handle->handle, + bufs[0].base, + bufs[0].len, + NULL, + &req->u.io.overlapped); + + if (!result && GetLastError() != ERROR_IO_PENDING) { + err = GetLastError(); + CloseHandle(req->u.io.overlapped.hEvent); + return err; + } + + if (result) { + /* Request completed immediately. */ + req->u.io.queued_bytes = 0; + } else { + /* Request queued by the kernel. */ + req->u.io.queued_bytes = bufs[0].len; + handle->write_queue_size += req->u.io.queued_bytes; + if (WaitForSingleObject(req->u.io.overlapped.hEvent, INFINITE) != + WAIT_OBJECT_0) { + err = GetLastError(); + CloseHandle(req->u.io.overlapped.hEvent); + return uv_translate_sys_error(err); + } + } + CloseHandle(req->u.io.overlapped.hEvent); + + REGISTER_HANDLE_REQ(loop, handle, req); + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + return 0; + } else { + result = WriteFile(handle->handle, + bufs[0].base, + bufs[0].len, + NULL, + &req->u.io.overlapped); + + if (!result && GetLastError() != ERROR_IO_PENDING) { + return GetLastError(); + } + + if (result) { + /* Request completed immediately. */ + req->u.io.queued_bytes = 0; + } else { + /* Request queued by the kernel. */ + req->u.io.queued_bytes = bufs[0].len; + handle->write_queue_size += req->u.io.queued_bytes; + } + + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + req->event_handle = CreateEvent(NULL, 0, 0, NULL); + if (!req->event_handle) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + if (!RegisterWaitForSingleObject(&req->wait_handle, + req->u.io.overlapped.hEvent, post_completion_write_wait, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD)) { + return GetLastError(); + } + } + } + + REGISTER_HANDLE_REQ(loop, handle, req); + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + + return 0; +} + + +int uv_pipe_write(uv_loop_t* loop, + uv_write_t* req, + uv_pipe_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb) { + return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, NULL, cb); +} + + +int uv_pipe_write2(uv_loop_t* loop, + uv_write_t* req, + uv_pipe_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb) { + if (!handle->ipc) { + return WSAEINVAL; + } + + return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, send_handle, cb); +} + + +static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle, + uv_buf_t buf) { + /* If there is an eof timer running, we don't need it any more, */ + /* so discard it. */ + eof_timer_destroy(handle); + + handle->flags &= ~UV_HANDLE_READABLE; + uv_read_stop((uv_stream_t*) handle); + + handle->read_cb((uv_stream_t*) handle, UV_EOF, &buf); +} + + +static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error, + uv_buf_t buf) { + /* If there is an eof timer running, we don't need it any more, */ + /* so discard it. */ + eof_timer_destroy(handle); + + uv_read_stop((uv_stream_t*) handle); + + handle->read_cb((uv_stream_t*)handle, uv_translate_sys_error(error), &buf); +} + + +static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle, + int error, uv_buf_t buf) { + if (error == ERROR_BROKEN_PIPE) { + uv_pipe_read_eof(loop, handle, buf); + } else { + uv_pipe_read_error(loop, handle, error, buf); + } +} + + +void uv__pipe_insert_pending_socket(uv_pipe_t* handle, + uv__ipc_socket_info_ex* info, + int tcp_connection) { + uv__ipc_queue_item_t* item; + + item = (uv__ipc_queue_item_t*) uv__malloc(sizeof(*item)); + if (item == NULL) + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + + memcpy(&item->socket_info_ex, info, sizeof(item->socket_info_ex)); + item->tcp_connection = tcp_connection; + QUEUE_INSERT_TAIL(&handle->pipe.conn.pending_ipc_info.queue, &item->member); + handle->pipe.conn.pending_ipc_info.queue_len++; +} + + +void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_req_t* req) { + DWORD bytes, avail; + uv_buf_t buf; + uv_ipc_frame_uv_stream ipc_frame; + + assert(handle->type == UV_NAMED_PIPE); + + handle->flags &= ~UV_HANDLE_READ_PENDING; + eof_timer_stop(handle); + + if (!REQ_SUCCESS(req)) { + /* An error occurred doing the 0-read. */ + if (handle->flags & UV_HANDLE_READING) { + uv_pipe_read_error_or_eof(loop, + handle, + GET_REQ_ERROR(req), + uv_null_buf_); + } + } else { + /* Do non-blocking reads until the buffer is empty */ + while (handle->flags & UV_HANDLE_READING) { + if (!PeekNamedPipe(handle->handle, + NULL, + 0, + NULL, + &avail, + NULL)) { + uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_); + break; + } + + if (avail == 0) { + /* There is nothing to read after all. */ + break; + } + + if (handle->ipc) { + /* Use the IPC framing protocol to read the incoming data. */ + if (handle->pipe.conn.remaining_ipc_rawdata_bytes == 0) { + /* We're reading a new frame. First, read the header. */ + assert(avail >= sizeof(ipc_frame.header)); + + if (!ReadFile(handle->handle, + &ipc_frame.header, + sizeof(ipc_frame.header), + &bytes, + NULL)) { + uv_pipe_read_error_or_eof(loop, handle, GetLastError(), + uv_null_buf_); + break; + } + + assert(bytes == sizeof(ipc_frame.header)); + assert(ipc_frame.header.flags <= (UV_IPC_TCP_SERVER | UV_IPC_RAW_DATA | + UV_IPC_TCP_CONNECTION)); + + if (ipc_frame.header.flags & UV_IPC_TCP_SERVER) { + assert(avail - sizeof(ipc_frame.header) >= + sizeof(ipc_frame.socket_info_ex)); + + /* Read the TCP socket info. */ + if (!ReadFile(handle->handle, + &ipc_frame.socket_info_ex, + sizeof(ipc_frame) - sizeof(ipc_frame.header), + &bytes, + NULL)) { + uv_pipe_read_error_or_eof(loop, handle, GetLastError(), + uv_null_buf_); + break; + } + + assert(bytes == sizeof(ipc_frame) - sizeof(ipc_frame.header)); + + /* Store the pending socket info. */ + uv__pipe_insert_pending_socket( + handle, + &ipc_frame.socket_info_ex, + ipc_frame.header.flags & UV_IPC_TCP_CONNECTION); + } + + if (ipc_frame.header.flags & UV_IPC_RAW_DATA) { + handle->pipe.conn.remaining_ipc_rawdata_bytes = + ipc_frame.header.raw_data_length; + continue; + } + } else { + avail = min(avail, (DWORD)handle->pipe.conn.remaining_ipc_rawdata_bytes); + } + } + + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, avail, &buf); + if (buf.base == NULL || buf.len == 0) { + handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); + break; + } + assert(buf.base != NULL); + + if (ReadFile(handle->handle, + buf.base, + min(buf.len, avail), + &bytes, + NULL)) { + /* Successful read */ + if (handle->ipc) { + assert(handle->pipe.conn.remaining_ipc_rawdata_bytes >= bytes); + handle->pipe.conn.remaining_ipc_rawdata_bytes = + handle->pipe.conn.remaining_ipc_rawdata_bytes - bytes; + } + handle->read_cb((uv_stream_t*)handle, bytes, &buf); + + /* Read again only if bytes == buf.len */ + if (bytes <= buf.len) { + break; + } + } else { + uv_pipe_read_error_or_eof(loop, handle, GetLastError(), buf); + break; + } + } + + /* Post another 0-read if still reading and not closing. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_pipe_queue_read(loop, handle); + } + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_write_t* req) { + int err; + + assert(handle->type == UV_NAMED_PIPE); + + assert(handle->write_queue_size >= req->u.io.queued_bytes); + handle->write_queue_size -= req->u.io.queued_bytes; + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (req->wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(req->wait_handle); + req->wait_handle = INVALID_HANDLE_VALUE; + } + if (req->event_handle) { + CloseHandle(req->event_handle); + req->event_handle = NULL; + } + } + + if (req->ipc_header) { + if (req == &handle->pipe.conn.ipc_header_write_req) { + req->type = UV_UNKNOWN_REQ; + } else { + uv__free(req); + } + } else { + if (req->cb) { + err = GET_REQ_ERROR(req); + req->cb(req, uv_translate_sys_error(err)); + } + } + + handle->stream.conn.write_reqs_pending--; + + if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE && + handle->pipe.conn.non_overlapped_writes_tail) { + assert(handle->stream.conn.write_reqs_pending > 0); + uv_queue_non_overlapped_write(handle); + } + + if (handle->stream.conn.shutdown_req != NULL && + handle->stream.conn.write_reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_req_t* raw_req) { + uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req; + + assert(handle->type == UV_NAMED_PIPE); + + if (handle->flags & UV__HANDLE_CLOSING) { + /* The req->pipeHandle should be freed already in uv_pipe_cleanup(). */ + assert(req->pipeHandle == INVALID_HANDLE_VALUE); + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + if (REQ_SUCCESS(req)) { + assert(req->pipeHandle != INVALID_HANDLE_VALUE); + req->next_pending = handle->pipe.serv.pending_accepts; + handle->pipe.serv.pending_accepts = req; + + if (handle->stream.serv.connection_cb) { + handle->stream.serv.connection_cb((uv_stream_t*)handle, 0); + } + } else { + if (req->pipeHandle != INVALID_HANDLE_VALUE) { + CloseHandle(req->pipeHandle); + req->pipeHandle = INVALID_HANDLE_VALUE; + } + if (!(handle->flags & UV__HANDLE_CLOSING)) { + uv_pipe_queue_accept(loop, handle, req, FALSE); + } + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_connect_t* req) { + int err; + + assert(handle->type == UV_NAMED_PIPE); + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (req->cb) { + err = 0; + if (REQ_SUCCESS(req)) { + uv_pipe_connection_init(handle); + } else { + err = GET_REQ_ERROR(req); + } + req->cb(req, uv_translate_sys_error(err)); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_shutdown_t* req) { + assert(handle->type == UV_NAMED_PIPE); + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (handle->flags & UV_HANDLE_READABLE) { + /* Initialize and optionally start the eof timer. Only do this if the */ + /* pipe is readable and we haven't seen EOF come in ourselves. */ + eof_timer_init(handle); + + /* If reading start the timer right now. */ + /* Otherwise uv_pipe_queue_read will start it. */ + if (handle->flags & UV_HANDLE_READ_PENDING) { + eof_timer_start(handle); + } + + } else { + /* This pipe is not readable. We can just close it to let the other end */ + /* know that we're done writing. */ + close_pipe(handle); + } + + if (req->cb) { + req->cb(req, 0); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +static void eof_timer_init(uv_pipe_t* pipe) { + int r; + + assert(pipe->pipe.conn.eof_timer == NULL); + assert(pipe->flags & UV_HANDLE_CONNECTION); + + pipe->pipe.conn.eof_timer = (uv_timer_t*) uv__malloc(sizeof *pipe->pipe.conn.eof_timer); + + r = uv_timer_init(pipe->loop, pipe->pipe.conn.eof_timer); + assert(r == 0); /* timers can't fail */ + pipe->pipe.conn.eof_timer->data = pipe; + uv_unref((uv_handle_t*) pipe->pipe.conn.eof_timer); +} + + +static void eof_timer_start(uv_pipe_t* pipe) { + assert(pipe->flags & UV_HANDLE_CONNECTION); + + if (pipe->pipe.conn.eof_timer != NULL) { + uv_timer_start(pipe->pipe.conn.eof_timer, eof_timer_cb, eof_timeout, 0); + } +} + + +static void eof_timer_stop(uv_pipe_t* pipe) { + assert(pipe->flags & UV_HANDLE_CONNECTION); + + if (pipe->pipe.conn.eof_timer != NULL) { + uv_timer_stop(pipe->pipe.conn.eof_timer); + } +} + + +static void eof_timer_cb(uv_timer_t* timer) { + uv_pipe_t* pipe = (uv_pipe_t*) timer->data; + uv_loop_t* loop = timer->loop; + + assert(pipe->type == UV_NAMED_PIPE); + + /* This should always be true, since we start the timer only */ + /* in uv_pipe_queue_read after successfully calling ReadFile, */ + /* or in uv_process_pipe_shutdown_req if a read is pending, */ + /* and we always immediately stop the timer in */ + /* uv_process_pipe_read_req. */ + assert(pipe->flags & UV_HANDLE_READ_PENDING); + + /* If there are many packets coming off the iocp then the timer callback */ + /* may be called before the read request is coming off the queue. */ + /* Therefore we check here if the read request has completed but will */ + /* be processed later. */ + if ((pipe->flags & UV_HANDLE_READ_PENDING) && + HasOverlappedIoCompleted(&pipe->read_req.u.io.overlapped)) { + return; + } + + /* Force both ends off the pipe. */ + close_pipe(pipe); + + /* Stop reading, so the pending read that is going to fail will */ + /* not be reported to the user. */ + uv_read_stop((uv_stream_t*) pipe); + + /* Report the eof and update flags. This will get reported even if the */ + /* user stopped reading in the meantime. TODO: is that okay? */ + uv_pipe_read_eof(loop, pipe, uv_null_buf_); +} + + +static void eof_timer_destroy(uv_pipe_t* pipe) { + assert(pipe->flags & UV_HANDLE_CONNECTION); + + if (pipe->pipe.conn.eof_timer) { + uv_close((uv_handle_t*) pipe->pipe.conn.eof_timer, eof_timer_close_cb); + pipe->pipe.conn.eof_timer = NULL; + } +} + + +static void eof_timer_close_cb(uv_handle_t* handle) { + assert(handle->type == UV_TIMER); + uv__free(handle); +} + + +int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { + HANDLE os_handle = uv__get_osfhandle(file); + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_ACCESS_INFORMATION access; + DWORD duplex_flags = 0; + + if (os_handle == INVALID_HANDLE_VALUE) + return UV_EBADF; + + /* In order to avoid closing a stdio file descriptor 0-2, duplicate the + * underlying OS handle and forget about the original fd. + * We could also opt to use the original OS handle and just never close it, + * but then there would be no reliable way to cancel pending read operations + * upon close. + */ + if (file <= 2) { + if (!DuplicateHandle(INVALID_HANDLE_VALUE, + os_handle, + INVALID_HANDLE_VALUE, + &os_handle, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)) + return uv_translate_sys_error(GetLastError()); + file = -1; + } + + /* Determine what kind of permissions we have on this handle. + * Cygwin opens the pipe in message mode, but we can support it, + * just query the access flags and set the stream flags accordingly. + */ + nt_status = pNtQueryInformationFile(os_handle, + &io_status, + &access, + sizeof(access), + FileAccessInformation); + if (nt_status != STATUS_SUCCESS) + return UV_EINVAL; + + if (pipe->ipc) { + if (!(access.AccessFlags & FILE_WRITE_DATA) || + !(access.AccessFlags & FILE_READ_DATA)) { + return UV_EINVAL; + } + } + + if (access.AccessFlags & FILE_WRITE_DATA) + duplex_flags |= UV_HANDLE_WRITABLE; + if (access.AccessFlags & FILE_READ_DATA) + duplex_flags |= UV_HANDLE_READABLE; + + if (os_handle == INVALID_HANDLE_VALUE || + uv_set_pipe_handle(pipe->loop, + pipe, + os_handle, + file, + duplex_flags) == -1) { + return UV_EINVAL; + } + + uv_pipe_connection_init(pipe); + + if (pipe->ipc) { + assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); + pipe->pipe.conn.ipc_pid = uv_parent_pid(); + assert(pipe->pipe.conn.ipc_pid != -1); + } + return 0; +} + + +static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) { + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_NAME_INFORMATION tmp_name_info; + FILE_NAME_INFORMATION* name_info; + WCHAR* name_buf; + unsigned int addrlen; + unsigned int name_size; + unsigned int name_len; + int err; + + name_info = NULL; + + if (handle->handle == INVALID_HANDLE_VALUE) { + *size = 0; + return UV_EINVAL; + } + + uv__pipe_pause_read((uv_pipe_t*)handle); /* cast away const warning */ + + nt_status = pNtQueryInformationFile(handle->handle, + &io_status, + &tmp_name_info, + sizeof tmp_name_info, + FileNameInformation); + if (nt_status == STATUS_BUFFER_OVERFLOW) { + name_size = sizeof(*name_info) + tmp_name_info.FileNameLength; + name_info = uv__malloc(name_size); + if (!name_info) { + *size = 0; + err = UV_ENOMEM; + goto cleanup; + } + + nt_status = pNtQueryInformationFile(handle->handle, + &io_status, + name_info, + name_size, + FileNameInformation); + } + + if (nt_status != STATUS_SUCCESS) { + *size = 0; + err = uv_translate_sys_error(pRtlNtStatusToDosError(nt_status)); + goto error; + } + + if (!name_info) { + /* the struct on stack was used */ + name_buf = tmp_name_info.FileName; + name_len = tmp_name_info.FileNameLength; + } else { + name_buf = name_info->FileName; + name_len = name_info->FileNameLength; + } + + if (name_len == 0) { + *size = 0; + err = 0; + goto error; + } + + name_len /= sizeof(WCHAR); + + /* check how much space we need */ + addrlen = WideCharToMultiByte(CP_UTF8, + 0, + name_buf, + name_len, + NULL, + 0, + NULL, + NULL); + if (!addrlen) { + *size = 0; + err = uv_translate_sys_error(GetLastError()); + goto error; + } else if (pipe_prefix_len + addrlen >= *size) { + /* "\\\\.\\pipe" + name */ + *size = pipe_prefix_len + addrlen + 1; + err = UV_ENOBUFS; + goto error; + } + + memcpy(buffer, pipe_prefix, pipe_prefix_len); + addrlen = WideCharToMultiByte(CP_UTF8, + 0, + name_buf, + name_len, + buffer+pipe_prefix_len, + *size-pipe_prefix_len, + NULL, + NULL); + if (!addrlen) { + *size = 0; + err = uv_translate_sys_error(GetLastError()); + goto error; + } + + addrlen += pipe_prefix_len; + *size = addrlen; + buffer[addrlen] = '\0'; + + err = 0; + goto cleanup; + +error: + uv__free(name_info); + +cleanup: + uv__pipe_unpause_read((uv_pipe_t*)handle); /* cast away const warning */ + return err; +} + + +int uv_pipe_pending_count(uv_pipe_t* handle) { + if (!handle->ipc) + return 0; + return handle->pipe.conn.pending_ipc_info.queue_len; +} + + +int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) { + if (handle->flags & UV_HANDLE_BOUND) + return uv__pipe_getname(handle, buffer, size); + + if (handle->flags & UV_HANDLE_CONNECTION || + handle->handle != INVALID_HANDLE_VALUE) { + *size = 0; + return 0; + } + + return UV_EBADF; +} + + +int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) { + /* emulate unix behaviour */ + if (handle->flags & UV_HANDLE_BOUND) + return UV_ENOTCONN; + + if (handle->handle != INVALID_HANDLE_VALUE) + return uv__pipe_getname(handle, buffer, size); + + return UV_EBADF; +} + + +uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { + if (!handle->ipc) + return UV_UNKNOWN_HANDLE; + if (handle->pipe.conn.pending_ipc_info.queue_len == 0) + return UV_UNKNOWN_HANDLE; + else + return UV_TCP; +} diff --git a/src/win/poll.c b/src/win/poll.c new file mode 100644 index 0000000..d479e52 --- /dev/null +++ b/src/win/poll.c @@ -0,0 +1,646 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = { + {0xe70f1aa0, 0xab8b, 0x11cf, + {0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}, + {0xf9eab0c0, 0x26d4, 0x11d0, + {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}}, + {0x9fc48064, 0x7298, 0x43e4, + {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}} +}; + +typedef struct uv_single_fd_set_s { + unsigned int fd_count; + SOCKET fd_array[1]; +} uv_single_fd_set_t; + + +static OVERLAPPED overlapped_dummy_; +static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT; + +static AFD_POLL_INFO afd_poll_info_dummy_; + + +static void uv__init_overlapped_dummy(void) { + HANDLE event; + + event = CreateEvent(NULL, TRUE, TRUE, NULL); + if (event == NULL) + uv_fatal_error(GetLastError(), "CreateEvent"); + + memset(&overlapped_dummy_, 0, sizeof overlapped_dummy_); + overlapped_dummy_.hEvent = (HANDLE) ((uintptr_t) event | 1); +} + + +static OVERLAPPED* uv__get_overlapped_dummy() { + uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy); + return &overlapped_dummy_; +} + + +static AFD_POLL_INFO* uv__get_afd_poll_info_dummy() { + return &afd_poll_info_dummy_; +} + + +static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { + uv_req_t* req; + AFD_POLL_INFO* afd_poll_info; + DWORD result; + + /* Find a yet unsubmitted req to submit. */ + if (handle->submitted_events_1 == 0) { + req = &handle->poll_req_1; + afd_poll_info = &handle->afd_poll_info_1; + handle->submitted_events_1 = handle->events; + handle->mask_events_1 = 0; + handle->mask_events_2 = handle->events; + } else if (handle->submitted_events_2 == 0) { + req = &handle->poll_req_2; + afd_poll_info = &handle->afd_poll_info_2; + handle->submitted_events_2 = handle->events; + handle->mask_events_1 = handle->events; + handle->mask_events_2 = 0; + } else { + /* Just wait until there's an unsubmitted req. */ + /* This will happen almost immediately as one of the 2 outstanding */ + /* requests is about to return. When this happens, */ + /* uv__fast_poll_process_poll_req will be called, and the pending */ + /* events, if needed, will be processed in a subsequent request. */ + return; + } + + /* Setting Exclusive to TRUE makes the other poll request return if there */ + /* is any. */ + afd_poll_info->Exclusive = TRUE; + afd_poll_info->NumberOfHandles = 1; + afd_poll_info->Timeout.QuadPart = INT64_MAX; + afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket; + afd_poll_info->Handles[0].Status = 0; + afd_poll_info->Handles[0].Events = 0; + + if (handle->events & UV_READABLE) { + afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE | + AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT; + } else { + if (handle->events & UV_DISCONNECT) { + afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT; + } + } + if (handle->events & UV_WRITABLE) { + afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL; + } + + memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped); + + result = uv_msafd_poll((SOCKET) handle->peer_socket, + afd_poll_info, + afd_poll_info, + &req->u.io.overlapped); + if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) { + /* Queue this req, reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, req); + } +} + + +static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) { + AFD_POLL_INFO afd_poll_info; + DWORD result; + + afd_poll_info.Exclusive = TRUE; + afd_poll_info.NumberOfHandles = 1; + afd_poll_info.Timeout.QuadPart = INT64_MAX; + afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket; + afd_poll_info.Handles[0].Status = 0; + afd_poll_info.Handles[0].Events = AFD_POLL_ALL; + + result = uv_msafd_poll(handle->socket, + &afd_poll_info, + uv__get_afd_poll_info_dummy(), + uv__get_overlapped_dummy()); + + if (result == SOCKET_ERROR) { + DWORD error = WSAGetLastError(); + if (error != WSA_IO_PENDING) + return error; + } + + return 0; +} + + +static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, + uv_req_t* req) { + unsigned char mask_events; + AFD_POLL_INFO* afd_poll_info; + + if (req == &handle->poll_req_1) { + afd_poll_info = &handle->afd_poll_info_1; + handle->submitted_events_1 = 0; + mask_events = handle->mask_events_1; + } else if (req == &handle->poll_req_2) { + afd_poll_info = &handle->afd_poll_info_2; + handle->submitted_events_2 = 0; + mask_events = handle->mask_events_2; + } else { + assert(0); + return; + } + + /* Report an error unless the select was just interrupted. */ + if (!REQ_SUCCESS(req)) { + DWORD error = GET_REQ_SOCK_ERROR(req); + if (error != WSAEINTR && handle->events != 0) { + handle->events = 0; /* Stop the watcher */ + handle->poll_cb(handle, uv_translate_sys_error(error), 0); + } + + } else if (afd_poll_info->NumberOfHandles >= 1) { + unsigned char events = 0; + + if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE | + AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) { + events |= UV_READABLE; + if ((afd_poll_info->Handles[0].Events & AFD_POLL_DISCONNECT) != 0) { + events |= UV_DISCONNECT; + } + } + if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND | + AFD_POLL_CONNECT_FAIL)) != 0) { + events |= UV_WRITABLE; + } + + events &= handle->events & ~mask_events; + + if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) { + /* Stop polling. */ + handle->events = 0; + if (uv__is_active(handle)) + uv__handle_stop(handle); + } + + if (events != 0) { + handle->poll_cb(handle, 0, events); + } + } + + if ((handle->events & ~(handle->submitted_events_1 | + handle->submitted_events_2)) != 0) { + uv__fast_poll_submit_poll_req(loop, handle); + } else if ((handle->flags & UV__HANDLE_CLOSING) && + handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { + assert(handle->type == UV_POLL); + assert(!(handle->flags & UV__HANDLE_CLOSING)); + assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); + + handle->events = events; + + if (handle->events != 0) { + uv__handle_start(handle); + } else { + uv__handle_stop(handle); + } + + if ((handle->events & ~(handle->submitted_events_1 | + handle->submitted_events_2)) != 0) { + uv__fast_poll_submit_poll_req(handle->loop, handle); + } + + return 0; +} + + +static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) { + handle->events = 0; + uv__handle_closing(handle); + + if (handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + return 0; + } else { + /* Cancel outstanding poll requests by executing another, unique poll */ + /* request that forces the outstanding ones to return. */ + return uv__fast_poll_cancel_poll_req(loop, handle); + } +} + + +static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp, + WSAPROTOCOL_INFOW* protocol_info) { + SOCKET sock = 0; + + sock = WSASocketW(protocol_info->iAddressFamily, + protocol_info->iSocketType, + protocol_info->iProtocol, + protocol_info, + 0, + WSA_FLAG_OVERLAPPED); + if (sock == INVALID_SOCKET) { + return INVALID_SOCKET; + } + + if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) { + goto error; + }; + + if (CreateIoCompletionPort((HANDLE) sock, + iocp, + (ULONG_PTR) sock, + 0) == NULL) { + goto error; + } + + return sock; + + error: + closesocket(sock); + return INVALID_SOCKET; +} + + +static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop, + WSAPROTOCOL_INFOW* protocol_info) { + int index, i; + SOCKET peer_socket; + + index = -1; + for (i = 0; (size_t) i < ARRAY_SIZE(uv_msafd_provider_ids); i++) { + if (memcmp((void*) &protocol_info->ProviderId, + (void*) &uv_msafd_provider_ids[i], + sizeof protocol_info->ProviderId) == 0) { + index = i; + } + } + + /* Check if the protocol uses an msafd socket. */ + if (index < 0) { + return INVALID_SOCKET; + } + + /* If we didn't (try) to create a peer socket yet, try to make one. Don't */ + /* try again if the peer socket creation failed earlier for the same */ + /* protocol. */ + peer_socket = loop->poll_peer_sockets[index]; + if (peer_socket == 0) { + peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info); + loop->poll_peer_sockets[index] = peer_socket; + } + + return peer_socket; +} + + +static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) { + uv_req_t* req = (uv_req_t*) arg; + uv_poll_t* handle = (uv_poll_t*) req->data; + unsigned char reported_events; + int r; + uv_single_fd_set_t rfds, wfds, efds; + struct timeval timeout; + + assert(handle->type == UV_POLL); + assert(req->type == UV_POLL_REQ); + + if (handle->events & UV_READABLE) { + rfds.fd_count = 1; + rfds.fd_array[0] = handle->socket; + } else { + rfds.fd_count = 0; + } + + if (handle->events & UV_WRITABLE) { + wfds.fd_count = 1; + wfds.fd_array[0] = handle->socket; + efds.fd_count = 1; + efds.fd_array[0] = handle->socket; + } else { + wfds.fd_count = 0; + efds.fd_count = 0; + } + + /* Make the select() time out after 3 minutes. If select() hangs because */ + /* the user closed the socket, we will at least not hang indefinitely. */ + timeout.tv_sec = 3 * 60; + timeout.tv_usec = 0; + + r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout); + if (r == SOCKET_ERROR) { + /* Queue this req, reporting an error. */ + SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError()); + POST_COMPLETION_FOR_REQ(handle->loop, req); + return 0; + } + + reported_events = 0; + + if (r > 0) { + if (rfds.fd_count > 0) { + assert(rfds.fd_count == 1); + assert(rfds.fd_array[0] == handle->socket); + reported_events |= UV_READABLE; + } + + if (wfds.fd_count > 0) { + assert(wfds.fd_count == 1); + assert(wfds.fd_array[0] == handle->socket); + reported_events |= UV_WRITABLE; + } else if (efds.fd_count > 0) { + assert(efds.fd_count == 1); + assert(efds.fd_array[0] == handle->socket); + reported_events |= UV_WRITABLE; + } + } + + SET_REQ_SUCCESS(req); + req->u.io.overlapped.InternalHigh = (DWORD) reported_events; + POST_COMPLETION_FOR_REQ(handle->loop, req); + + return 0; +} + + +static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { + uv_req_t* req; + + /* Find a yet unsubmitted req to submit. */ + if (handle->submitted_events_1 == 0) { + req = &handle->poll_req_1; + handle->submitted_events_1 = handle->events; + handle->mask_events_1 = 0; + handle->mask_events_2 = handle->events; + } else if (handle->submitted_events_2 == 0) { + req = &handle->poll_req_2; + handle->submitted_events_2 = handle->events; + handle->mask_events_1 = handle->events; + handle->mask_events_2 = 0; + } else { + assert(0); + return; + } + + if (!QueueUserWorkItem(uv__slow_poll_thread_proc, + (void*) req, + WT_EXECUTELONGFUNCTION)) { + /* Make this req pending, reporting an error. */ + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, req); + } +} + + + +static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, + uv_req_t* req) { + unsigned char mask_events; + int err; + + if (req == &handle->poll_req_1) { + handle->submitted_events_1 = 0; + mask_events = handle->mask_events_1; + } else if (req == &handle->poll_req_2) { + handle->submitted_events_2 = 0; + mask_events = handle->mask_events_2; + } else { + assert(0); + return; + } + + if (!REQ_SUCCESS(req)) { + /* Error. */ + if (handle->events != 0) { + err = GET_REQ_ERROR(req); + handle->events = 0; /* Stop the watcher */ + handle->poll_cb(handle, uv_translate_sys_error(err), 0); + } + } else { + /* Got some events. */ + int events = req->u.io.overlapped.InternalHigh & handle->events & ~mask_events; + if (events != 0) { + handle->poll_cb(handle, 0, events); + } + } + + if ((handle->events & ~(handle->submitted_events_1 | + handle->submitted_events_2)) != 0) { + uv__slow_poll_submit_poll_req(loop, handle); + } else if ((handle->flags & UV__HANDLE_CLOSING) && + handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { + assert(handle->type == UV_POLL); + assert(!(handle->flags & UV__HANDLE_CLOSING)); + assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); + + handle->events = events; + + if (handle->events != 0) { + uv__handle_start(handle); + } else { + uv__handle_stop(handle); + } + + if ((handle->events & + ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) { + uv__slow_poll_submit_poll_req(handle->loop, handle); + } + + return 0; +} + + +static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) { + handle->events = 0; + uv__handle_closing(handle); + + if (handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + + return 0; +} + + +int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { + return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd)); +} + + +int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, + uv_os_sock_t socket) { + WSAPROTOCOL_INFOW protocol_info; + int len; + SOCKET peer_socket, base_socket; + DWORD bytes; + DWORD yes = 1; + + /* Set the socket to nonblocking mode */ + if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) + return uv_translate_sys_error(WSAGetLastError()); + + /* Try to obtain a base handle for the socket. This increases this chances */ + /* that we find an AFD handle and are able to use the fast poll mechanism. */ + /* This will always fail on windows XP/2k3, since they don't support the */ + /* SIO_BASE_HANDLE ioctl. */ +#ifndef NDEBUG + base_socket = INVALID_SOCKET; +#endif + + if (WSAIoctl(socket, + SIO_BASE_HANDLE, + NULL, + 0, + &base_socket, + sizeof base_socket, + &bytes, + NULL, + NULL) == 0) { + assert(base_socket != 0 && base_socket != INVALID_SOCKET); + socket = base_socket; + } + + uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL); + handle->socket = socket; + handle->events = 0; + + /* Obtain protocol information about the socket. */ + len = sizeof protocol_info; + if (getsockopt(socket, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &len) != 0) { + return uv_translate_sys_error(WSAGetLastError()); + } + + /* Get the peer socket that is needed to enable fast poll. If the returned */ + /* value is NULL, the protocol is not implemented by MSAFD and we'll have */ + /* to use slow mode. */ + peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info); + + if (peer_socket != INVALID_SOCKET) { + /* Initialize fast poll specific fields. */ + handle->peer_socket = peer_socket; + } else { + /* Initialize slow poll specific fields. */ + handle->flags |= UV_HANDLE_POLL_SLOW; + } + + /* Initialize 2 poll reqs. */ + handle->submitted_events_1 = 0; + uv_req_init(loop, (uv_req_t*) &(handle->poll_req_1)); + handle->poll_req_1.type = UV_POLL_REQ; + handle->poll_req_1.data = handle; + + handle->submitted_events_2 = 0; + uv_req_init(loop, (uv_req_t*) &(handle->poll_req_2)); + handle->poll_req_2.type = UV_POLL_REQ; + handle->poll_req_2.data = handle; + + return 0; +} + + +int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) { + int err; + + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + err = uv__fast_poll_set(handle->loop, handle, events); + } else { + err = uv__slow_poll_set(handle->loop, handle, events); + } + + if (err) { + return uv_translate_sys_error(err); + } + + handle->poll_cb = cb; + + return 0; +} + + +int uv_poll_stop(uv_poll_t* handle) { + int err; + + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + err = uv__fast_poll_set(handle->loop, handle, 0); + } else { + err = uv__slow_poll_set(handle->loop, handle, 0); + } + + return uv_translate_sys_error(err); +} + + +void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) { + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + uv__fast_poll_process_poll_req(loop, handle, req); + } else { + uv__slow_poll_process_poll_req(loop, handle, req); + } +} + + +int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) { + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + return uv__fast_poll_close(loop, handle); + } else { + return uv__slow_poll_close(loop, handle); + } +} + + +void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) { + assert(handle->flags & UV__HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + assert(handle->submitted_events_1 == 0); + assert(handle->submitted_events_2 == 0); + + uv__handle_close(handle); +} diff --git a/src/win/process-stdio.c b/src/win/process-stdio.c new file mode 100644 index 0000000..e3c06f5 --- /dev/null +++ b/src/win/process-stdio.c @@ -0,0 +1,510 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" + + +/* + * The `child_stdio_buffer` buffer has the following layout: + * int number_of_fds + * unsigned char crt_flags[number_of_fds] + * HANDLE os_handle[number_of_fds] + */ +#define CHILD_STDIO_SIZE(count) \ + (sizeof(int) + \ + sizeof(unsigned char) * (count) + \ + sizeof(uintptr_t) * (count)) + +#define CHILD_STDIO_COUNT(buffer) \ + *((unsigned int*) (buffer)) + +#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \ + *((unsigned char*) (buffer) + sizeof(int) + fd) + +#define CHILD_STDIO_HANDLE(buffer, fd) \ + *((HANDLE*) ((unsigned char*) (buffer) + \ + sizeof(int) + \ + sizeof(unsigned char) * \ + CHILD_STDIO_COUNT((buffer)) + \ + sizeof(HANDLE) * (fd))) + + +/* CRT file descriptor mode flags */ +#define FOPEN 0x01 +#define FEOFLAG 0x02 +#define FCRLF 0x04 +#define FPIPE 0x08 +#define FNOINHERIT 0x10 +#define FAPPEND 0x20 +#define FDEV 0x40 +#define FTEXT 0x80 + + +/* + * Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited + * the parent process. Don't check for errors - the stdio handles may not be + * valid, or may be closed already. There is no guarantee that this function + * does a perfect job. + */ +void uv_disable_stdio_inheritance(void) { + HANDLE handle; + STARTUPINFOW si; + + /* Make the windows stdio handles non-inheritable. */ + handle = GetStdHandle(STD_INPUT_HANDLE); + if (handle != NULL && handle != INVALID_HANDLE_VALUE) + SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); + + handle = GetStdHandle(STD_OUTPUT_HANDLE); + if (handle != NULL && handle != INVALID_HANDLE_VALUE) + SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); + + handle = GetStdHandle(STD_ERROR_HANDLE); + if (handle != NULL && handle != INVALID_HANDLE_VALUE) + SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); + + /* Make inherited CRT FDs non-inheritable. */ + GetStartupInfoW(&si); + if (uv__stdio_verify(si.lpReserved2, si.cbReserved2)) + uv__stdio_noinherit(si.lpReserved2); +} + + +static int uv__create_stdio_pipe_pair(uv_loop_t* loop, + uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) { + char pipe_name[64]; + SECURITY_ATTRIBUTES sa; + DWORD server_access = 0; + DWORD client_access = 0; + HANDLE child_pipe = INVALID_HANDLE_VALUE; + int err; + + if (flags & UV_READABLE_PIPE) { + /* The server needs inbound access too, otherwise CreateNamedPipe() */ + /* won't give us the FILE_READ_ATTRIBUTES permission. We need that to */ + /* probe the state of the write buffer when we're trying to shutdown */ + /* the pipe. */ + server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND; + client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; + } + if (flags & UV_WRITABLE_PIPE) { + server_access |= PIPE_ACCESS_INBOUND; + client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES; + } + + /* Create server pipe handle. */ + err = uv_stdio_pipe_server(loop, + server_pipe, + server_access, + pipe_name, + sizeof(pipe_name)); + if (err) + goto error; + + /* Create child pipe handle. */ + sa.nLength = sizeof sa; + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + child_pipe = CreateFileA(pipe_name, + client_access, + 0, + &sa, + OPEN_EXISTING, + server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0, + NULL); + if (child_pipe == INVALID_HANDLE_VALUE) { + err = GetLastError(); + goto error; + } + +#ifndef NDEBUG + /* Validate that the pipe was opened in the right mode. */ + { + DWORD mode; + BOOL r = GetNamedPipeHandleState(child_pipe, + &mode, + NULL, + NULL, + NULL, + NULL, + 0); + assert(r == TRUE); + assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT)); + } +#endif + + /* Do a blocking ConnectNamedPipe. This should not block because we have */ + /* both ends of the pipe created. */ + if (!ConnectNamedPipe(server_pipe->handle, NULL)) { + if (GetLastError() != ERROR_PIPE_CONNECTED) { + err = GetLastError(); + goto error; + } + } + + /* The server end is now readable and/or writable. */ + if (flags & UV_READABLE_PIPE) + server_pipe->flags |= UV_HANDLE_WRITABLE; + if (flags & UV_WRITABLE_PIPE) + server_pipe->flags |= UV_HANDLE_READABLE; + + *child_pipe_ptr = child_pipe; + return 0; + + error: + if (server_pipe->handle != INVALID_HANDLE_VALUE) { + uv_pipe_cleanup(loop, server_pipe); + } + + if (child_pipe != INVALID_HANDLE_VALUE) { + CloseHandle(child_pipe); + } + + return err; +} + + +static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) { + HANDLE current_process; + + + /* _get_osfhandle will sometimes return -2 in case of an error. This seems */ + /* to happen when fd <= 2 and the process' corresponding stdio handle is */ + /* set to NULL. Unfortunately DuplicateHandle will happily duplicate */ + /* (HANDLE) -2, so this situation goes unnoticed until someone tries to */ + /* use the duplicate. Therefore we filter out known-invalid handles here. */ + if (handle == INVALID_HANDLE_VALUE || + handle == NULL || + handle == (HANDLE) -2) { + *dup = INVALID_HANDLE_VALUE; + return ERROR_INVALID_HANDLE; + } + + current_process = GetCurrentProcess(); + + if (!DuplicateHandle(current_process, + handle, + current_process, + dup, + 0, + TRUE, + DUPLICATE_SAME_ACCESS)) { + *dup = INVALID_HANDLE_VALUE; + return GetLastError(); + } + + return 0; +} + + +static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) { + HANDLE handle; + + if (fd == -1) { + *dup = INVALID_HANDLE_VALUE; + return ERROR_INVALID_HANDLE; + } + + handle = uv__get_osfhandle(fd); + return uv__duplicate_handle(loop, handle, dup); +} + + +int uv__create_nul_handle(HANDLE* handle_ptr, + DWORD access) { + HANDLE handle; + SECURITY_ATTRIBUTES sa; + + sa.nLength = sizeof sa; + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + handle = CreateFileW(L"NUL", + access, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sa, + OPEN_EXISTING, + 0, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + return GetLastError(); + } + + *handle_ptr = handle; + return 0; +} + + +int uv__stdio_create(uv_loop_t* loop, + const uv_process_options_t* options, + BYTE** buffer_ptr) { + BYTE* buffer; + int count, i; + int err; + + count = options->stdio_count; + + if (count < 0 || count > 255) { + /* Only support FDs 0-255 */ + return ERROR_NOT_SUPPORTED; + } else if (count < 3) { + /* There should always be at least 3 stdio handles. */ + count = 3; + } + + /* Allocate the child stdio buffer */ + buffer = (BYTE*) uv__malloc(CHILD_STDIO_SIZE(count)); + if (buffer == NULL) { + return ERROR_OUTOFMEMORY; + } + + /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */ + /* clean up on failure. */ + CHILD_STDIO_COUNT(buffer) = count; + for (i = 0; i < count; i++) { + CHILD_STDIO_CRT_FLAGS(buffer, i) = 0; + CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE; + } + + for (i = 0; i < count; i++) { + uv_stdio_container_t fdopt; + if (i < options->stdio_count) { + fdopt = options->stdio[i]; + } else { + fdopt.flags = UV_IGNORE; + } + + switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | + UV_INHERIT_STREAM)) { + case UV_IGNORE: + /* Starting a process with no stdin/stout/stderr can confuse it. */ + /* So no matter what the user specified, we make sure the first */ + /* three FDs are always open in their typical modes, e.g. stdin */ + /* be readable and stdout/err should be writable. For FDs > 2, don't */ + /* do anything - all handles in the stdio buffer are initialized with */ + /* INVALID_HANDLE_VALUE, which should be okay. */ + if (i <= 2) { + DWORD access = (i == 0) ? FILE_GENERIC_READ : + FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES; + + err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i), + access); + if (err) + goto error; + + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; + } + break; + + case UV_CREATE_PIPE: { + /* Create a pair of two connected pipe ends; one end is turned into */ + /* an uv_pipe_t for use by the parent. The other one is given to */ + /* the child. */ + uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream; + HANDLE child_pipe = INVALID_HANDLE_VALUE; + + /* Create a new, connected pipe pair. stdio[i].stream should point */ + /* to an uninitialized, but not connected pipe handle. */ + assert(fdopt.data.stream->type == UV_NAMED_PIPE); + assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION)); + assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER)); + + err = uv__create_stdio_pipe_pair(loop, + parent_pipe, + &child_pipe, + fdopt.flags); + if (err) + goto error; + + CHILD_STDIO_HANDLE(buffer, i) = child_pipe; + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE; + break; + } + + case UV_INHERIT_FD: { + /* Inherit a raw FD. */ + HANDLE child_handle; + + /* Make an inheritable duplicate of the handle. */ + err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle); + if (err) { + /* If fdopt.data.fd is not valid and fd fd <= 2, then ignore the */ + /* error. */ + if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) { + CHILD_STDIO_CRT_FLAGS(buffer, i) = 0; + CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE; + break; + } + goto error; + } + + /* Figure out what the type is. */ + switch (GetFileType(child_handle)) { + case FILE_TYPE_DISK: + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN; + break; + + case FILE_TYPE_PIPE: + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE; + + case FILE_TYPE_CHAR: + case FILE_TYPE_REMOTE: + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; + break; + + case FILE_TYPE_UNKNOWN: + if (GetLastError() != 0) { + err = GetLastError(); + CloseHandle(child_handle); + goto error; + } + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; + break; + + default: + assert(0); + return -1; + } + + CHILD_STDIO_HANDLE(buffer, i) = child_handle; + break; + } + + case UV_INHERIT_STREAM: { + /* Use an existing stream as the stdio handle for the child. */ + HANDLE stream_handle, child_handle; + unsigned char crt_flags; + uv_stream_t* stream = fdopt.data.stream; + + /* Leech the handle out of the stream. */ + if (stream->type == UV_TTY) { + stream_handle = ((uv_tty_t*) stream)->handle; + crt_flags = FOPEN | FDEV; + } else if (stream->type == UV_NAMED_PIPE && + stream->flags & UV_HANDLE_CONNECTION) { + stream_handle = ((uv_pipe_t*) stream)->handle; + crt_flags = FOPEN | FPIPE; + } else { + stream_handle = INVALID_HANDLE_VALUE; + crt_flags = 0; + } + + if (stream_handle == NULL || + stream_handle == INVALID_HANDLE_VALUE) { + /* The handle is already closed, or not yet created, or the */ + /* stream type is not supported. */ + err = ERROR_NOT_SUPPORTED; + goto error; + } + + /* Make an inheritable copy of the handle. */ + err = uv__duplicate_handle(loop, stream_handle, &child_handle); + if (err) + goto error; + + CHILD_STDIO_HANDLE(buffer, i) = child_handle; + CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags; + break; + } + + default: + assert(0); + return -1; + } + } + + *buffer_ptr = buffer; + return 0; + + error: + uv__stdio_destroy(buffer); + return err; +} + + +void uv__stdio_destroy(BYTE* buffer) { + int i, count; + + count = CHILD_STDIO_COUNT(buffer); + for (i = 0; i < count; i++) { + HANDLE handle = CHILD_STDIO_HANDLE(buffer, i); + if (handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle); + } + } + + uv__free(buffer); +} + + +void uv__stdio_noinherit(BYTE* buffer) { + int i, count; + + count = CHILD_STDIO_COUNT(buffer); + for (i = 0; i < count; i++) { + HANDLE handle = CHILD_STDIO_HANDLE(buffer, i); + if (handle != INVALID_HANDLE_VALUE) { + SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); + } + } +} + + +int uv__stdio_verify(BYTE* buffer, WORD size) { + unsigned int count; + + /* Check the buffer pointer. */ + if (buffer == NULL) + return 0; + + /* Verify that the buffer is at least big enough to hold the count. */ + if (size < CHILD_STDIO_SIZE(0)) + return 0; + + /* Verify if the count is within range. */ + count = CHILD_STDIO_COUNT(buffer); + if (count > 256) + return 0; + + /* Verify that the buffer size is big enough to hold info for N FDs. */ + if (size < CHILD_STDIO_SIZE(count)) + return 0; + + return 1; +} + + +WORD uv__stdio_size(BYTE* buffer) { + return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer))); +} + + +HANDLE uv__stdio_handle(BYTE* buffer, int fd) { + return CHILD_STDIO_HANDLE(buffer, fd); +} diff --git a/src/win/process.c b/src/win/process.c new file mode 100644 index 0000000..855c374 --- /dev/null +++ b/src/win/process.c @@ -0,0 +1,1247 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include /* alloca */ + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +#define SIGKILL 9 + + +typedef struct env_var { + const WCHAR* const wide; + const WCHAR* const wide_eq; + const size_t len; /* including null or '=' */ +} env_var_t; + +#define E_V(str) { L##str, L##str L"=", sizeof(str) } + +static const env_var_t required_vars[] = { /* keep me sorted */ + E_V("HOMEDRIVE"), + E_V("HOMEPATH"), + E_V("LOGONSERVER"), + E_V("PATH"), + E_V("SYSTEMDRIVE"), + E_V("SYSTEMROOT"), + E_V("TEMP"), + E_V("USERDOMAIN"), + E_V("USERNAME"), + E_V("USERPROFILE"), + E_V("WINDIR"), +}; +static size_t n_required_vars = ARRAY_SIZE(required_vars); + + +static HANDLE uv_global_job_handle_; +static uv_once_t uv_global_job_handle_init_guard_ = UV_ONCE_INIT; + + +static void uv__init_global_job_handle(void) { + /* Create a job object and set it up to kill all contained processes when + * it's closed. Since this handle is made non-inheritable and we're not + * giving it to anyone, we're the only process holding a reference to it. + * That means that if this process exits it is closed and all the processes + * it contains are killed. All processes created with uv_spawn that are not + * spawned with the UV_PROCESS_DETACHED flag are assigned to this job. + * + * We're setting the JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag so only the + * processes that we explicitly add are affected, and *their* subprocesses + * are not. This ensures that our child processes are not limited in their + * ability to use job control on Windows versions that don't deal with + * nested jobs (prior to Windows 8 / Server 2012). It also lets our child + * processes created detached processes without explicitly breaking away + * from job control (which uv_spawn doesn't, either). + */ + SECURITY_ATTRIBUTES attr; + JOBOBJECT_EXTENDED_LIMIT_INFORMATION info; + + memset(&attr, 0, sizeof attr); + attr.bInheritHandle = FALSE; + + memset(&info, 0, sizeof info); + info.BasicLimitInformation.LimitFlags = + JOB_OBJECT_LIMIT_BREAKAWAY_OK | + JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK | + JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION | + JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + + uv_global_job_handle_ = CreateJobObjectW(&attr, NULL); + if (uv_global_job_handle_ == NULL) + uv_fatal_error(GetLastError(), "CreateJobObjectW"); + + if (!SetInformationJobObject(uv_global_job_handle_, + JobObjectExtendedLimitInformation, + &info, + sizeof info)) + uv_fatal_error(GetLastError(), "SetInformationJobObject"); +} + + +static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) { + int ws_len, r; + WCHAR* ws; + + ws_len = MultiByteToWideChar(CP_UTF8, + 0, + s, + -1, + NULL, + 0); + if (ws_len <= 0) { + return GetLastError(); + } + + ws = (WCHAR*) uv__malloc(ws_len * sizeof(WCHAR)); + if (ws == NULL) { + return ERROR_OUTOFMEMORY; + } + + r = MultiByteToWideChar(CP_UTF8, + 0, + s, + -1, + ws, + ws_len); + assert(r == ws_len); + + *ws_ptr = ws; + return 0; +} + + +static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) { + uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS); + handle->exit_cb = NULL; + handle->pid = 0; + handle->exit_signal = 0; + handle->wait_handle = INVALID_HANDLE_VALUE; + handle->process_handle = INVALID_HANDLE_VALUE; + handle->child_stdio_buffer = NULL; + handle->exit_cb_pending = 0; + + uv_req_init(loop, (uv_req_t*)&handle->exit_req); + handle->exit_req.type = UV_PROCESS_EXIT; + handle->exit_req.data = handle; +} + + +/* + * Path search functions + */ + +/* + * Helper function for search_path + */ +static WCHAR* search_path_join_test(const WCHAR* dir, + size_t dir_len, + const WCHAR* name, + size_t name_len, + const WCHAR* ext, + size_t ext_len, + const WCHAR* cwd, + size_t cwd_len) { + WCHAR *result, *result_pos; + DWORD attrs; + if (dir_len > 2 && dir[0] == L'\\' && dir[1] == L'\\') { + /* It's a UNC path so ignore cwd */ + cwd_len = 0; + } else if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) { + /* It's a full path without drive letter, use cwd's drive letter only */ + cwd_len = 2; + } else if (dir_len >= 2 && dir[1] == L':' && + (dir_len < 3 || (dir[2] != L'/' && dir[2] != L'\\'))) { + /* It's a relative path with drive letter (ext.g. D:../some/file) + * Replace drive letter in dir by full cwd if it points to the same drive, + * otherwise use the dir only. + */ + if (cwd_len < 2 || _wcsnicmp(cwd, dir, 2) != 0) { + cwd_len = 0; + } else { + dir += 2; + dir_len -= 2; + } + } else if (dir_len > 2 && dir[1] == L':') { + /* It's an absolute path with drive letter + * Don't use the cwd at all + */ + cwd_len = 0; + } + + /* Allocate buffer for output */ + result = result_pos = (WCHAR*)uv__malloc(sizeof(WCHAR) * + (cwd_len + 1 + dir_len + 1 + name_len + 1 + ext_len + 1)); + + /* Copy cwd */ + wcsncpy(result_pos, cwd, cwd_len); + result_pos += cwd_len; + + /* Add a path separator if cwd didn't end with one */ + if (cwd_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) { + result_pos[0] = L'\\'; + result_pos++; + } + + /* Copy dir */ + wcsncpy(result_pos, dir, dir_len); + result_pos += dir_len; + + /* Add a separator if the dir didn't end with one */ + if (dir_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) { + result_pos[0] = L'\\'; + result_pos++; + } + + /* Copy filename */ + wcsncpy(result_pos, name, name_len); + result_pos += name_len; + + if (ext_len) { + /* Add a dot if the filename didn't end with one */ + if (name_len && result_pos[-1] != '.') { + result_pos[0] = L'.'; + result_pos++; + } + + /* Copy extension */ + wcsncpy(result_pos, ext, ext_len); + result_pos += ext_len; + } + + /* Null terminator */ + result_pos[0] = L'\0'; + + attrs = GetFileAttributesW(result); + + if (attrs != INVALID_FILE_ATTRIBUTES && + !(attrs & FILE_ATTRIBUTE_DIRECTORY)) { + return result; + } + + uv__free(result); + return NULL; +} + + +/* + * Helper function for search_path + */ +static WCHAR* path_search_walk_ext(const WCHAR *dir, + size_t dir_len, + const WCHAR *name, + size_t name_len, + WCHAR *cwd, + size_t cwd_len, + int name_has_ext) { + WCHAR* result; + + /* If the name itself has a nonempty extension, try this extension first */ + if (name_has_ext) { + result = search_path_join_test(dir, dir_len, + name, name_len, + L"", 0, + cwd, cwd_len); + if (result != NULL) { + return result; + } + } + + /* Try .com extension */ + result = search_path_join_test(dir, dir_len, + name, name_len, + L"com", 3, + cwd, cwd_len); + if (result != NULL) { + return result; + } + + /* Try .exe extension */ + result = search_path_join_test(dir, dir_len, + name, name_len, + L"exe", 3, + cwd, cwd_len); + if (result != NULL) { + return result; + } + + return NULL; +} + + +/* + * search_path searches the system path for an executable filename - + * the windows API doesn't provide this as a standalone function nor as an + * option to CreateProcess. + * + * It tries to return an absolute filename. + * + * Furthermore, it tries to follow the semantics that cmd.exe, with this + * exception that PATHEXT environment variable isn't used. Since CreateProcess + * can start only .com and .exe files, only those extensions are tried. This + * behavior equals that of msvcrt's spawn functions. + * + * - Do not search the path if the filename already contains a path (either + * relative or absolute). + * + * - If there's really only a filename, check the current directory for file, + * then search all path directories. + * + * - If filename specified has *any* extension, search for the file with the + * specified extension first. + * + * - If the literal filename is not found in a directory, try *appending* + * (not replacing) .com first and then .exe. + * + * - The path variable may contain relative paths; relative paths are relative + * to the cwd. + * + * - Directories in path may or may not end with a trailing backslash. + * + * - CMD does not trim leading/trailing whitespace from path/pathex entries + * nor from the environment variables as a whole. + * + * - When cmd.exe cannot read a directory, it will just skip it and go on + * searching. However, unlike posix-y systems, it will happily try to run a + * file that is not readable/executable; if the spawn fails it will not + * continue searching. + * + * UNC path support: we are dealing with UNC paths in both the path and the + * filename. This is a deviation from what cmd.exe does (it does not let you + * start a program by specifying an UNC path on the command line) but this is + * really a pointless restriction. + * + */ +static WCHAR* search_path(const WCHAR *file, + WCHAR *cwd, + const WCHAR *path) { + int file_has_dir; + WCHAR* result = NULL; + WCHAR *file_name_start; + WCHAR *dot; + const WCHAR *dir_start, *dir_end, *dir_path; + size_t dir_len; + int name_has_ext; + + size_t file_len = wcslen(file); + size_t cwd_len = wcslen(cwd); + + /* If the caller supplies an empty filename, + * we're not gonna return c:\windows\.exe -- GFY! + */ + if (file_len == 0 + || (file_len == 1 && file[0] == L'.')) { + return NULL; + } + + /* Find the start of the filename so we can split the directory from the */ + /* name. */ + for (file_name_start = (WCHAR*)file + file_len; + file_name_start > file + && file_name_start[-1] != L'\\' + && file_name_start[-1] != L'/' + && file_name_start[-1] != L':'; + file_name_start--); + + file_has_dir = file_name_start != file; + + /* Check if the filename includes an extension */ + dot = wcschr(file_name_start, L'.'); + name_has_ext = (dot != NULL && dot[1] != L'\0'); + + if (file_has_dir) { + /* The file has a path inside, don't use path */ + result = path_search_walk_ext( + file, file_name_start - file, + file_name_start, file_len - (file_name_start - file), + cwd, cwd_len, + name_has_ext); + + } else { + dir_end = path; + + /* The file is really only a name; look in cwd first, then scan path */ + result = path_search_walk_ext(L"", 0, + file, file_len, + cwd, cwd_len, + name_has_ext); + + while (result == NULL) { + if (*dir_end == L'\0') { + break; + } + + /* Skip the separator that dir_end now points to */ + if (dir_end != path || *path == L';') { + dir_end++; + } + + /* Next slice starts just after where the previous one ended */ + dir_start = dir_end; + + /* Slice until the next ; or \0 is found */ + dir_end = wcschr(dir_start, L';'); + if (dir_end == NULL) { + dir_end = wcschr(dir_start, L'\0'); + } + + /* If the slice is zero-length, don't bother */ + if (dir_end - dir_start == 0) { + continue; + } + + dir_path = dir_start; + dir_len = dir_end - dir_start; + + /* Adjust if the path is quoted. */ + if (dir_path[0] == '"' || dir_path[0] == '\'') { + ++dir_path; + --dir_len; + } + + if (dir_path[dir_len - 1] == '"' || dir_path[dir_len - 1] == '\'') { + --dir_len; + } + + result = path_search_walk_ext(dir_path, dir_len, + file, file_len, + cwd, cwd_len, + name_has_ext); + } + } + + return result; +} + + +/* + * Quotes command line arguments + * Returns a pointer to the end (next char to be written) of the buffer + */ +WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) { + size_t len = wcslen(source); + size_t i; + int quote_hit; + WCHAR* start; + + if (len == 0) { + /* Need double quotation for empty argument */ + *(target++) = L'"'; + *(target++) = L'"'; + return target; + } + + if (NULL == wcspbrk(source, L" \t\"")) { + /* No quotation needed */ + wcsncpy(target, source, len); + target += len; + return target; + } + + if (NULL == wcspbrk(source, L"\"\\")) { + /* + * No embedded double quotes or backlashes, so I can just wrap + * quote marks around the whole thing. + */ + *(target++) = L'"'; + wcsncpy(target, source, len); + target += len; + *(target++) = L'"'; + return target; + } + + /* + * Expected input/output: + * input : hello"world + * output: "hello\"world" + * input : hello""world + * output: "hello\"\"world" + * input : hello\world + * output: hello\world + * input : hello\\world + * output: hello\\world + * input : hello\"world + * output: "hello\\\"world" + * input : hello\\"world + * output: "hello\\\\\"world" + * input : hello world\ + * output: "hello world\" + */ + + *(target++) = L'"'; + start = target; + quote_hit = 1; + + for (i = len; i > 0; --i) { + *(target++) = source[i - 1]; + + if (quote_hit && source[i - 1] == L'\\') { + *(target++) = L'\\'; + } else if(source[i - 1] == L'"') { + quote_hit = 1; + *(target++) = L'\\'; + } else { + quote_hit = 0; + } + } + target[0] = L'\0'; + wcsrev(start); + *(target++) = L'"'; + return target; +} + + +int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) { + char** arg; + WCHAR* dst = NULL; + WCHAR* temp_buffer = NULL; + size_t dst_len = 0; + size_t temp_buffer_len = 0; + WCHAR* pos; + int arg_count = 0; + int err = 0; + + /* Count the required size. */ + for (arg = args; *arg; arg++) { + DWORD arg_len; + + arg_len = MultiByteToWideChar(CP_UTF8, + 0, + *arg, + -1, + NULL, + 0); + if (arg_len == 0) { + return GetLastError(); + } + + dst_len += arg_len; + + if (arg_len > temp_buffer_len) + temp_buffer_len = arg_len; + + arg_count++; + } + + /* Adjust for potential quotes. Also assume the worst-case scenario */ + /* that every character needs escaping, so we need twice as much space. */ + dst_len = dst_len * 2 + arg_count * 2; + + /* Allocate buffer for the final command line. */ + dst = (WCHAR*) uv__malloc(dst_len * sizeof(WCHAR)); + if (dst == NULL) { + err = ERROR_OUTOFMEMORY; + goto error; + } + + /* Allocate temporary working buffer. */ + temp_buffer = (WCHAR*) uv__malloc(temp_buffer_len * sizeof(WCHAR)); + if (temp_buffer == NULL) { + err = ERROR_OUTOFMEMORY; + goto error; + } + + pos = dst; + for (arg = args; *arg; arg++) { + DWORD arg_len; + + /* Convert argument to wide char. */ + arg_len = MultiByteToWideChar(CP_UTF8, + 0, + *arg, + -1, + temp_buffer, + (int) (dst + dst_len - pos)); + if (arg_len == 0) { + err = GetLastError(); + goto error; + } + + if (verbatim_arguments) { + /* Copy verbatim. */ + wcscpy(pos, temp_buffer); + pos += arg_len - 1; + } else { + /* Quote/escape, if needed. */ + pos = quote_cmd_arg(temp_buffer, pos); + } + + *pos++ = *(arg + 1) ? L' ' : L'\0'; + } + + uv__free(temp_buffer); + + *dst_ptr = dst; + return 0; + +error: + uv__free(dst); + uv__free(temp_buffer); + return err; +} + + +int env_strncmp(const wchar_t* a, int na, const wchar_t* b) { + wchar_t* a_eq; + wchar_t* b_eq; + wchar_t* A; + wchar_t* B; + int nb; + int r; + + if (na < 0) { + a_eq = wcschr(a, L'='); + assert(a_eq); + na = (int)(long)(a_eq - a); + } else { + na--; + } + b_eq = wcschr(b, L'='); + assert(b_eq); + nb = b_eq - b; + + A = alloca((na+1) * sizeof(wchar_t)); + B = alloca((nb+1) * sizeof(wchar_t)); + + r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, a, na, A, na); + assert(r==na); + A[na] = L'\0'; + r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, b, nb, B, nb); + assert(r==nb); + B[nb] = L'\0'; + + while (1) { + wchar_t AA = *A++; + wchar_t BB = *B++; + if (AA < BB) { + return -1; + } else if (AA > BB) { + return 1; + } else if (!AA && !BB) { + return 0; + } + } +} + + +static int qsort_wcscmp(const void *a, const void *b) { + wchar_t* astr = *(wchar_t* const*)a; + wchar_t* bstr = *(wchar_t* const*)b; + return env_strncmp(astr, -1, bstr); +} + + +/* + * The way windows takes environment variables is different than what C does; + * Windows wants a contiguous block of null-terminated strings, terminated + * with an additional null. + * + * Windows has a few "essential" environment variables. winsock will fail + * to initialize if SYSTEMROOT is not defined; some APIs make reference to + * TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that + * these get defined if the input environment block does not contain any + * values for them. + * + * Also add variables known to Cygwin to be required for correct + * subprocess operation in many cases: + * https://github.com/Alexpux/Cygwin/blob/b266b04fbbd3a595f02ea149e4306d3ab9b1fe3d/winsup/cygwin/environ.cc#L955 + * + */ +int make_program_env(char* env_block[], WCHAR** dst_ptr) { + WCHAR* dst; + WCHAR* ptr; + char** env; + size_t env_len = 0; + int len; + size_t i; + DWORD var_size; + size_t env_block_count = 1; /* 1 for null-terminator */ + WCHAR* dst_copy; + WCHAR** ptr_copy; + WCHAR** env_copy; + DWORD* required_vars_value_len = alloca(n_required_vars * sizeof(DWORD*)); + + /* first pass: determine size in UTF-16 */ + for (env = env_block; *env; env++) { + int len; + if (strchr(*env, '=')) { + len = MultiByteToWideChar(CP_UTF8, + 0, + *env, + -1, + NULL, + 0); + if (len <= 0) { + return GetLastError(); + } + env_len += len; + env_block_count++; + } + } + + /* second pass: copy to UTF-16 environment block */ + dst_copy = (WCHAR*)uv__malloc(env_len * sizeof(WCHAR)); + if (!dst_copy) { + return ERROR_OUTOFMEMORY; + } + env_copy = alloca(env_block_count * sizeof(WCHAR*)); + + ptr = dst_copy; + ptr_copy = env_copy; + for (env = env_block; *env; env++) { + if (strchr(*env, '=')) { + len = MultiByteToWideChar(CP_UTF8, + 0, + *env, + -1, + ptr, + (int) (env_len - (ptr - dst_copy))); + if (len <= 0) { + DWORD err = GetLastError(); + uv__free(dst_copy); + return err; + } + *ptr_copy++ = ptr; + ptr += len; + } + } + *ptr_copy = NULL; + assert(env_len == ptr - dst_copy); + + /* sort our (UTF-16) copy */ + qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp); + + /* third pass: check for required variables */ + for (ptr_copy = env_copy, i = 0; i < n_required_vars; ) { + int cmp; + if (!*ptr_copy) { + cmp = -1; + } else { + cmp = env_strncmp(required_vars[i].wide_eq, + required_vars[i].len, + *ptr_copy); + } + if (cmp < 0) { + /* missing required var */ + var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0); + required_vars_value_len[i] = var_size; + if (var_size != 0) { + env_len += required_vars[i].len; + env_len += var_size; + } + i++; + } else { + ptr_copy++; + if (cmp == 0) + i++; + } + } + + /* final pass: copy, in sort order, and inserting required variables */ + dst = uv__malloc((1+env_len) * sizeof(WCHAR)); + if (!dst) { + uv__free(dst_copy); + return ERROR_OUTOFMEMORY; + } + + for (ptr = dst, ptr_copy = env_copy, i = 0; + *ptr_copy || i < n_required_vars; + ptr += len) { + int cmp; + if (i >= n_required_vars) { + cmp = 1; + } else if (!*ptr_copy) { + cmp = -1; + } else { + cmp = env_strncmp(required_vars[i].wide_eq, + required_vars[i].len, + *ptr_copy); + } + if (cmp < 0) { + /* missing required var */ + len = required_vars_value_len[i]; + if (len) { + wcscpy(ptr, required_vars[i].wide_eq); + ptr += required_vars[i].len; + var_size = GetEnvironmentVariableW(required_vars[i].wide, + ptr, + (int) (env_len - (ptr - dst))); + if (var_size != len-1) { /* race condition? */ + uv_fatal_error(GetLastError(), "GetEnvironmentVariableW"); + } + } + i++; + } else { + /* copy var from env_block */ + len = wcslen(*ptr_copy) + 1; + wmemcpy(ptr, *ptr_copy, len); + ptr_copy++; + if (cmp == 0) + i++; + } + } + + /* Terminate with an extra NULL. */ + assert(env_len == (ptr - dst)); + *ptr = L'\0'; + + uv__free(dst_copy); + *dst_ptr = dst; + return 0; +} + +/* + * Attempt to find the value of the PATH environment variable in the child's + * preprocessed environment. + * + * If found, a pointer into `env` is returned. If not found, NULL is returned. + */ +static WCHAR* find_path(WCHAR *env) { + for (; env != NULL && *env != 0; env += wcslen(env) + 1) { + if (wcsncmp(env, L"PATH=", 5) == 0) + return &env[5]; + } + + return NULL; +} + +/* + * Called on Windows thread-pool thread to indicate that + * a child process has exited. + */ +static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) { + uv_process_t* process = (uv_process_t*) data; + uv_loop_t* loop = process->loop; + + assert(didTimeout == FALSE); + assert(process); + assert(!process->exit_cb_pending); + + process->exit_cb_pending = 1; + + /* Post completed */ + POST_COMPLETION_FOR_REQ(loop, &process->exit_req); +} + + +/* Called on main thread after a child process has exited. */ +void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { + int64_t exit_code; + DWORD status; + + assert(handle->exit_cb_pending); + handle->exit_cb_pending = 0; + + /* If we're closing, don't call the exit callback. Just schedule a close */ + /* callback now. */ + if (handle->flags & UV__HANDLE_CLOSING) { + uv_want_endgame(loop, (uv_handle_t*) handle); + return; + } + + /* Unregister from process notification. */ + if (handle->wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(handle->wait_handle); + handle->wait_handle = INVALID_HANDLE_VALUE; + } + + /* Set the handle to inactive: no callbacks will be made after the exit */ + /* callback.*/ + uv__handle_stop(handle); + + if (GetExitCodeProcess(handle->process_handle, &status)) { + exit_code = status; + } else { + /* Unable to to obtain the exit code. This should never happen. */ + exit_code = uv_translate_sys_error(GetLastError()); + } + + /* Fire the exit callback. */ + if (handle->exit_cb) { + handle->exit_cb(handle, exit_code, handle->exit_signal); + } +} + + +void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { + uv__handle_closing(handle); + + if (handle->wait_handle != INVALID_HANDLE_VALUE) { + /* This blocks until either the wait was cancelled, or the callback has */ + /* completed. */ + BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE); + if (!r) { + /* This should never happen, and if it happens, we can't recover... */ + uv_fatal_error(GetLastError(), "UnregisterWaitEx"); + } + + handle->wait_handle = INVALID_HANDLE_VALUE; + } + + if (!handle->exit_cb_pending) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } +} + + +void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) { + assert(!handle->exit_cb_pending); + assert(handle->flags & UV__HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + /* Clean-up the process handle. */ + CloseHandle(handle->process_handle); + + uv__handle_close(handle); +} + + +int uv_spawn(uv_loop_t* loop, + uv_process_t* process, + const uv_process_options_t* options) { + int i; + int err = 0; + WCHAR* path = NULL, *alloc_path = NULL; + BOOL result; + WCHAR* application_path = NULL, *application = NULL, *arguments = NULL, + *env = NULL, *cwd = NULL; + STARTUPINFOW startup; + PROCESS_INFORMATION info; + DWORD process_flags; + + uv_process_init(loop, process); + process->exit_cb = options->exit_cb; + + if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) { + return UV_ENOTSUP; + } + + if (options->file == NULL || + options->args == NULL) { + return UV_EINVAL; + } + + assert(options->file != NULL); + assert(!(options->flags & ~(UV_PROCESS_DETACHED | + UV_PROCESS_SETGID | + UV_PROCESS_SETUID | + UV_PROCESS_WINDOWS_HIDE | + UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); + + err = uv_utf8_to_utf16_alloc(options->file, &application); + if (err) + goto done; + + err = make_program_args( + options->args, + options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS, + &arguments); + if (err) + goto done; + + if (options->env) { + err = make_program_env(options->env, &env); + if (err) + goto done; + } + + if (options->cwd) { + /* Explicit cwd */ + err = uv_utf8_to_utf16_alloc(options->cwd, &cwd); + if (err) + goto done; + + } else { + /* Inherit cwd */ + DWORD cwd_len, r; + + cwd_len = GetCurrentDirectoryW(0, NULL); + if (!cwd_len) { + err = GetLastError(); + goto done; + } + + cwd = (WCHAR*) uv__malloc(cwd_len * sizeof(WCHAR)); + if (cwd == NULL) { + err = ERROR_OUTOFMEMORY; + goto done; + } + + r = GetCurrentDirectoryW(cwd_len, cwd); + if (r == 0 || r >= cwd_len) { + err = GetLastError(); + goto done; + } + } + + /* Get PATH environment variable. */ + path = find_path(env); + if (path == NULL) { + DWORD path_len, r; + + path_len = GetEnvironmentVariableW(L"PATH", NULL, 0); + if (path_len == 0) { + err = GetLastError(); + goto done; + } + + alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR)); + if (alloc_path == NULL) { + err = ERROR_OUTOFMEMORY; + goto done; + } + path = alloc_path; + + r = GetEnvironmentVariableW(L"PATH", path, path_len); + if (r == 0 || r >= path_len) { + err = GetLastError(); + goto done; + } + } + + err = uv__stdio_create(loop, options, &process->child_stdio_buffer); + if (err) + goto done; + + application_path = search_path(application, + cwd, + path); + if (application_path == NULL) { + /* Not found. */ + err = ERROR_FILE_NOT_FOUND; + goto done; + } + + startup.cb = sizeof(startup); + startup.lpReserved = NULL; + startup.lpDesktop = NULL; + startup.lpTitle = NULL; + startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + + startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer); + startup.lpReserved2 = (BYTE*) process->child_stdio_buffer; + + startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0); + startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1); + startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2); + + if (options->flags & UV_PROCESS_WINDOWS_HIDE) { + /* Use SW_HIDE to avoid any potential process window. */ + startup.wShowWindow = SW_HIDE; + } else { + startup.wShowWindow = SW_SHOWDEFAULT; + } + + process_flags = CREATE_UNICODE_ENVIRONMENT; + + if (options->flags & UV_PROCESS_DETACHED) { + /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That + * means that libuv might not let you create a fully daemonized process + * when run under job control. However the type of job control that libuv + * itself creates doesn't trickle down to subprocesses so they can still + * daemonize. + * + * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the + * CreateProcess call fail if we're under job control that doesn't allow + * breakaway. + */ + process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; + } + + if (!CreateProcessW(application_path, + arguments, + NULL, + NULL, + 1, + process_flags, + env, + cwd, + &startup, + &info)) { + /* CreateProcessW failed. */ + err = GetLastError(); + goto done; + } + + /* Spawn succeeded */ + /* Beyond this point, failure is reported asynchronously. */ + + process->process_handle = info.hProcess; + process->pid = info.dwProcessId; + + /* If the process isn't spawned as detached, assign to the global job */ + /* object so windows will kill it when the parent process dies. */ + if (!(options->flags & UV_PROCESS_DETACHED)) { + uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle); + + if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) { + /* AssignProcessToJobObject might fail if this process is under job + * control and the job doesn't have the + * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version + * that doesn't support nested jobs. + * + * When that happens we just swallow the error and continue without + * establishing a kill-child-on-parent-exit relationship, otherwise + * there would be no way for libuv applications run under job control + * to spawn processes at all. + */ + DWORD err = GetLastError(); + if (err != ERROR_ACCESS_DENIED) + uv_fatal_error(err, "AssignProcessToJobObject"); + } + } + + /* Set IPC pid to all IPC pipes. */ + for (i = 0; i < options->stdio_count; i++) { + const uv_stdio_container_t* fdopt = &options->stdio[i]; + if (fdopt->flags & UV_CREATE_PIPE && + fdopt->data.stream->type == UV_NAMED_PIPE && + ((uv_pipe_t*) fdopt->data.stream)->ipc) { + ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId; + } + } + + /* Setup notifications for when the child process exits. */ + result = RegisterWaitForSingleObject(&process->wait_handle, + process->process_handle, exit_wait_callback, (void*)process, INFINITE, + WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE); + if (!result) { + uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject"); + } + + CloseHandle(info.hThread); + + assert(!err); + + /* Make the handle active. It will remain active until the exit callback */ + /* is made or the handle is closed, whichever happens first. */ + uv__handle_start(process); + + /* Cleanup, whether we succeeded or failed. */ + done: + uv__free(application); + uv__free(application_path); + uv__free(arguments); + uv__free(cwd); + uv__free(env); + uv__free(alloc_path); + + if (process->child_stdio_buffer != NULL) { + /* Clean up child stdio handles. */ + uv__stdio_destroy(process->child_stdio_buffer); + process->child_stdio_buffer = NULL; + } + + return uv_translate_sys_error(err); +} + + +static int uv__kill(HANDLE process_handle, int signum) { + switch (signum) { + case SIGTERM: + case SIGKILL: + case SIGINT: { + /* Unconditionally terminate the process. On Windows, killed processes */ + /* normally return 1. */ + DWORD status; + int err; + + if (TerminateProcess(process_handle, 1)) + return 0; + + /* If the process already exited before TerminateProcess was called, */ + /* TerminateProcess will fail with ERROR_ACCESS_DENIED. */ + err = GetLastError(); + if (err == ERROR_ACCESS_DENIED && + GetExitCodeProcess(process_handle, &status) && + status != STILL_ACTIVE) { + return UV_ESRCH; + } + + return uv_translate_sys_error(err); + } + + case 0: { + /* Health check: is the process still alive? */ + DWORD status; + + if (!GetExitCodeProcess(process_handle, &status)) + return uv_translate_sys_error(GetLastError()); + + if (status != STILL_ACTIVE) + return UV_ESRCH; + + return 0; + } + + default: + /* Unsupported signal. */ + return UV_ENOSYS; + } +} + + +int uv_process_kill(uv_process_t* process, int signum) { + int err; + + if (process->process_handle == INVALID_HANDLE_VALUE) { + return UV_EINVAL; + } + + err = uv__kill(process->process_handle, signum); + if (err) { + return err; /* err is already translated. */ + } + + process->exit_signal = signum; + + return 0; +} + + +int uv_kill(int pid, int signum) { + int err; + HANDLE process_handle = OpenProcess(PROCESS_TERMINATE | + PROCESS_QUERY_INFORMATION, FALSE, pid); + + if (process_handle == NULL) { + err = GetLastError(); + if (err == ERROR_INVALID_PARAMETER) { + return UV_ESRCH; + } else { + return uv_translate_sys_error(err); + } + } + + err = uv__kill(process_handle, signum); + CloseHandle(process_handle); + + return err; /* err is already translated. */ +} diff --git a/src/win/req-inl.h b/src/win/req-inl.h new file mode 100644 index 0000000..b5e502e --- /dev/null +++ b/src/win/req-inl.h @@ -0,0 +1,224 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_WIN_REQ_INL_H_ +#define UV_WIN_REQ_INL_H_ + +#include + +#include "uv.h" +#include "internal.h" + + +#define SET_REQ_STATUS(req, status) \ + (req)->u.io.overlapped.Internal = (ULONG_PTR) (status) + +#define SET_REQ_ERROR(req, error) \ + SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error))) + +#define SET_REQ_SUCCESS(req) \ + SET_REQ_STATUS((req), STATUS_SUCCESS) + +#define GET_REQ_STATUS(req) \ + ((NTSTATUS) (req)->u.io.overlapped.Internal) + +#define REQ_SUCCESS(req) \ + (NT_SUCCESS(GET_REQ_STATUS((req)))) + +#define GET_REQ_ERROR(req) \ + (pRtlNtStatusToDosError(GET_REQ_STATUS((req)))) + +#define GET_REQ_SOCK_ERROR(req) \ + (uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req)))) + + +#define REGISTER_HANDLE_REQ(loop, handle, req) \ + do { \ + INCREASE_ACTIVE_COUNT((loop), (handle)); \ + uv__req_register((loop), (req)); \ + } while (0) + +#define UNREGISTER_HANDLE_REQ(loop, handle, req) \ + do { \ + DECREASE_ACTIVE_COUNT((loop), (handle)); \ + uv__req_unregister((loop), (req)); \ + } while (0) + + +#define UV_SUCCEEDED_WITHOUT_IOCP(result) \ + ((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP)) + +#define UV_SUCCEEDED_WITH_IOCP(result) \ + ((result) || (GetLastError() == ERROR_IO_PENDING)) + + +#define POST_COMPLETION_FOR_REQ(loop, req) \ + if (!PostQueuedCompletionStatus((loop)->iocp, \ + 0, \ + 0, \ + &((req)->u.io.overlapped))) { \ + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \ + } + + +INLINE static void uv_req_init(uv_loop_t* loop, uv_req_t* req) { + req->type = UV_UNKNOWN_REQ; + SET_REQ_SUCCESS(req); +} + + +INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) { + return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped); +} + + +INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) { + req->next_req = NULL; + if (loop->pending_reqs_tail) { +#ifdef _DEBUG + /* Ensure the request is not already in the queue, or the queue + * will get corrupted. + */ + uv_req_t* current = loop->pending_reqs_tail; + do { + assert(req != current); + current = current->next_req; + } while(current != loop->pending_reqs_tail); +#endif + + req->next_req = loop->pending_reqs_tail->next_req; + loop->pending_reqs_tail->next_req = req; + loop->pending_reqs_tail = req; + } else { + req->next_req = req; + loop->pending_reqs_tail = req; + } +} + + +#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \ + do { \ + switch (((uv_handle_t*) (req)->handle_at)->type) { \ + case UV_TCP: \ + uv_process_tcp_##method##_req(loop, \ + (uv_tcp_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + case UV_NAMED_PIPE: \ + uv_process_pipe_##method##_req(loop, \ + (uv_pipe_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + case UV_TTY: \ + uv_process_tty_##method##_req(loop, \ + (uv_tty_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + default: \ + assert(0); \ + } \ + } while (0) + + +INLINE static int uv_process_reqs(uv_loop_t* loop) { + uv_req_t* req; + uv_req_t* first; + uv_req_t* next; + + if (loop->pending_reqs_tail == NULL) + return 0; + + first = loop->pending_reqs_tail->next_req; + next = first; + loop->pending_reqs_tail = NULL; + + while (next != NULL) { + req = next; + next = req->next_req != first ? req->next_req : NULL; + + switch (req->type) { + case UV_READ: + DELEGATE_STREAM_REQ(loop, req, read, data); + break; + + case UV_WRITE: + DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle); + break; + + case UV_ACCEPT: + DELEGATE_STREAM_REQ(loop, req, accept, data); + break; + + case UV_CONNECT: + DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle); + break; + + case UV_SHUTDOWN: + /* Tcp shutdown requests don't come here. */ + assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE); + uv_process_pipe_shutdown_req( + loop, + (uv_pipe_t*) ((uv_shutdown_t*) req)->handle, + (uv_shutdown_t*) req); + break; + + case UV_UDP_RECV: + uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req); + break; + + case UV_UDP_SEND: + uv_process_udp_send_req(loop, + ((uv_udp_send_t*) req)->handle, + (uv_udp_send_t*) req); + break; + + case UV_WAKEUP: + uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req); + break; + + case UV_SIGNAL_REQ: + uv_process_signal_req(loop, (uv_signal_t*) req->data, req); + break; + + case UV_POLL_REQ: + uv_process_poll_req(loop, (uv_poll_t*) req->data, req); + break; + + case UV_PROCESS_EXIT: + uv_process_proc_exit(loop, (uv_process_t*) req->data); + break; + + case UV_FS_EVENT_REQ: + uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data); + break; + + default: + assert(0); + } + } + + return 1; +} + +#endif /* UV_WIN_REQ_INL_H_ */ diff --git a/src/win/req.c b/src/win/req.c new file mode 100644 index 0000000..111cc5e --- /dev/null +++ b/src/win/req.c @@ -0,0 +1,25 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include + +#include "uv.h" +#include "internal.h" diff --git a/src/win/signal.c b/src/win/signal.c new file mode 100644 index 0000000..2c64a55 --- /dev/null +++ b/src/win/signal.c @@ -0,0 +1,356 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * 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. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +RB_HEAD(uv_signal_tree_s, uv_signal_s); + +static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree); +static ssize_t volatile uv__signal_control_handler_refs = 0; +static CRITICAL_SECTION uv__signal_lock; + + +void uv_signals_init() { + InitializeCriticalSection(&uv__signal_lock); +} + + +static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { + /* Compare signums first so all watchers with the same signnum end up */ + /* adjacent. */ + if (w1->signum < w2->signum) return -1; + if (w1->signum > w2->signum) return 1; + + /* Sort by loop pointer, so we can easily look up the first item after */ + /* { .signum = x, .loop = NULL } */ + if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1; + if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1; + + if ((uintptr_t) w1 < (uintptr_t) w2) return -1; + if ((uintptr_t) w1 > (uintptr_t) w2) return 1; + + return 0; +} + + +RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare); + + +/* + * Dispatches signal {signum} to all active uv_signal_t watchers in all loops. + * Returns 1 if the signal was dispatched to any watcher, or 0 if there were + * no active signal watchers observing this signal. + */ +int uv__signal_dispatch(int signum) { + uv_signal_t lookup; + uv_signal_t* handle; + int dispatched = 0; + + EnterCriticalSection(&uv__signal_lock); + + lookup.signum = signum; + lookup.loop = NULL; + + for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup); + handle != NULL && handle->signum == signum; + handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) { + unsigned long previous = InterlockedExchange( + (volatile LONG*) &handle->pending_signum, signum); + + if (!previous) { + POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req); + } + + dispatched = 1; + } + + LeaveCriticalSection(&uv__signal_lock); + + return dispatched; +} + + +static BOOL WINAPI uv__signal_control_handler(DWORD type) { + switch (type) { + case CTRL_C_EVENT: + return uv__signal_dispatch(SIGINT); + + case CTRL_BREAK_EVENT: + return uv__signal_dispatch(SIGBREAK); + + case CTRL_CLOSE_EVENT: + if (uv__signal_dispatch(SIGHUP)) { + /* Windows will terminate the process after the control handler */ + /* returns. After that it will just terminate our process. Therefore */ + /* block the signal handler so the main loop has some time to pick */ + /* up the signal and do something for a few seconds. */ + Sleep(INFINITE); + return TRUE; + } + return FALSE; + + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + /* These signals are only sent to services. Services have their own */ + /* notification mechanism, so there's no point in handling these. */ + + default: + /* We don't handle these. */ + return FALSE; + } +} + + +static int uv__signal_register_control_handler() { + /* When this function is called, the uv__signal_lock must be held. */ + + /* If the console control handler has already been hooked, just add a */ + /* reference. */ + if (uv__signal_control_handler_refs > 0) { + uv__signal_control_handler_refs++; + return 0; + } + + if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) + return GetLastError(); + + uv__signal_control_handler_refs++; + + return 0; +} + + +static void uv__signal_unregister_control_handler() { + /* When this function is called, the uv__signal_lock must be held. */ + BOOL r; + + /* Don't unregister if the number of console control handlers exceeds one. */ + /* Just remove a reference in that case. */ + if (uv__signal_control_handler_refs > 1) { + uv__signal_control_handler_refs--; + return; + } + + assert(uv__signal_control_handler_refs == 1); + + r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE); + /* This should never fail; if it does it is probably a bug in libuv. */ + assert(r); + + uv__signal_control_handler_refs--; +} + + +static int uv__signal_register(int signum) { + switch (signum) { + case SIGINT: + case SIGBREAK: + case SIGHUP: + return uv__signal_register_control_handler(); + + case SIGWINCH: + /* SIGWINCH is generated in tty.c. No need to register anything. */ + return 0; + + case SIGILL: + case SIGABRT_COMPAT: + case SIGFPE: + case SIGSEGV: + case SIGTERM: + case SIGABRT: + /* Signal is never raised. */ + return 0; + + default: + /* Invalid signal. */ + return ERROR_INVALID_PARAMETER; + } +} + + +static void uv__signal_unregister(int signum) { + switch (signum) { + case SIGINT: + case SIGBREAK: + case SIGHUP: + uv__signal_unregister_control_handler(); + return; + + case SIGWINCH: + /* SIGWINCH is generated in tty.c. No need to unregister anything. */ + return; + + case SIGILL: + case SIGABRT_COMPAT: + case SIGFPE: + case SIGSEGV: + case SIGTERM: + case SIGABRT: + /* Nothing is registered for this signal. */ + return; + + default: + /* Libuv bug. */ + assert(0 && "Invalid signum"); + return; + } +} + + +int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { + uv_req_t* req; + + uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL); + handle->pending_signum = 0; + handle->signum = 0; + handle->signal_cb = NULL; + + req = &handle->signal_req; + uv_req_init(loop, req); + req->type = UV_SIGNAL_REQ; + req->data = handle; + + return 0; +} + + +int uv_signal_stop(uv_signal_t* handle) { + uv_signal_t* removed_handle; + + /* If the watcher wasn't started, this is a no-op. */ + if (handle->signum == 0) + return 0; + + EnterCriticalSection(&uv__signal_lock); + + uv__signal_unregister(handle->signum); + + removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle); + assert(removed_handle == handle); + + LeaveCriticalSection(&uv__signal_lock); + + handle->signum = 0; + uv__handle_stop(handle); + + return 0; +} + + +int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { + int err; + + /* If the user supplies signum == 0, then return an error already. If the */ + /* signum is otherwise invalid then uv__signal_register will find out */ + /* eventually. */ + if (signum == 0) { + return UV_EINVAL; + } + + /* Short circuit: if the signal watcher is already watching {signum} don't */ + /* go through the process of deregistering and registering the handler. */ + /* Additionally, this avoids pending signals getting lost in the (small) */ + /* time frame that handle->signum == 0. */ + if (signum == handle->signum) { + handle->signal_cb = signal_cb; + return 0; + } + + /* If the signal handler was already active, stop it first. */ + if (handle->signum != 0) { + int r = uv_signal_stop(handle); + /* uv_signal_stop is infallible. */ + assert(r == 0); + } + + EnterCriticalSection(&uv__signal_lock); + + err = uv__signal_register(signum); + if (err) { + /* Uh-oh, didn't work. */ + LeaveCriticalSection(&uv__signal_lock); + return uv_translate_sys_error(err); + } + + handle->signum = signum; + RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle); + + LeaveCriticalSection(&uv__signal_lock); + + handle->signal_cb = signal_cb; + uv__handle_start(handle); + + return 0; +} + + +void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, + uv_req_t* req) { + long dispatched_signum; + + assert(handle->type == UV_SIGNAL); + assert(req->type == UV_SIGNAL_REQ); + + dispatched_signum = InterlockedExchange( + (volatile LONG*) &handle->pending_signum, 0); + assert(dispatched_signum != 0); + + /* Check if the pending signal equals the signum that we are watching for. */ + /* These can get out of sync when the handler is stopped and restarted */ + /* while the signal_req is pending. */ + if (dispatched_signum == handle->signum) + handle->signal_cb(handle, dispatched_signum); + + if (handle->flags & UV__HANDLE_CLOSING) { + /* When it is closing, it must be stopped at this point. */ + assert(handle->signum == 0); + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) { + uv_signal_stop(handle); + uv__handle_closing(handle); + + if (handle->pending_signum == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) { + assert(handle->flags & UV__HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + assert(handle->signum == 0); + assert(handle->pending_signum == 0); + + handle->flags |= UV_HANDLE_CLOSED; + + uv__handle_close(handle); +} diff --git a/src/win/snprintf.c b/src/win/snprintf.c new file mode 100644 index 0000000..776c0e3 --- /dev/null +++ b/src/win/snprintf.c @@ -0,0 +1,42 @@ +/* Copyright the libuv project contributors. All rights reserved. + * + * 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. + */ + +#if defined(_MSC_VER) && _MSC_VER < 1900 + +#include +#include + +/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer + * on overflow... + */ +int snprintf(char* buf, size_t len, const char* fmt, ...) { + int n; + va_list ap; + va_start(ap, fmt); + + n = _vscprintf(fmt, ap); + vsnprintf_s(buf, len, _TRUNCATE, fmt, ap); + + va_end(ap); + return n; +} + +#endif diff --git a/src/win/stream-inl.h b/src/win/stream-inl.h new file mode 100644 index 0000000..b7a3c11 --- /dev/null +++ b/src/win/stream-inl.h @@ -0,0 +1,56 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_WIN_STREAM_INL_H_ +#define UV_WIN_STREAM_INL_H_ + +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +INLINE static void uv_stream_init(uv_loop_t* loop, + uv_stream_t* handle, + uv_handle_type type) { + uv__handle_init(loop, (uv_handle_t*) handle, type); + handle->write_queue_size = 0; + handle->activecnt = 0; +} + + +INLINE static void uv_connection_init(uv_stream_t* handle) { + handle->flags |= UV_HANDLE_CONNECTION; + handle->stream.conn.write_reqs_pending = 0; + + uv_req_init(handle->loop, (uv_req_t*) &(handle->read_req)); + handle->read_req.event_handle = NULL; + handle->read_req.wait_handle = INVALID_HANDLE_VALUE; + handle->read_req.type = UV_READ; + handle->read_req.data = handle; + + handle->stream.conn.shutdown_req = NULL; +} + + +#endif /* UV_WIN_STREAM_INL_H_ */ diff --git a/src/win/stream.c b/src/win/stream.c new file mode 100644 index 0000000..a2466e5 --- /dev/null +++ b/src/win/stream.c @@ -0,0 +1,249 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { + int err; + + err = ERROR_INVALID_PARAMETER; + switch (stream->type) { + case UV_TCP: + err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb); + break; + case UV_NAMED_PIPE: + err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_accept(uv_stream_t* server, uv_stream_t* client) { + int err; + + err = ERROR_INVALID_PARAMETER; + switch (server->type) { + case UV_TCP: + err = uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client); + break; + case UV_NAMED_PIPE: + err = uv_pipe_accept((uv_pipe_t*)server, client); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { + int err; + + if (handle->flags & UV_HANDLE_READING) { + return UV_EALREADY; + } + + if (!(handle->flags & UV_HANDLE_READABLE)) { + return UV_ENOTCONN; + } + + err = ERROR_INVALID_PARAMETER; + switch (handle->type) { + case UV_TCP: + err = uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb); + break; + case UV_NAMED_PIPE: + err = uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb); + break; + case UV_TTY: + err = uv_tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_read_stop(uv_stream_t* handle) { + int err; + + if (!(handle->flags & UV_HANDLE_READING)) + return 0; + + err = 0; + if (handle->type == UV_TTY) { + err = uv_tty_read_stop((uv_tty_t*) handle); + } else { + if (handle->type == UV_NAMED_PIPE) { + uv__pipe_stop_read((uv_pipe_t*) handle); + } else { + handle->flags &= ~UV_HANDLE_READING; + } + DECREASE_ACTIVE_COUNT(handle->loop, handle); + } + + return uv_translate_sys_error(err); +} + + +int uv_write(uv_write_t* req, + uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb) { + uv_loop_t* loop = handle->loop; + int err; + + if (!(handle->flags & UV_HANDLE_WRITABLE)) { + return UV_EPIPE; + } + + err = ERROR_INVALID_PARAMETER; + switch (handle->type) { + case UV_TCP: + err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb); + break; + case UV_NAMED_PIPE: + err = uv_pipe_write(loop, req, (uv_pipe_t*) handle, bufs, nbufs, cb); + break; + case UV_TTY: + err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_write2(uv_write_t* req, + uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb) { + uv_loop_t* loop = handle->loop; + int err; + + if (!(handle->flags & UV_HANDLE_WRITABLE)) { + return UV_EPIPE; + } + + err = ERROR_INVALID_PARAMETER; + switch (handle->type) { + case UV_NAMED_PIPE: + err = uv_pipe_write2(loop, + req, + (uv_pipe_t*) handle, + bufs, + nbufs, + send_handle, + cb); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_try_write(uv_stream_t* stream, + const uv_buf_t bufs[], + unsigned int nbufs) { + if (stream->flags & UV__HANDLE_CLOSING) + return UV_EBADF; + if (!(stream->flags & UV_HANDLE_WRITABLE)) + return UV_EPIPE; + + switch (stream->type) { + case UV_TCP: + return uv__tcp_try_write((uv_tcp_t*) stream, bufs, nbufs); + case UV_TTY: + return uv__tty_try_write((uv_tty_t*) stream, bufs, nbufs); + case UV_NAMED_PIPE: + return UV_EAGAIN; + default: + assert(0); + return UV_ENOSYS; + } +} + + +int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { + uv_loop_t* loop = handle->loop; + + if (!(handle->flags & UV_HANDLE_WRITABLE)) { + return UV_EPIPE; + } + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_SHUTDOWN; + req->handle = handle; + req->cb = cb; + + handle->flags &= ~UV_HANDLE_WRITABLE; + handle->stream.conn.shutdown_req = req; + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + + uv_want_endgame(loop, (uv_handle_t*)handle); + + return 0; +} + + +int uv_is_readable(const uv_stream_t* handle) { + return !!(handle->flags & UV_HANDLE_READABLE); +} + + +int uv_is_writable(const uv_stream_t* handle) { + return !!(handle->flags & UV_HANDLE_WRITABLE); +} + + +int uv_stream_set_blocking(uv_stream_t* handle, int blocking) { + if (handle->type != UV_NAMED_PIPE) + return UV_EINVAL; + + if (blocking != 0) + handle->flags |= UV_HANDLE_BLOCKING_WRITES; + else + handle->flags &= ~UV_HANDLE_BLOCKING_WRITES; + + return 0; +} diff --git a/src/win/tcp.c b/src/win/tcp.c new file mode 100644 index 0000000..0709696 --- /dev/null +++ b/src/win/tcp.c @@ -0,0 +1,1510 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" + + +/* + * Threshold of active tcp streams for which to preallocate tcp read buffers. + * (Due to node slab allocator performing poorly under this pattern, + * the optimization is temporarily disabled (threshold=0). This will be + * revisited once node allocator is improved.) + */ +const unsigned int uv_active_tcp_streams_threshold = 0; + +/* + * Number of simultaneous pending AcceptEx calls. + */ +const unsigned int uv_simultaneous_server_accepts = 32; + +/* A zero-size buffer for use by uv_tcp_read */ +static char uv_zero_[] = ""; + +static int uv__tcp_nodelay(uv_tcp_t* handle, SOCKET socket, int enable) { + if (setsockopt(socket, + IPPROTO_TCP, + TCP_NODELAY, + (const char*)&enable, + sizeof enable) == -1) { + return WSAGetLastError(); + } + return 0; +} + + +static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsigned int delay) { + if (setsockopt(socket, + SOL_SOCKET, + SO_KEEPALIVE, + (const char*)&enable, + sizeof enable) == -1) { + return WSAGetLastError(); + } + + if (enable && setsockopt(socket, + IPPROTO_TCP, + TCP_KEEPALIVE, + (const char*)&delay, + sizeof delay) == -1) { + return WSAGetLastError(); + } + + return 0; +} + + +static int uv_tcp_set_socket(uv_loop_t* loop, + uv_tcp_t* handle, + SOCKET socket, + int family, + int imported) { + DWORD yes = 1; + int non_ifs_lsp; + int err; + + if (handle->socket != INVALID_SOCKET) + return UV_EBUSY; + + /* Set the socket to nonblocking mode */ + if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) { + return WSAGetLastError(); + } + + /* Make the socket non-inheritable */ + if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0)) + return GetLastError(); + + /* Associate it with the I/O completion port. */ + /* Use uv_handle_t pointer as completion key. */ + if (CreateIoCompletionPort((HANDLE)socket, + loop->iocp, + (ULONG_PTR)socket, + 0) == NULL) { + if (imported) { + handle->flags |= UV_HANDLE_EMULATE_IOCP; + } else { + return GetLastError(); + } + } + + if (family == AF_INET6) { + non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv6; + } else { + non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4; + } + + if (pSetFileCompletionNotificationModes && + !(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) { + if (pSetFileCompletionNotificationModes((HANDLE) socket, + FILE_SKIP_SET_EVENT_ON_HANDLE | + FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { + handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; + } else if (GetLastError() != ERROR_INVALID_FUNCTION) { + return GetLastError(); + } + } + + if (handle->flags & UV_HANDLE_TCP_NODELAY) { + err = uv__tcp_nodelay(handle, socket, 1); + if (err) + return err; + } + + /* TODO: Use stored delay. */ + if (handle->flags & UV_HANDLE_TCP_KEEPALIVE) { + err = uv__tcp_keepalive(handle, socket, 1, 60); + if (err) + return err; + } + + handle->socket = socket; + + if (family == AF_INET6) { + handle->flags |= UV_HANDLE_IPV6; + } else { + assert(!(handle->flags & UV_HANDLE_IPV6)); + } + + return 0; +} + + +int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) { + int domain; + + /* Use the lower 8 bits for the domain */ + domain = flags & 0xFF; + if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) + return UV_EINVAL; + + if (flags & ~0xFF) + return UV_EINVAL; + + uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP); + handle->tcp.serv.accept_reqs = NULL; + handle->tcp.serv.pending_accepts = NULL; + handle->socket = INVALID_SOCKET; + handle->reqs_pending = 0; + handle->tcp.serv.func_acceptex = NULL; + handle->tcp.conn.func_connectex = NULL; + handle->tcp.serv.processed_accepts = 0; + handle->delayed_error = 0; + + /* If anything fails beyond this point we need to remove the handle from + * the handle queue, since it was added by uv__handle_init in uv_stream_init. + */ + + if (domain != AF_UNSPEC) { + SOCKET sock; + DWORD err; + + sock = socket(domain, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) { + err = WSAGetLastError(); + QUEUE_REMOVE(&handle->handle_queue); + return uv_translate_sys_error(err); + } + + err = uv_tcp_set_socket(handle->loop, handle, sock, domain, 0); + if (err) { + closesocket(sock); + QUEUE_REMOVE(&handle->handle_queue); + return uv_translate_sys_error(err); + } + + } + + return 0; +} + + +int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) { + return uv_tcp_init_ex(loop, handle, AF_UNSPEC); +} + + +void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { + int err; + unsigned int i; + uv_tcp_accept_t* req; + + if (handle->flags & UV_HANDLE_CONNECTION && + handle->stream.conn.shutdown_req != NULL && + handle->stream.conn.write_reqs_pending == 0) { + + UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req); + + err = 0; + if (handle->flags & UV__HANDLE_CLOSING) { + err = ERROR_OPERATION_ABORTED; + } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) { + err = WSAGetLastError(); + } + + if (handle->stream.conn.shutdown_req->cb) { + handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, + uv_translate_sys_error(err)); + } + + handle->stream.conn.shutdown_req = NULL; + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + if (handle->flags & UV__HANDLE_CLOSING && + handle->reqs_pending == 0) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) { + closesocket(handle->socket); + handle->socket = INVALID_SOCKET; + handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; + } + + if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) { + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + for (i = 0; i < uv_simultaneous_server_accepts; i++) { + req = &handle->tcp.serv.accept_reqs[i]; + if (req->wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(req->wait_handle); + req->wait_handle = INVALID_HANDLE_VALUE; + } + if (req->event_handle) { + CloseHandle(req->event_handle); + req->event_handle = NULL; + } + } + } + + uv__free(handle->tcp.serv.accept_reqs); + handle->tcp.serv.accept_reqs = NULL; + } + + if (handle->flags & UV_HANDLE_CONNECTION && + handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(handle->read_req.wait_handle); + handle->read_req.wait_handle = INVALID_HANDLE_VALUE; + } + if (handle->read_req.event_handle) { + CloseHandle(handle->read_req.event_handle); + handle->read_req.event_handle = NULL; + } + } + + uv__handle_close(handle); + loop->active_tcp_streams--; + } +} + + +/* Unlike on Unix, here we don't set SO_REUSEADDR, because it doesn't just + * allow binding to addresses that are in use by sockets in TIME_WAIT, it + * effectively allows 'stealing' a port which is in use by another application. + * + * SO_EXCLUSIVEADDRUSE is also not good here because it does check all sockets, + * regardless of state, so we'd get an error even if the port is in use by a + * socket in TIME_WAIT state. + * + * See issue #1360. + * + */ +static int uv_tcp_try_bind(uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + DWORD err; + int r; + + if (handle->socket == INVALID_SOCKET) { + SOCKET sock; + + /* Cannot set IPv6-only mode on non-IPv6 socket. */ + if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6) + return ERROR_INVALID_PARAMETER; + + sock = socket(addr->sa_family, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) { + return WSAGetLastError(); + } + + err = uv_tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0); + if (err) { + closesocket(sock); + return err; + } + } + +#ifdef IPV6_V6ONLY + if (addr->sa_family == AF_INET6) { + int on; + + on = (flags & UV_TCP_IPV6ONLY) != 0; + + /* TODO: how to handle errors? This may fail if there is no ipv4 stack */ + /* available, or when run on XP/2003 which have no support for dualstack */ + /* sockets. For now we're silently ignoring the error. */ + setsockopt(handle->socket, + IPPROTO_IPV6, + IPV6_V6ONLY, + (const char*)&on, + sizeof on); + } +#endif + + r = bind(handle->socket, addr, addrlen); + + if (r == SOCKET_ERROR) { + err = WSAGetLastError(); + if (err == WSAEADDRINUSE) { + /* Some errors are not to be reported until connect() or listen() */ + handle->delayed_error = err; + } else { + return err; + } + } + + handle->flags |= UV_HANDLE_BOUND; + + return 0; +} + + +static void CALLBACK post_completion(void* context, BOOLEAN timed_out) { + uv_req_t* req; + uv_tcp_t* handle; + + req = (uv_req_t*) context; + assert(req != NULL); + handle = (uv_tcp_t*)req->data; + assert(handle != NULL); + assert(!timed_out); + + if (!PostQueuedCompletionStatus(handle->loop->iocp, + req->u.io.overlapped.InternalHigh, + 0, + &req->u.io.overlapped)) { + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); + } +} + + +static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) { + uv_write_t* req; + uv_tcp_t* handle; + + req = (uv_write_t*) context; + assert(req != NULL); + handle = (uv_tcp_t*)req->handle; + assert(handle != NULL); + assert(!timed_out); + + if (!PostQueuedCompletionStatus(handle->loop->iocp, + req->u.io.overlapped.InternalHigh, + 0, + &req->u.io.overlapped)) { + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); + } +} + + +static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { + uv_loop_t* loop = handle->loop; + BOOL success; + DWORD bytes; + SOCKET accept_socket; + short family; + + assert(handle->flags & UV_HANDLE_LISTENING); + assert(req->accept_socket == INVALID_SOCKET); + + /* choose family and extension function */ + if (handle->flags & UV_HANDLE_IPV6) { + family = AF_INET6; + } else { + family = AF_INET; + } + + /* Open a socket for the accepted connection. */ + accept_socket = socket(family, SOCK_STREAM, 0); + if (accept_socket == INVALID_SOCKET) { + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->reqs_pending++; + return; + } + + /* Make the socket non-inheritable */ + if (!SetHandleInformation((HANDLE) accept_socket, HANDLE_FLAG_INHERIT, 0)) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->reqs_pending++; + closesocket(accept_socket); + return; + } + + /* Prepare the overlapped structure. */ + memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); + } + + success = handle->tcp.serv.func_acceptex(handle->socket, + accept_socket, + (void*)req->accept_buffer, + 0, + sizeof(struct sockaddr_storage), + sizeof(struct sockaddr_storage), + &bytes, + &req->u.io.overlapped); + + if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { + /* Process the req without IOCP. */ + req->accept_socket = accept_socket; + handle->reqs_pending++; + uv_insert_pending_req(loop, (uv_req_t*)req); + } else if (UV_SUCCEEDED_WITH_IOCP(success)) { + /* The req will be processed with IOCP. */ + req->accept_socket = accept_socket; + handle->reqs_pending++; + if (handle->flags & UV_HANDLE_EMULATE_IOCP && + req->wait_handle == INVALID_HANDLE_VALUE && + !RegisterWaitForSingleObject(&req->wait_handle, + req->event_handle, post_completion, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD)) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->reqs_pending++; + return; + } + } else { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->reqs_pending++; + /* Destroy the preallocated client socket. */ + closesocket(accept_socket); + /* Destroy the event handle */ + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + CloseHandle(req->u.io.overlapped.hEvent); + req->event_handle = NULL; + } + } +} + + +static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { + uv_read_t* req; + uv_buf_t buf; + int result; + DWORD bytes, flags; + + assert(handle->flags & UV_HANDLE_READING); + assert(!(handle->flags & UV_HANDLE_READ_PENDING)); + + req = &handle->read_req; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + + /* + * Preallocate a read buffer if the number of active streams is below + * the threshold. + */ + if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) { + handle->flags &= ~UV_HANDLE_ZERO_READ; + handle->tcp.conn.read_buffer = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer); + if (handle->tcp.conn.read_buffer.base == NULL || + handle->tcp.conn.read_buffer.len == 0) { + handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tcp.conn.read_buffer); + return; + } + assert(handle->tcp.conn.read_buffer.base != NULL); + buf = handle->tcp.conn.read_buffer; + } else { + handle->flags |= UV_HANDLE_ZERO_READ; + buf.base = (char*) &uv_zero_; + buf.len = 0; + } + + /* Prepare the overlapped structure. */ + memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + assert(req->event_handle); + req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); + } + + flags = 0; + result = WSARecv(handle->socket, + (WSABUF*)&buf, + 1, + &bytes, + &flags, + &req->u.io.overlapped, + NULL); + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Process the req without IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + req->u.io.overlapped.InternalHigh = bytes; + handle->reqs_pending++; + uv_insert_pending_req(loop, (uv_req_t*)req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* The req will be processed with IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + if (handle->flags & UV_HANDLE_EMULATE_IOCP && + req->wait_handle == INVALID_HANDLE_VALUE && + !RegisterWaitForSingleObject(&req->wait_handle, + req->event_handle, post_completion, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD)) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + } + } else { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->reqs_pending++; + } +} + + +int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { + uv_loop_t* loop = handle->loop; + unsigned int i, simultaneous_accepts; + uv_tcp_accept_t* req; + int err; + + assert(backlog > 0); + + if (handle->flags & UV_HANDLE_LISTENING) { + handle->stream.serv.connection_cb = cb; + } + + if (handle->flags & UV_HANDLE_READING) { + return WSAEISCONN; + } + + if (handle->delayed_error) { + return handle->delayed_error; + } + + if (!(handle->flags & UV_HANDLE_BOUND)) { + err = uv_tcp_try_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + 0); + if (err) + return err; + if (handle->delayed_error) + return handle->delayed_error; + } + + if (!handle->tcp.serv.func_acceptex) { + if (!uv_get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) { + return WSAEAFNOSUPPORT; + } + } + + if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) && + listen(handle->socket, backlog) == SOCKET_ERROR) { + return WSAGetLastError(); + } + + handle->flags |= UV_HANDLE_LISTENING; + handle->stream.serv.connection_cb = cb; + INCREASE_ACTIVE_COUNT(loop, handle); + + simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1 + : uv_simultaneous_server_accepts; + + if(!handle->tcp.serv.accept_reqs) { + handle->tcp.serv.accept_reqs = (uv_tcp_accept_t*) + uv__malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t)); + if (!handle->tcp.serv.accept_reqs) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + for (i = 0; i < simultaneous_accepts; i++) { + req = &handle->tcp.serv.accept_reqs[i]; + uv_req_init(loop, (uv_req_t*)req); + req->type = UV_ACCEPT; + req->accept_socket = INVALID_SOCKET; + req->data = handle; + + req->wait_handle = INVALID_HANDLE_VALUE; + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + req->event_handle = CreateEvent(NULL, 0, 0, NULL); + if (!req->event_handle) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + } else { + req->event_handle = NULL; + } + + uv_tcp_queue_accept(handle, req); + } + + /* Initialize other unused requests too, because uv_tcp_endgame */ + /* doesn't know how how many requests were initialized, so it will */ + /* try to clean up {uv_simultaneous_server_accepts} requests. */ + for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) { + req = &handle->tcp.serv.accept_reqs[i]; + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_ACCEPT; + req->accept_socket = INVALID_SOCKET; + req->data = handle; + req->wait_handle = INVALID_HANDLE_VALUE; + req->event_handle = NULL; + } + } + + return 0; +} + + +int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { + uv_loop_t* loop = server->loop; + int err = 0; + int family; + + uv_tcp_accept_t* req = server->tcp.serv.pending_accepts; + + if (!req) { + /* No valid connections found, so we error out. */ + return WSAEWOULDBLOCK; + } + + if (req->accept_socket == INVALID_SOCKET) { + return WSAENOTCONN; + } + + if (server->flags & UV_HANDLE_IPV6) { + family = AF_INET6; + } else { + family = AF_INET; + } + + err = uv_tcp_set_socket(client->loop, + client, + req->accept_socket, + family, + 0); + if (err) { + closesocket(req->accept_socket); + } else { + uv_connection_init((uv_stream_t*) client); + /* AcceptEx() implicitly binds the accepted socket. */ + client->flags |= UV_HANDLE_BOUND | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + } + + /* Prepare the req to pick up a new connection */ + server->tcp.serv.pending_accepts = req->next_pending; + req->next_pending = NULL; + req->accept_socket = INVALID_SOCKET; + + if (!(server->flags & UV__HANDLE_CLOSING)) { + /* Check if we're in a middle of changing the number of pending accepts. */ + if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) { + uv_tcp_queue_accept(server, req); + } else { + /* We better be switching to a single pending accept. */ + assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT); + + server->tcp.serv.processed_accepts++; + + if (server->tcp.serv.processed_accepts >= uv_simultaneous_server_accepts) { + server->tcp.serv.processed_accepts = 0; + /* + * All previously queued accept requests are now processed. + * We now switch to queueing just a single accept. + */ + uv_tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]); + server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING; + server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; + } + } + } + + loop->active_tcp_streams++; + + return err; +} + + +int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { + uv_loop_t* loop = handle->loop; + + handle->flags |= UV_HANDLE_READING; + handle->read_cb = read_cb; + handle->alloc_cb = alloc_cb; + INCREASE_ACTIVE_COUNT(loop, handle); + + /* If reading was stopped and then started again, there could still be a */ + /* read request pending. */ + if (!(handle->flags & UV_HANDLE_READ_PENDING)) { + if (handle->flags & UV_HANDLE_EMULATE_IOCP && + !handle->read_req.event_handle) { + handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL); + if (!handle->read_req.event_handle) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + } + uv_tcp_queue_read(loop, handle); + } + + return 0; +} + + +static int uv_tcp_try_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + uv_connect_cb cb) { + uv_loop_t* loop = handle->loop; + const struct sockaddr* bind_addr; + BOOL success; + DWORD bytes; + int err; + + if (handle->delayed_error) { + return handle->delayed_error; + } + + if (!(handle->flags & UV_HANDLE_BOUND)) { + if (addrlen == sizeof(uv_addr_ip4_any_)) { + bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_; + } else if (addrlen == sizeof(uv_addr_ip6_any_)) { + bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_; + } else { + abort(); + } + err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0); + if (err) + return err; + if (handle->delayed_error) + return handle->delayed_error; + } + + if (!handle->tcp.conn.func_connectex) { + if (!uv_get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) { + return WSAEAFNOSUPPORT; + } + } + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_CONNECT; + req->handle = (uv_stream_t*) handle; + req->cb = cb; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + + success = handle->tcp.conn.func_connectex(handle->socket, + addr, + addrlen, + NULL, + 0, + &bytes, + &req->u.io.overlapped); + + if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { + /* Process the req without IOCP. */ + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + uv_insert_pending_req(loop, (uv_req_t*)req); + } else if (UV_SUCCEEDED_WITH_IOCP(success)) { + /* The req will be processed with IOCP. */ + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + } else { + return WSAGetLastError(); + } + + return 0; +} + + +int uv_tcp_getsockname(const uv_tcp_t* handle, + struct sockaddr* name, + int* namelen) { + int result; + + if (handle->socket == INVALID_SOCKET) { + return UV_EINVAL; + } + + if (handle->delayed_error) { + return uv_translate_sys_error(handle->delayed_error); + } + + result = getsockname(handle->socket, name, namelen); + if (result != 0) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +int uv_tcp_getpeername(const uv_tcp_t* handle, + struct sockaddr* name, + int* namelen) { + int result; + + if (handle->socket == INVALID_SOCKET) { + return UV_EINVAL; + } + + if (handle->delayed_error) { + return uv_translate_sys_error(handle->delayed_error); + } + + result = getpeername(handle->socket, name, namelen); + if (result != 0) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +int uv_tcp_write(uv_loop_t* loop, + uv_write_t* req, + uv_tcp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb) { + int result; + DWORD bytes; + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_WRITE; + req->handle = (uv_stream_t*) handle; + req->cb = cb; + + /* Prepare the overlapped structure. */ + memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + req->event_handle = CreateEvent(NULL, 0, 0, NULL); + if (!req->event_handle) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); + req->wait_handle = INVALID_HANDLE_VALUE; + } + + result = WSASend(handle->socket, + (WSABUF*) bufs, + nbufs, + &bytes, + 0, + &req->u.io.overlapped, + NULL); + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Request completed immediately. */ + req->u.io.queued_bytes = 0; + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + uv_insert_pending_req(loop, (uv_req_t*) req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* Request queued by the kernel. */ + req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs); + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + handle->write_queue_size += req->u.io.queued_bytes; + if (handle->flags & UV_HANDLE_EMULATE_IOCP && + !RegisterWaitForSingleObject(&req->wait_handle, + req->event_handle, post_write_completion, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + } + } else { + /* Send failed due to an error, report it later */ + req->u.io.queued_bytes = 0; + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, (uv_req_t*) req); + } + + return 0; +} + + +int uv__tcp_try_write(uv_tcp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs) { + int result; + DWORD bytes; + + if (handle->stream.conn.write_reqs_pending > 0) + return UV_EAGAIN; + + result = WSASend(handle->socket, + (WSABUF*) bufs, + nbufs, + &bytes, + 0, + NULL, + NULL); + + if (result == SOCKET_ERROR) + return uv_translate_sys_error(WSAGetLastError()); + else + return bytes; +} + + +void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_req_t* req) { + DWORD bytes, flags, err; + uv_buf_t buf; + + assert(handle->type == UV_TCP); + + handle->flags &= ~UV_HANDLE_READ_PENDING; + + if (!REQ_SUCCESS(req)) { + /* An error occurred doing the read. */ + if ((handle->flags & UV_HANDLE_READING) || + !(handle->flags & UV_HANDLE_ZERO_READ)) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + buf = (handle->flags & UV_HANDLE_ZERO_READ) ? + uv_buf_init(NULL, 0) : handle->tcp.conn.read_buffer; + + err = GET_REQ_SOCK_ERROR(req); + + if (err == WSAECONNABORTED) { + /* + * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix. + */ + err = WSAECONNRESET; + } + + handle->read_cb((uv_stream_t*)handle, + uv_translate_sys_error(err), + &buf); + } + } else { + if (!(handle->flags & UV_HANDLE_ZERO_READ)) { + /* The read was done with a non-zero buffer length. */ + if (req->u.io.overlapped.InternalHigh > 0) { + /* Successful read */ + handle->read_cb((uv_stream_t*)handle, + req->u.io.overlapped.InternalHigh, + &handle->tcp.conn.read_buffer); + /* Read again only if bytes == buf.len */ + if (req->u.io.overlapped.InternalHigh < handle->tcp.conn.read_buffer.len) { + goto done; + } + } else { + /* Connection closed */ + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + handle->flags &= ~UV_HANDLE_READABLE; + + buf.base = 0; + buf.len = 0; + handle->read_cb((uv_stream_t*)handle, UV_EOF, &handle->tcp.conn.read_buffer); + goto done; + } + } + + /* Do nonblocking reads until the buffer is empty */ + while (handle->flags & UV_HANDLE_READING) { + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); + if (buf.base == NULL || buf.len == 0) { + handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); + break; + } + assert(buf.base != NULL); + + flags = 0; + if (WSARecv(handle->socket, + (WSABUF*)&buf, + 1, + &bytes, + &flags, + NULL, + NULL) != SOCKET_ERROR) { + if (bytes > 0) { + /* Successful read */ + handle->read_cb((uv_stream_t*)handle, bytes, &buf); + /* Read again only if bytes == buf.len */ + if (bytes < buf.len) { + break; + } + } else { + /* Connection closed */ + handle->flags &= ~(UV_HANDLE_READING | UV_HANDLE_READABLE); + DECREASE_ACTIVE_COUNT(loop, handle); + + handle->read_cb((uv_stream_t*)handle, UV_EOF, &buf); + break; + } + } else { + err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK) { + /* Read buffer was completely empty, report a 0-byte read. */ + handle->read_cb((uv_stream_t*)handle, 0, &buf); + } else { + /* Ouch! serious error. */ + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + + if (err == WSAECONNABORTED) { + /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with */ + /* Unix. */ + err = WSAECONNRESET; + } + + handle->read_cb((uv_stream_t*)handle, + uv_translate_sys_error(err), + &buf); + } + break; + } + } + +done: + /* Post another read if still reading and not closing. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_tcp_queue_read(loop, handle); + } + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_write_t* req) { + int err; + + assert(handle->type == UV_TCP); + + assert(handle->write_queue_size >= req->u.io.queued_bytes); + handle->write_queue_size -= req->u.io.queued_bytes; + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (req->wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(req->wait_handle); + req->wait_handle = INVALID_HANDLE_VALUE; + } + if (req->event_handle) { + CloseHandle(req->event_handle); + req->event_handle = NULL; + } + } + + if (req->cb) { + err = uv_translate_sys_error(GET_REQ_SOCK_ERROR(req)); + if (err == UV_ECONNABORTED) { + /* use UV_ECANCELED for consistency with Unix */ + err = UV_ECANCELED; + } + req->cb(req, err); + } + + handle->stream.conn.write_reqs_pending--; + if (handle->stream.conn.shutdown_req != NULL && + handle->stream.conn.write_reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_req_t* raw_req) { + uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req; + int err; + + assert(handle->type == UV_TCP); + + /* If handle->accepted_socket is not a valid socket, then */ + /* uv_queue_accept must have failed. This is a serious error. We stop */ + /* accepting connections and report this error to the connection */ + /* callback. */ + if (req->accept_socket == INVALID_SOCKET) { + if (handle->flags & UV_HANDLE_LISTENING) { + handle->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, handle); + if (handle->stream.serv.connection_cb) { + err = GET_REQ_SOCK_ERROR(req); + handle->stream.serv.connection_cb((uv_stream_t*)handle, + uv_translate_sys_error(err)); + } + } + } else if (REQ_SUCCESS(req) && + setsockopt(req->accept_socket, + SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, + (char*)&handle->socket, + sizeof(handle->socket)) == 0) { + req->next_pending = handle->tcp.serv.pending_accepts; + handle->tcp.serv.pending_accepts = req; + + /* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */ + if (handle->stream.serv.connection_cb) { + handle->stream.serv.connection_cb((uv_stream_t*)handle, 0); + } + } else { + /* Error related to accepted socket is ignored because the server */ + /* socket may still be healthy. If the server socket is broken */ + /* uv_queue_accept will detect it. */ + closesocket(req->accept_socket); + req->accept_socket = INVALID_SOCKET; + if (handle->flags & UV_HANDLE_LISTENING) { + uv_tcp_queue_accept(handle, req); + } + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_connect_t* req) { + int err; + + assert(handle->type == UV_TCP); + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + err = 0; + if (REQ_SUCCESS(req)) { + if (setsockopt(handle->socket, + SOL_SOCKET, + SO_UPDATE_CONNECT_CONTEXT, + NULL, + 0) == 0) { + uv_connection_init((uv_stream_t*)handle); + handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + loop->active_tcp_streams++; + } else { + err = WSAGetLastError(); + } + } else { + err = GET_REQ_SOCK_ERROR(req); + } + req->cb(req, uv_translate_sys_error(err)); + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex, + int tcp_connection) { + int err; + SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + &socket_info_ex->socket_info, + 0, + WSA_FLAG_OVERLAPPED); + + if (socket == INVALID_SOCKET) { + return WSAGetLastError(); + } + + err = uv_tcp_set_socket(tcp->loop, + tcp, + socket, + socket_info_ex->socket_info.iAddressFamily, + 1); + if (err) { + closesocket(socket); + return err; + } + + if (tcp_connection) { + uv_connection_init((uv_stream_t*)tcp); + tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + } + + tcp->flags |= UV_HANDLE_BOUND; + tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET; + + tcp->delayed_error = socket_info_ex->delayed_error; + + tcp->loop->active_tcp_streams++; + return 0; +} + + +int uv_tcp_nodelay(uv_tcp_t* handle, int enable) { + int err; + + if (handle->socket != INVALID_SOCKET) { + err = uv__tcp_nodelay(handle, handle->socket, enable); + if (err) + return err; + } + + if (enable) { + handle->flags |= UV_HANDLE_TCP_NODELAY; + } else { + handle->flags &= ~UV_HANDLE_TCP_NODELAY; + } + + return 0; +} + + +int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { + int err; + + if (handle->socket != INVALID_SOCKET) { + err = uv__tcp_keepalive(handle, handle->socket, enable, delay); + if (err) + return err; + } + + if (enable) { + handle->flags |= UV_HANDLE_TCP_KEEPALIVE; + } else { + handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE; + } + + /* TODO: Store delay if handle->socket isn't created yet. */ + + return 0; +} + + +int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, + LPWSAPROTOCOL_INFOW protocol_info) { + if (!(handle->flags & UV_HANDLE_CONNECTION)) { + /* + * We're about to share the socket with another process. Because + * this is a listening socket, we assume that the other process will + * be accepting connections on it. So, before sharing the socket + * with another process, we call listen here in the parent process. + */ + + if (!(handle->flags & UV_HANDLE_LISTENING)) { + if (!(handle->flags & UV_HANDLE_BOUND)) { + return ERROR_INVALID_PARAMETER; + } + + if (!(handle->delayed_error)) { + if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) { + handle->delayed_error = WSAGetLastError(); + } + } + } + } + + if (WSADuplicateSocketW(handle->socket, pid, protocol_info)) { + return WSAGetLastError(); + } + + handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET; + + return 0; +} + + +int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { + if (handle->flags & UV_HANDLE_CONNECTION) { + return UV_EINVAL; + } + + /* Check if we're already in the desired mode. */ + if ((enable && !(handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) || + (!enable && handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) { + return 0; + } + + /* Don't allow switching from single pending accept to many. */ + if (enable) { + return UV_ENOTSUP; + } + + /* Check if we're in a middle of changing the number of pending accepts. */ + if (handle->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING) { + return 0; + } + + handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; + + /* Flip the changing flag if we have already queued multiple accepts. */ + if (handle->flags & UV_HANDLE_LISTENING) { + handle->flags |= UV_HANDLE_TCP_ACCEPT_STATE_CHANGING; + } + + return 0; +} + + +static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) { + SOCKET socket = tcp->socket; + int non_ifs_lsp; + + /* Check if we have any non-IFS LSPs stacked on top of TCP */ + non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 : + uv_tcp_non_ifs_lsp_ipv4; + + /* If there are non-ifs LSPs then try to obtain a base handle for the */ + /* socket. This will always fail on Windows XP/3k. */ + if (non_ifs_lsp) { + DWORD bytes; + if (WSAIoctl(socket, + SIO_BASE_HANDLE, + NULL, + 0, + &socket, + sizeof socket, + &bytes, + NULL, + NULL) != 0) { + /* Failed. We can't do CancelIo. */ + return -1; + } + } + + assert(socket != 0 && socket != INVALID_SOCKET); + + if (!CancelIo((HANDLE) socket)) { + return GetLastError(); + } + + /* It worked. */ + return 0; +} + + +void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { + int close_socket = 1; + + if (tcp->flags & UV_HANDLE_READ_PENDING) { + /* In order for winsock to do a graceful close there must not be any */ + /* any pending reads, or the socket must be shut down for writing */ + if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) { + /* Just do shutdown on non-shared sockets, which ensures graceful close. */ + shutdown(tcp->socket, SD_SEND); + + } else if (uv_tcp_try_cancel_io(tcp) == 0) { + /* In case of a shared socket, we try to cancel all outstanding I/O, */ + /* If that works, don't close the socket yet - wait for the read req to */ + /* return and close the socket in uv_tcp_endgame. */ + close_socket = 0; + + } else { + /* When cancelling isn't possible - which could happen when an LSP is */ + /* present on an old Windows version, we will have to close the socket */ + /* with a read pending. That is not nice because trailing sent bytes */ + /* may not make it to the other side. */ + } + + } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) && + tcp->tcp.serv.accept_reqs != NULL) { + /* Under normal circumstances closesocket() will ensure that all pending */ + /* accept reqs are canceled. However, when the socket is shared the */ + /* presence of another reference to the socket in another process will */ + /* keep the accept reqs going, so we have to ensure that these are */ + /* canceled. */ + if (uv_tcp_try_cancel_io(tcp) != 0) { + /* When cancellation is not possible, there is another option: we can */ + /* close the incoming sockets, which will also cancel the accept */ + /* operations. However this is not cool because we might inadvertently */ + /* close a socket that just accepted a new connection, which will */ + /* cause the connection to be aborted. */ + unsigned int i; + for (i = 0; i < uv_simultaneous_server_accepts; i++) { + uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i]; + if (req->accept_socket != INVALID_SOCKET && + !HasOverlappedIoCompleted(&req->u.io.overlapped)) { + closesocket(req->accept_socket); + req->accept_socket = INVALID_SOCKET; + } + } + } + } + + if (tcp->flags & UV_HANDLE_READING) { + tcp->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, tcp); + } + + if (tcp->flags & UV_HANDLE_LISTENING) { + tcp->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, tcp); + } + + if (close_socket) { + closesocket(tcp->socket); + tcp->socket = INVALID_SOCKET; + tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; + } + + tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); + uv__handle_closing(tcp); + + if (tcp->reqs_pending == 0) { + uv_want_endgame(tcp->loop, (uv_handle_t*)tcp); + } +} + + +int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { + WSAPROTOCOL_INFOW protocol_info; + int opt_len; + int err; + + /* Detect the address family of the socket. */ + opt_len = (int) sizeof protocol_info; + if (getsockopt(sock, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &opt_len) == SOCKET_ERROR) { + return uv_translate_sys_error(GetLastError()); + } + + err = uv_tcp_set_socket(handle->loop, + handle, + sock, + protocol_info.iAddressFamily, + 1); + if (err) { + return uv_translate_sys_error(err); + } + + return 0; +} + + +/* This function is an egress point, i.e. it returns libuv errors rather than + * system errors. + */ +int uv__tcp_bind(uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + int err; + + err = uv_tcp_try_bind(handle, addr, addrlen, flags); + if (err) + return uv_translate_sys_error(err); + + return 0; +} + + +/* This function is an egress point, i.e. it returns libuv errors rather than + * system errors. + */ +int uv__tcp_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + uv_connect_cb cb) { + int err; + + err = uv_tcp_try_connect(req, handle, addr, addrlen, cb); + if (err) + return uv_translate_sys_error(err); + + return 0; +} diff --git a/src/win/thread.c b/src/win/thread.c new file mode 100644 index 0000000..91684e9 --- /dev/null +++ b/src/win/thread.c @@ -0,0 +1,697 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include + +#include "uv.h" +#include "internal.h" + + +#define HAVE_CONDVAR_API() (pInitializeConditionVariable != NULL) + +static int uv_cond_fallback_init(uv_cond_t* cond); +static void uv_cond_fallback_destroy(uv_cond_t* cond); +static void uv_cond_fallback_signal(uv_cond_t* cond); +static void uv_cond_fallback_broadcast(uv_cond_t* cond); +static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex); +static int uv_cond_fallback_timedwait(uv_cond_t* cond, + uv_mutex_t* mutex, uint64_t timeout); + +static int uv_cond_condvar_init(uv_cond_t* cond); +static void uv_cond_condvar_destroy(uv_cond_t* cond); +static void uv_cond_condvar_signal(uv_cond_t* cond); +static void uv_cond_condvar_broadcast(uv_cond_t* cond); +static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex); +static int uv_cond_condvar_timedwait(uv_cond_t* cond, + uv_mutex_t* mutex, uint64_t timeout); + + +static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) { + DWORD result; + HANDLE existing_event, created_event; + + created_event = CreateEvent(NULL, 1, 0, NULL); + if (created_event == 0) { + /* Could fail in a low-memory situation? */ + uv_fatal_error(GetLastError(), "CreateEvent"); + } + + existing_event = InterlockedCompareExchangePointer(&guard->event, + created_event, + NULL); + + if (existing_event == NULL) { + /* We won the race */ + callback(); + + result = SetEvent(created_event); + assert(result); + guard->ran = 1; + + } else { + /* We lost the race. Destroy the event we created and wait for the */ + /* existing one to become signaled. */ + CloseHandle(created_event); + result = WaitForSingleObject(existing_event, INFINITE); + assert(result == WAIT_OBJECT_0); + } +} + + +void uv_once(uv_once_t* guard, void (*callback)(void)) { + /* Fast case - avoid WaitForSingleObject. */ + if (guard->ran) { + return; + } + + uv__once_inner(guard, callback); +} + + +/* Verify that uv_thread_t can be stored in a TLS slot. */ +STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*)); + +static uv_key_t uv__current_thread_key; +static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT; + + +static void uv__init_current_thread_key(void) { + if (uv_key_create(&uv__current_thread_key)) + abort(); +} + + +struct thread_ctx { + void (*entry)(void* arg); + void* arg; + uv_thread_t self; +}; + + +static UINT __stdcall uv__thread_start(void* arg) { + struct thread_ctx *ctx_p; + struct thread_ctx ctx; + + ctx_p = arg; + ctx = *ctx_p; + uv__free(ctx_p); + + uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key); + uv_key_set(&uv__current_thread_key, (void*) ctx.self); + + ctx.entry(ctx.arg); + + return 0; +} + + +int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { + struct thread_ctx* ctx; + int err; + HANDLE thread; + + ctx = uv__malloc(sizeof(*ctx)); + if (ctx == NULL) + return UV_ENOMEM; + + ctx->entry = entry; + ctx->arg = arg; + + /* Create the thread in suspended state so we have a chance to pass + * its own creation handle to it */ + thread = (HANDLE) _beginthreadex(NULL, + 0, + uv__thread_start, + ctx, + CREATE_SUSPENDED, + NULL); + if (thread == NULL) { + err = errno; + uv__free(ctx); + } else { + err = 0; + *tid = thread; + ctx->self = thread; + ResumeThread(thread); + } + + switch (err) { + case 0: + return 0; + case EACCES: + return UV_EACCES; + case EAGAIN: + return UV_EAGAIN; + case EINVAL: + return UV_EINVAL; + } + + return UV_EIO; +} + + +uv_thread_t uv_thread_self(void) { + uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key); + return (uv_thread_t) uv_key_get(&uv__current_thread_key); +} + + +int uv_thread_join(uv_thread_t *tid) { + if (WaitForSingleObject(*tid, INFINITE)) + return uv_translate_sys_error(GetLastError()); + else { + CloseHandle(*tid); + *tid = 0; + return 0; + } +} + + +int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { + return *t1 == *t2; +} + + +int uv_mutex_init(uv_mutex_t* mutex) { + InitializeCriticalSection(mutex); + return 0; +} + + +void uv_mutex_destroy(uv_mutex_t* mutex) { + DeleteCriticalSection(mutex); +} + + +void uv_mutex_lock(uv_mutex_t* mutex) { + EnterCriticalSection(mutex); +} + + +int uv_mutex_trylock(uv_mutex_t* mutex) { + if (TryEnterCriticalSection(mutex)) + return 0; + else + return UV_EBUSY; +} + + +void uv_mutex_unlock(uv_mutex_t* mutex) { + LeaveCriticalSection(mutex); +} + + +int uv_rwlock_init(uv_rwlock_t* rwlock) { + /* Initialize the semaphore that acts as the write lock. */ + HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL); + if (handle == NULL) + return uv_translate_sys_error(GetLastError()); + rwlock->state_.write_semaphore_ = handle; + + /* Initialize the critical section protecting the reader count. */ + InitializeCriticalSection(&rwlock->state_.num_readers_lock_); + + /* Initialize the reader count. */ + rwlock->state_.num_readers_ = 0; + + return 0; +} + + +void uv_rwlock_destroy(uv_rwlock_t* rwlock) { + DeleteCriticalSection(&rwlock->state_.num_readers_lock_); + CloseHandle(rwlock->state_.write_semaphore_); +} + + +void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { + /* Acquire the lock that protects the reader count. */ + EnterCriticalSection(&rwlock->state_.num_readers_lock_); + + /* Increase the reader count, and lock for write if this is the first + * reader. + */ + if (++rwlock->state_.num_readers_ == 1) { + DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE); + if (r != WAIT_OBJECT_0) + uv_fatal_error(GetLastError(), "WaitForSingleObject"); + } + + /* Release the lock that protects the reader count. */ + LeaveCriticalSection(&rwlock->state_.num_readers_lock_); +} + + +int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { + int err; + + if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_)) + return UV_EBUSY; + + err = 0; + + if (rwlock->state_.num_readers_ == 0) { + /* Currently there are no other readers, which means that the write lock + * needs to be acquired. + */ + DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0); + if (r == WAIT_OBJECT_0) + rwlock->state_.num_readers_++; + else if (r == WAIT_TIMEOUT) + err = UV_EBUSY; + else if (r == WAIT_FAILED) + uv_fatal_error(GetLastError(), "WaitForSingleObject"); + + } else { + /* The write lock has already been acquired because there are other + * active readers. + */ + rwlock->state_.num_readers_++; + } + + LeaveCriticalSection(&rwlock->state_.num_readers_lock_); + return err; +} + + +void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { + EnterCriticalSection(&rwlock->state_.num_readers_lock_); + + if (--rwlock->state_.num_readers_ == 0) { + if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL)) + uv_fatal_error(GetLastError(), "ReleaseSemaphore"); + } + + LeaveCriticalSection(&rwlock->state_.num_readers_lock_); +} + + +void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { + DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE); + if (r != WAIT_OBJECT_0) + uv_fatal_error(GetLastError(), "WaitForSingleObject"); +} + + +int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { + DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0); + if (r == WAIT_OBJECT_0) + return 0; + else if (r == WAIT_TIMEOUT) + return UV_EBUSY; + else + uv_fatal_error(GetLastError(), "WaitForSingleObject"); +} + + +void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { + if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL)) + uv_fatal_error(GetLastError(), "ReleaseSemaphore"); +} + + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + *sem = CreateSemaphore(NULL, value, INT_MAX, NULL); + if (*sem == NULL) + return uv_translate_sys_error(GetLastError()); + else + return 0; +} + + +void uv_sem_destroy(uv_sem_t* sem) { + if (!CloseHandle(*sem)) + abort(); +} + + +void uv_sem_post(uv_sem_t* sem) { + if (!ReleaseSemaphore(*sem, 1, NULL)) + abort(); +} + + +void uv_sem_wait(uv_sem_t* sem) { + if (WaitForSingleObject(*sem, INFINITE) != WAIT_OBJECT_0) + abort(); +} + + +int uv_sem_trywait(uv_sem_t* sem) { + DWORD r = WaitForSingleObject(*sem, 0); + + if (r == WAIT_OBJECT_0) + return 0; + + if (r == WAIT_TIMEOUT) + return UV_EAGAIN; + + abort(); + return -1; /* Satisfy the compiler. */ +} + + +/* This condition variable implementation is based on the SetEvent solution + * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html + * We could not use the SignalObjectAndWait solution (section 3.4) because + * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and + * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs. + */ + +static int uv_cond_fallback_init(uv_cond_t* cond) { + int err; + + /* Initialize the count to 0. */ + cond->fallback.waiters_count = 0; + + InitializeCriticalSection(&cond->fallback.waiters_count_lock); + + /* Create an auto-reset event. */ + cond->fallback.signal_event = CreateEvent(NULL, /* no security */ + FALSE, /* auto-reset event */ + FALSE, /* non-signaled initially */ + NULL); /* unnamed */ + if (!cond->fallback.signal_event) { + err = GetLastError(); + goto error2; + } + + /* Create a manual-reset event. */ + cond->fallback.broadcast_event = CreateEvent(NULL, /* no security */ + TRUE, /* manual-reset */ + FALSE, /* non-signaled */ + NULL); /* unnamed */ + if (!cond->fallback.broadcast_event) { + err = GetLastError(); + goto error; + } + + return 0; + +error: + CloseHandle(cond->fallback.signal_event); +error2: + DeleteCriticalSection(&cond->fallback.waiters_count_lock); + return uv_translate_sys_error(err); +} + + +static int uv_cond_condvar_init(uv_cond_t* cond) { + pInitializeConditionVariable(&cond->cond_var); + return 0; +} + + +int uv_cond_init(uv_cond_t* cond) { + uv__once_init(); + + if (HAVE_CONDVAR_API()) + return uv_cond_condvar_init(cond); + else + return uv_cond_fallback_init(cond); +} + + +static void uv_cond_fallback_destroy(uv_cond_t* cond) { + if (!CloseHandle(cond->fallback.broadcast_event)) + abort(); + if (!CloseHandle(cond->fallback.signal_event)) + abort(); + DeleteCriticalSection(&cond->fallback.waiters_count_lock); +} + + +static void uv_cond_condvar_destroy(uv_cond_t* cond) { + /* nothing to do */ +} + + +void uv_cond_destroy(uv_cond_t* cond) { + if (HAVE_CONDVAR_API()) + uv_cond_condvar_destroy(cond); + else + uv_cond_fallback_destroy(cond); +} + + +static void uv_cond_fallback_signal(uv_cond_t* cond) { + int have_waiters; + + /* Avoid race conditions. */ + EnterCriticalSection(&cond->fallback.waiters_count_lock); + have_waiters = cond->fallback.waiters_count > 0; + LeaveCriticalSection(&cond->fallback.waiters_count_lock); + + if (have_waiters) + SetEvent(cond->fallback.signal_event); +} + + +static void uv_cond_condvar_signal(uv_cond_t* cond) { + pWakeConditionVariable(&cond->cond_var); +} + + +void uv_cond_signal(uv_cond_t* cond) { + if (HAVE_CONDVAR_API()) + uv_cond_condvar_signal(cond); + else + uv_cond_fallback_signal(cond); +} + + +static void uv_cond_fallback_broadcast(uv_cond_t* cond) { + int have_waiters; + + /* Avoid race conditions. */ + EnterCriticalSection(&cond->fallback.waiters_count_lock); + have_waiters = cond->fallback.waiters_count > 0; + LeaveCriticalSection(&cond->fallback.waiters_count_lock); + + if (have_waiters) + SetEvent(cond->fallback.broadcast_event); +} + + +static void uv_cond_condvar_broadcast(uv_cond_t* cond) { + pWakeAllConditionVariable(&cond->cond_var); +} + + +void uv_cond_broadcast(uv_cond_t* cond) { + if (HAVE_CONDVAR_API()) + uv_cond_condvar_broadcast(cond); + else + uv_cond_fallback_broadcast(cond); +} + + +static int uv_cond_wait_helper(uv_cond_t* cond, uv_mutex_t* mutex, + DWORD dwMilliseconds) { + DWORD result; + int last_waiter; + HANDLE handles[2] = { + cond->fallback.signal_event, + cond->fallback.broadcast_event + }; + + /* Avoid race conditions. */ + EnterCriticalSection(&cond->fallback.waiters_count_lock); + cond->fallback.waiters_count++; + LeaveCriticalSection(&cond->fallback.waiters_count_lock); + + /* It's ok to release the here since Win32 manual-reset events */ + /* maintain state when used with . This avoids the "lost wakeup" */ + /* bug. */ + uv_mutex_unlock(mutex); + + /* Wait for either event to become signaled due to being */ + /* called or being called. */ + result = WaitForMultipleObjects(2, handles, FALSE, dwMilliseconds); + + EnterCriticalSection(&cond->fallback.waiters_count_lock); + cond->fallback.waiters_count--; + last_waiter = result == WAIT_OBJECT_0 + 1 + && cond->fallback.waiters_count == 0; + LeaveCriticalSection(&cond->fallback.waiters_count_lock); + + /* Some thread called . */ + if (last_waiter) { + /* We're the last waiter to be notified or to stop waiting, so reset the */ + /* the manual-reset event. */ + ResetEvent(cond->fallback.broadcast_event); + } + + /* Reacquire the . */ + uv_mutex_lock(mutex); + + if (result == WAIT_OBJECT_0 || result == WAIT_OBJECT_0 + 1) + return 0; + + if (result == WAIT_TIMEOUT) + return UV_ETIMEDOUT; + + abort(); + return -1; /* Satisfy the compiler. */ +} + + +static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex) { + if (uv_cond_wait_helper(cond, mutex, INFINITE)) + abort(); +} + + +static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex) { + if (!pSleepConditionVariableCS(&cond->cond_var, mutex, INFINITE)) + abort(); +} + + +void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) { + if (HAVE_CONDVAR_API()) + uv_cond_condvar_wait(cond, mutex); + else + uv_cond_fallback_wait(cond, mutex); +} + + +static int uv_cond_fallback_timedwait(uv_cond_t* cond, + uv_mutex_t* mutex, uint64_t timeout) { + return uv_cond_wait_helper(cond, mutex, (DWORD)(timeout / 1e6)); +} + + +static int uv_cond_condvar_timedwait(uv_cond_t* cond, + uv_mutex_t* mutex, uint64_t timeout) { + if (pSleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6))) + return 0; + if (GetLastError() != ERROR_TIMEOUT) + abort(); + return UV_ETIMEDOUT; +} + + +int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, + uint64_t timeout) { + if (HAVE_CONDVAR_API()) + return uv_cond_condvar_timedwait(cond, mutex, timeout); + else + return uv_cond_fallback_timedwait(cond, mutex, timeout); +} + + +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + int err; + + barrier->n = count; + barrier->count = 0; + + err = uv_mutex_init(&barrier->mutex); + if (err) + return err; + + err = uv_sem_init(&barrier->turnstile1, 0); + if (err) + goto error2; + + err = uv_sem_init(&barrier->turnstile2, 1); + if (err) + goto error; + + return 0; + +error: + uv_sem_destroy(&barrier->turnstile1); +error2: + uv_mutex_destroy(&barrier->mutex); + return err; + +} + + +void uv_barrier_destroy(uv_barrier_t* barrier) { + uv_sem_destroy(&barrier->turnstile2); + uv_sem_destroy(&barrier->turnstile1); + uv_mutex_destroy(&barrier->mutex); +} + + +int uv_barrier_wait(uv_barrier_t* barrier) { + int serial_thread; + + uv_mutex_lock(&barrier->mutex); + if (++barrier->count == barrier->n) { + uv_sem_wait(&barrier->turnstile2); + uv_sem_post(&barrier->turnstile1); + } + uv_mutex_unlock(&barrier->mutex); + + uv_sem_wait(&barrier->turnstile1); + uv_sem_post(&barrier->turnstile1); + + uv_mutex_lock(&barrier->mutex); + serial_thread = (--barrier->count == 0); + if (serial_thread) { + uv_sem_wait(&barrier->turnstile1); + uv_sem_post(&barrier->turnstile2); + } + uv_mutex_unlock(&barrier->mutex); + + uv_sem_wait(&barrier->turnstile2); + uv_sem_post(&barrier->turnstile2); + return serial_thread; +} + + +int uv_key_create(uv_key_t* key) { + key->tls_index = TlsAlloc(); + if (key->tls_index == TLS_OUT_OF_INDEXES) + return UV_ENOMEM; + return 0; +} + + +void uv_key_delete(uv_key_t* key) { + if (TlsFree(key->tls_index) == FALSE) + abort(); + key->tls_index = TLS_OUT_OF_INDEXES; +} + + +void* uv_key_get(uv_key_t* key) { + void* value; + + value = TlsGetValue(key->tls_index); + if (value == NULL) + if (GetLastError() != ERROR_SUCCESS) + abort(); + + return value; +} + + +void uv_key_set(uv_key_t* key, void* value) { + if (TlsSetValue(key->tls_index, value) == FALSE) + abort(); +} diff --git a/src/win/timer.c b/src/win/timer.c new file mode 100644 index 0000000..27ca771 --- /dev/null +++ b/src/win/timer.c @@ -0,0 +1,195 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "tree.h" +#include "handle-inl.h" + + +/* The number of milliseconds in one second. */ +#define UV__MILLISEC 1000 + + +void uv_update_time(uv_loop_t* loop) { + uint64_t new_time = uv__hrtime(UV__MILLISEC); + assert(new_time >= loop->time); + loop->time = new_time; +} + + +static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) { + if (a->due < b->due) + return -1; + if (a->due > b->due) + return 1; + /* + * compare start_id when both has the same due. start_id is + * allocated with loop->timer_counter in uv_timer_start(). + */ + if (a->start_id < b->start_id) + return -1; + if (a->start_id > b->start_id) + return 1; + return 0; +} + + +RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare); + + +int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { + uv__handle_init(loop, (uv_handle_t*) handle, UV_TIMER); + handle->timer_cb = NULL; + handle->repeat = 0; + + return 0; +} + + +void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) { + if (handle->flags & UV__HANDLE_CLOSING) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); + } +} + + +static uint64_t get_clamped_due_time(uint64_t loop_time, uint64_t timeout) { + uint64_t clamped_timeout; + + clamped_timeout = loop_time + timeout; + if (clamped_timeout < timeout) + clamped_timeout = (uint64_t) -1; + + return clamped_timeout; +} + + +int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout, + uint64_t repeat) { + uv_loop_t* loop = handle->loop; + uv_timer_t* old; + + if (timer_cb == NULL) + return UV_EINVAL; + + if (uv__is_active(handle)) + uv_timer_stop(handle); + + handle->timer_cb = timer_cb; + handle->due = get_clamped_due_time(loop->time, timeout); + handle->repeat = repeat; + uv__handle_start(handle); + + /* start_id is the second index to be compared in uv__timer_cmp() */ + handle->start_id = handle->loop->timer_counter++; + + old = RB_INSERT(uv_timer_tree_s, &loop->timers, handle); + assert(old == NULL); + + return 0; +} + + +int uv_timer_stop(uv_timer_t* handle) { + uv_loop_t* loop = handle->loop; + + if (!uv__is_active(handle)) + return 0; + + RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); + uv__handle_stop(handle); + + return 0; +} + + +int uv_timer_again(uv_timer_t* handle) { + /* If timer_cb is NULL that means that the timer was never started. */ + if (!handle->timer_cb) { + return UV_EINVAL; + } + + if (handle->repeat) { + uv_timer_stop(handle); + uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat); + } + + return 0; +} + + +void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) { + assert(handle->type == UV_TIMER); + handle->repeat = repeat; +} + + +uint64_t uv_timer_get_repeat(const uv_timer_t* handle) { + assert(handle->type == UV_TIMER); + return handle->repeat; +} + + +DWORD uv__next_timeout(const uv_loop_t* loop) { + uv_timer_t* timer; + int64_t delta; + + /* Check if there are any running timers + * Need to cast away const first, since RB_MIN doesn't know what we are + * going to do with this return value, it can't be marked const + */ + timer = RB_MIN(uv_timer_tree_s, &((uv_loop_t*)loop)->timers); + if (timer) { + delta = timer->due - loop->time; + if (delta >= UINT_MAX - 1) { + /* A timeout value of UINT_MAX means infinite, so that's no good. */ + return UINT_MAX - 1; + } else if (delta < 0) { + /* Negative timeout values are not allowed */ + return 0; + } else { + return (DWORD)delta; + } + } else { + /* No timers */ + return INFINITE; + } +} + + +void uv_process_timers(uv_loop_t* loop) { + uv_timer_t* timer; + + /* Call timer callbacks */ + for (timer = RB_MIN(uv_timer_tree_s, &loop->timers); + timer != NULL && timer->due <= loop->time; + timer = RB_MIN(uv_timer_tree_s, &loop->timers)) { + + uv_timer_stop(timer); + uv_timer_again(timer); + timer->timer_cb((uv_timer_t*) timer); + } +} diff --git a/src/win/tty.c b/src/win/tty.c new file mode 100644 index 0000000..0975b33 --- /dev/null +++ b/src/win/tty.c @@ -0,0 +1,2237 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#ifndef COMMON_LVB_REVERSE_VIDEO +# define COMMON_LVB_REVERSE_VIDEO 0x4000 +#endif + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" + +#ifndef InterlockedOr +# define InterlockedOr _InterlockedOr +#endif + +#define UNICODE_REPLACEMENT_CHARACTER (0xfffd) + +#define ANSI_NORMAL 0x00 +#define ANSI_ESCAPE_SEEN 0x02 +#define ANSI_CSI 0x04 +#define ANSI_ST_CONTROL 0x08 +#define ANSI_IGNORE 0x10 +#define ANSI_IN_ARG 0x20 +#define ANSI_IN_STRING 0x40 +#define ANSI_BACKSLASH_SEEN 0x80 + +#define MAX_INPUT_BUFFER_LENGTH 8192 + +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif + +static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info); +static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); +static int uv__cancel_read_console(uv_tty_t* handle); + + +/* Null uv_buf_t */ +static const uv_buf_t uv_null_buf_ = { 0, NULL }; + +enum uv__read_console_status_e { + NOT_STARTED, + IN_PROGRESS, + TRAP_REQUESTED, + COMPLETED +}; + +static volatile LONG uv__read_console_status = NOT_STARTED; +static volatile LONG uv__restore_screen_state; +static CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state; + + +/* + * The console virtual window. + * + * Normally cursor movement in windows is relative to the console screen buffer, + * e.g. the application is allowed to overwrite the 'history'. This is very + * inconvenient, it makes absolute cursor movement pretty useless. There is + * also the concept of 'client rect' which is defined by the actual size of + * the console window and the scroll position of the screen buffer, but it's + * very volatile because it changes when the user scrolls. + * + * To make cursor movement behave sensibly we define a virtual window to which + * cursor movement is confined. The virtual window is always as wide as the + * console screen buffer, but it's height is defined by the size of the + * console window. The top of the virtual window aligns with the position + * of the caret when the first stdout/err handle is created, unless that would + * mean that it would extend beyond the bottom of the screen buffer - in that + * that case it's located as far down as possible. + * + * When the user writes a long text or many newlines, such that the output + * reaches beyond the bottom of the virtual window, the virtual window is + * shifted downwards, but not resized. + * + * Since all tty i/o happens on the same console, this window is shared + * between all stdout/stderr handles. + */ + +static int uv_tty_virtual_offset = -1; +static int uv_tty_virtual_height = -1; +static int uv_tty_virtual_width = -1; + +static CRITICAL_SECTION uv_tty_output_lock; + +static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE; + +static WORD uv_tty_default_text_attributes = + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + +static char uv_tty_default_fg_color = 7; +static char uv_tty_default_bg_color = 0; +static char uv_tty_default_fg_bright = 0; +static char uv_tty_default_bg_bright = 0; +static char uv_tty_default_inverse = 0; + +typedef enum { + UV_SUPPORTED, + UV_UNCHECKED, + UV_UNSUPPORTED +} uv_vtermstate_t; +/* Determine whether or not ANSI support is enabled. */ +static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED; +static void uv__determine_vterm_state(HANDLE handle); + +void uv_console_init() { + InitializeCriticalSection(&uv_tty_output_lock); +} + + +int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { + HANDLE handle; + CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; + + handle = (HANDLE) uv__get_osfhandle(fd); + if (handle == INVALID_HANDLE_VALUE) + return UV_EBADF; + + if (fd <= 2) { + /* In order to avoid closing a stdio file descriptor 0-2, duplicate the + * underlying OS handle and forget about the original fd. + * We could also opt to use the original OS handle and just never close it, + * but then there would be no reliable way to cancel pending read operations + * upon close. + */ + if (!DuplicateHandle(INVALID_HANDLE_VALUE, + handle, + INVALID_HANDLE_VALUE, + &handle, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)) + return uv_translate_sys_error(GetLastError()); + fd = -1; + } + + if (!readable) { + /* Obtain the screen buffer info with the output handle. */ + if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) { + return uv_translate_sys_error(GetLastError()); + } + + /* Obtain the the tty_output_lock because the virtual window state is */ + /* shared between all uv_tty_t handles. */ + EnterCriticalSection(&uv_tty_output_lock); + + if (uv__vterm_state == UV_UNCHECKED) + uv__determine_vterm_state(handle); + + /* Store the global tty output handle. This handle is used by TTY read */ + /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */ + /* is received. */ + uv_tty_output_handle = handle; + + /* Remember the original console text attributes. */ + uv_tty_capture_initial_style(&screen_buffer_info); + + uv_tty_update_virtual_window(&screen_buffer_info); + + LeaveCriticalSection(&uv_tty_output_lock); + } + + + uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY); + uv_connection_init((uv_stream_t*) tty); + + tty->handle = handle; + tty->u.fd = fd; + tty->reqs_pending = 0; + tty->flags |= UV_HANDLE_BOUND; + + if (readable) { + /* Initialize TTY input specific fields. */ + tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE; + /* TODO: remove me in v2.x. */ + tty->tty.rd.unused_ = NULL; + tty->tty.rd.read_line_buffer = uv_null_buf_; + tty->tty.rd.read_raw_wait = NULL; + + /* Init keycode-to-vt100 mapper state. */ + tty->tty.rd.last_key_len = 0; + tty->tty.rd.last_key_offset = 0; + tty->tty.rd.last_utf16_high_surrogate = 0; + memset(&tty->tty.rd.last_input_record, 0, sizeof tty->tty.rd.last_input_record); + } else { + /* TTY output specific fields. */ + tty->flags |= UV_HANDLE_WRITABLE; + + /* Init utf8-to-utf16 conversion state. */ + tty->tty.wr.utf8_bytes_left = 0; + tty->tty.wr.utf8_codepoint = 0; + + /* Initialize eol conversion state */ + tty->tty.wr.previous_eol = 0; + + /* Init ANSI parser state. */ + tty->tty.wr.ansi_parser_state = ANSI_NORMAL; + } + + return 0; +} + + +/* Set the default console text attributes based on how the console was + * configured when libuv started. + */ +static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) { + static int style_captured = 0; + + /* Only do this once. + Assumption: Caller has acquired uv_tty_output_lock. */ + if (style_captured) + return; + + /* Save raw win32 attributes. */ + uv_tty_default_text_attributes = info->wAttributes; + + /* Convert black text on black background to use white text. */ + if (uv_tty_default_text_attributes == 0) + uv_tty_default_text_attributes = 7; + + /* Convert Win32 attributes to ANSI colors. */ + uv_tty_default_fg_color = 0; + uv_tty_default_bg_color = 0; + uv_tty_default_fg_bright = 0; + uv_tty_default_bg_bright = 0; + uv_tty_default_inverse = 0; + + if (uv_tty_default_text_attributes & FOREGROUND_RED) + uv_tty_default_fg_color |= 1; + + if (uv_tty_default_text_attributes & FOREGROUND_GREEN) + uv_tty_default_fg_color |= 2; + + if (uv_tty_default_text_attributes & FOREGROUND_BLUE) + uv_tty_default_fg_color |= 4; + + if (uv_tty_default_text_attributes & BACKGROUND_RED) + uv_tty_default_bg_color |= 1; + + if (uv_tty_default_text_attributes & BACKGROUND_GREEN) + uv_tty_default_bg_color |= 2; + + if (uv_tty_default_text_attributes & BACKGROUND_BLUE) + uv_tty_default_bg_color |= 4; + + if (uv_tty_default_text_attributes & FOREGROUND_INTENSITY) + uv_tty_default_fg_bright = 1; + + if (uv_tty_default_text_attributes & BACKGROUND_INTENSITY) + uv_tty_default_bg_bright = 1; + + if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO) + uv_tty_default_inverse = 1; + + style_captured = 1; +} + + +int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { + DWORD flags; + unsigned char was_reading; + uv_alloc_cb alloc_cb; + uv_read_cb read_cb; + int err; + + if (!(tty->flags & UV_HANDLE_TTY_READABLE)) { + return UV_EINVAL; + } + + if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) { + return 0; + } + + switch (mode) { + case UV_TTY_MODE_NORMAL: + flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; + break; + case UV_TTY_MODE_RAW: + flags = ENABLE_WINDOW_INPUT; + break; + case UV_TTY_MODE_IO: + return UV_ENOTSUP; + default: + return UV_EINVAL; + } + + if (!SetConsoleMode(tty->handle, flags)) { + return uv_translate_sys_error(GetLastError()); + } + + /* If currently reading, stop, and restart reading. */ + if (tty->flags & UV_HANDLE_READING) { + was_reading = 1; + alloc_cb = tty->alloc_cb; + read_cb = tty->read_cb; + err = uv_tty_read_stop(tty); + if (err) { + return uv_translate_sys_error(err); + } + } else { + was_reading = 0; + } + + /* Update flag. */ + tty->flags &= ~UV_HANDLE_TTY_RAW; + tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0; + + /* If we just stopped reading, restart. */ + if (was_reading) { + err = uv_tty_read_start(tty, alloc_cb, read_cb); + if (err) { + return uv_translate_sys_error(err); + } + } + + return 0; +} + + +int uv_is_tty(uv_file file) { + DWORD result; + return GetConsoleMode((HANDLE) _get_osfhandle(file), &result) != 0; +} + + +int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { + CONSOLE_SCREEN_BUFFER_INFO info; + + if (!GetConsoleScreenBufferInfo(tty->handle, &info)) { + return uv_translate_sys_error(GetLastError()); + } + + EnterCriticalSection(&uv_tty_output_lock); + uv_tty_update_virtual_window(&info); + LeaveCriticalSection(&uv_tty_output_lock); + + *width = uv_tty_virtual_width; + *height = uv_tty_virtual_height; + + return 0; +} + + +static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) { + uv_loop_t* loop; + uv_tty_t* handle; + uv_req_t* req; + + assert(data); + assert(!didTimeout); + + req = (uv_req_t*) data; + handle = (uv_tty_t*) req->data; + loop = handle->loop; + + UnregisterWait(handle->tty.rd.read_raw_wait); + handle->tty.rd.read_raw_wait = NULL; + + SET_REQ_SUCCESS(req); + POST_COMPLETION_FOR_REQ(loop, req); +} + + +static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) { + uv_read_t* req; + BOOL r; + + assert(handle->flags & UV_HANDLE_READING); + assert(!(handle->flags & UV_HANDLE_READ_PENDING)); + + assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE); + + handle->tty.rd.read_line_buffer = uv_null_buf_; + + req = &handle->read_req; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + + r = RegisterWaitForSingleObject(&handle->tty.rd.read_raw_wait, + handle->handle, + uv_tty_post_raw_read, + (void*) req, + INFINITE, + WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE); + if (!r) { + handle->tty.rd.read_raw_wait = NULL; + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + } + + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; +} + + +static DWORD CALLBACK uv_tty_line_read_thread(void* data) { + uv_loop_t* loop; + uv_tty_t* handle; + uv_req_t* req; + DWORD bytes, read_bytes; + WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3]; + DWORD chars, read_chars; + LONG status; + COORD pos; + + assert(data); + + req = (uv_req_t*) data; + handle = (uv_tty_t*) req->data; + loop = handle->loop; + + assert(handle->tty.rd.read_line_buffer.base != NULL); + assert(handle->tty.rd.read_line_buffer.len > 0); + + /* ReadConsole can't handle big buffers. */ + if (handle->tty.rd.read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) { + bytes = handle->tty.rd.read_line_buffer.len; + } else { + bytes = MAX_INPUT_BUFFER_LENGTH; + } + + /* At last, unicode! */ + /* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */ + chars = bytes / 3; + + status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS); + if (status == TRAP_REQUESTED) { + SET_REQ_SUCCESS(req); + req->u.io.overlapped.InternalHigh = 0; + POST_COMPLETION_FOR_REQ(loop, req); + return 0; + } + + if (ReadConsoleW(handle->handle, + (void*) utf16, + chars, + &read_chars, + NULL)) { + read_bytes = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + read_chars, + handle->tty.rd.read_line_buffer.base, + bytes, + NULL, + NULL); + SET_REQ_SUCCESS(req); + req->u.io.overlapped.InternalHigh = read_bytes; + } else { + SET_REQ_ERROR(req, GetLastError()); + } + + InterlockedExchange(&uv__read_console_status, COMPLETED); + + /* If we canceled the read by sending a VK_RETURN event, restore the screen + state to undo the visual effect of the VK_RETURN*/ + if (InterlockedOr(&uv__restore_screen_state, 0)) { + HANDLE active_screen_buffer = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (active_screen_buffer != INVALID_HANDLE_VALUE) { + pos = uv__saved_screen_state.dwCursorPosition; + + /* If the cursor was at the bottom line of the screen buffer, the + VK_RETURN would have caused the buffer contents to scroll up by + one line. The right position to reset the cursor to is therefore one + line higher */ + if (pos.Y == uv__saved_screen_state.dwSize.Y - 1) + pos.Y--; + + SetConsoleCursorPosition(active_screen_buffer, pos); + CloseHandle(active_screen_buffer); + } + } + + POST_COMPLETION_FOR_REQ(loop, req); + return 0; +} + + +static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { + uv_read_t* req; + BOOL r; + + assert(handle->flags & UV_HANDLE_READING); + assert(!(handle->flags & UV_HANDLE_READ_PENDING)); + assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE); + + req = &handle->read_req; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + + handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer); + if (handle->tty.rd.read_line_buffer.base == NULL || + handle->tty.rd.read_line_buffer.len == 0) { + handle->read_cb((uv_stream_t*) handle, + UV_ENOBUFS, + &handle->tty.rd.read_line_buffer); + return; + } + assert(handle->tty.rd.read_line_buffer.base != NULL); + + /* Reset flags No locking is required since there cannot be a line read + in progress. We are also relying on the memory barrier provided by + QueueUserWorkItem*/ + uv__restore_screen_state = FALSE; + uv__read_console_status = NOT_STARTED; + r = QueueUserWorkItem(uv_tty_line_read_thread, + (void*) req, + WT_EXECUTELONGFUNCTION); + if (!r) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + } + + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; +} + + +static void uv_tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) { + if (handle->flags & UV_HANDLE_TTY_RAW) { + uv_tty_queue_read_raw(loop, handle); + } else { + uv_tty_queue_read_line(loop, handle); + } +} + + +static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl, + size_t* len) { +#define VK_CASE(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str) \ + case (vk): \ + if (shift && ctrl) { \ + *len = sizeof shift_ctrl_str; \ + return "\033" shift_ctrl_str; \ + } else if (shift) { \ + *len = sizeof shift_str ; \ + return "\033" shift_str; \ + } else if (ctrl) { \ + *len = sizeof ctrl_str; \ + return "\033" ctrl_str; \ + } else { \ + *len = sizeof normal_str; \ + return "\033" normal_str; \ + } + + switch (code) { + /* These mappings are the same as Cygwin's. Unmodified and alt-modified */ + /* keypad keys comply with linux console, modifiers comply with xterm */ + /* modifier usage. F1..f12 and shift-f1..f10 comply with linux console, */ + /* f6..f12 with and without modifiers comply with rxvt. */ + VK_CASE(VK_INSERT, "[2~", "[2;2~", "[2;5~", "[2;6~") + VK_CASE(VK_END, "[4~", "[4;2~", "[4;5~", "[4;6~") + VK_CASE(VK_DOWN, "[B", "[1;2B", "[1;5B", "[1;6B") + VK_CASE(VK_NEXT, "[6~", "[6;2~", "[6;5~", "[6;6~") + VK_CASE(VK_LEFT, "[D", "[1;2D", "[1;5D", "[1;6D") + VK_CASE(VK_CLEAR, "[G", "[1;2G", "[1;5G", "[1;6G") + VK_CASE(VK_RIGHT, "[C", "[1;2C", "[1;5C", "[1;6C") + VK_CASE(VK_UP, "[A", "[1;2A", "[1;5A", "[1;6A") + VK_CASE(VK_HOME, "[1~", "[1;2~", "[1;5~", "[1;6~") + VK_CASE(VK_PRIOR, "[5~", "[5;2~", "[5;5~", "[5;6~") + VK_CASE(VK_DELETE, "[3~", "[3;2~", "[3;5~", "[3;6~") + VK_CASE(VK_NUMPAD0, "[2~", "[2;2~", "[2;5~", "[2;6~") + VK_CASE(VK_NUMPAD1, "[4~", "[4;2~", "[4;5~", "[4;6~") + VK_CASE(VK_NUMPAD2, "[B", "[1;2B", "[1;5B", "[1;6B") + VK_CASE(VK_NUMPAD3, "[6~", "[6;2~", "[6;5~", "[6;6~") + VK_CASE(VK_NUMPAD4, "[D", "[1;2D", "[1;5D", "[1;6D") + VK_CASE(VK_NUMPAD5, "[G", "[1;2G", "[1;5G", "[1;6G") + VK_CASE(VK_NUMPAD6, "[C", "[1;2C", "[1;5C", "[1;6C") + VK_CASE(VK_NUMPAD7, "[A", "[1;2A", "[1;5A", "[1;6A") + VK_CASE(VK_NUMPAD8, "[1~", "[1;2~", "[1;5~", "[1;6~") + VK_CASE(VK_NUMPAD9, "[5~", "[5;2~", "[5;5~", "[5;6~") + VK_CASE(VK_DECIMAL, "[3~", "[3;2~", "[3;5~", "[3;6~") + VK_CASE(VK_F1, "[[A", "[23~", "[11^", "[23^" ) + VK_CASE(VK_F2, "[[B", "[24~", "[12^", "[24^" ) + VK_CASE(VK_F3, "[[C", "[25~", "[13^", "[25^" ) + VK_CASE(VK_F4, "[[D", "[26~", "[14^", "[26^" ) + VK_CASE(VK_F5, "[[E", "[28~", "[15^", "[28^" ) + VK_CASE(VK_F6, "[17~", "[29~", "[17^", "[29^" ) + VK_CASE(VK_F7, "[18~", "[31~", "[18^", "[31^" ) + VK_CASE(VK_F8, "[19~", "[32~", "[19^", "[32^" ) + VK_CASE(VK_F9, "[20~", "[33~", "[20^", "[33^" ) + VK_CASE(VK_F10, "[21~", "[34~", "[21^", "[34^" ) + VK_CASE(VK_F11, "[23~", "[23$", "[23^", "[23@" ) + VK_CASE(VK_F12, "[24~", "[24$", "[24^", "[24@" ) + + default: + *len = 0; + return NULL; + } +#undef VK_CASE +} + + +void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* req) { + /* Shortcut for handle->tty.rd.last_input_record.Event.KeyEvent. */ +#define KEV handle->tty.rd.last_input_record.Event.KeyEvent + + DWORD records_left, records_read; + uv_buf_t buf; + off_t buf_used; + + assert(handle->type == UV_TTY); + assert(handle->flags & UV_HANDLE_TTY_READABLE); + handle->flags &= ~UV_HANDLE_READ_PENDING; + + if (!(handle->flags & UV_HANDLE_READING) || + !(handle->flags & UV_HANDLE_TTY_RAW)) { + goto out; + } + + if (!REQ_SUCCESS(req)) { + /* An error occurred while waiting for the event. */ + if ((handle->flags & UV_HANDLE_READING)) { + handle->flags &= ~UV_HANDLE_READING; + handle->read_cb((uv_stream_t*)handle, + uv_translate_sys_error(GET_REQ_ERROR(req)), + &uv_null_buf_); + } + goto out; + } + + /* Fetch the number of events */ + if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb((uv_stream_t*)handle, + uv_translate_sys_error(GetLastError()), + &uv_null_buf_); + goto out; + } + + /* Windows sends a lot of events that we're not interested in, so buf */ + /* will be allocated on demand, when there's actually something to emit. */ + buf = uv_null_buf_; + buf_used = 0; + + while ((records_left > 0 || handle->tty.rd.last_key_len > 0) && + (handle->flags & UV_HANDLE_READING)) { + if (handle->tty.rd.last_key_len == 0) { + /* Read the next input record */ + if (!ReadConsoleInputW(handle->handle, + &handle->tty.rd.last_input_record, + 1, + &records_read)) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb((uv_stream_t*) handle, + uv_translate_sys_error(GetLastError()), + &buf); + goto out; + } + records_left--; + + /* If the window was resized, recompute the virtual window size. This */ + /* will trigger a SIGWINCH signal if the window size changed in an */ + /* way that matters to libuv. */ + if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) { + CONSOLE_SCREEN_BUFFER_INFO info; + + EnterCriticalSection(&uv_tty_output_lock); + + if (uv_tty_output_handle != INVALID_HANDLE_VALUE && + GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) { + uv_tty_update_virtual_window(&info); + } + + LeaveCriticalSection(&uv_tty_output_lock); + + continue; + } + + /* Ignore other events that are not key or resize events. */ + if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) { + continue; + } + + /* Ignore keyup events, unless the left alt key was held and a valid */ + /* unicode character was emitted. */ + if (!KEV.bKeyDown && !(((KEV.dwControlKeyState & LEFT_ALT_PRESSED) || + KEV.wVirtualKeyCode==VK_MENU) && KEV.uChar.UnicodeChar != 0)) { + continue; + } + + /* Ignore keypresses to numpad number keys if the left alt is held */ + /* because the user is composing a character, or windows simulating */ + /* this. */ + if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) && + !(KEV.dwControlKeyState & ENHANCED_KEY) && + (KEV.wVirtualKeyCode == VK_INSERT || + KEV.wVirtualKeyCode == VK_END || + KEV.wVirtualKeyCode == VK_DOWN || + KEV.wVirtualKeyCode == VK_NEXT || + KEV.wVirtualKeyCode == VK_LEFT || + KEV.wVirtualKeyCode == VK_CLEAR || + KEV.wVirtualKeyCode == VK_RIGHT || + KEV.wVirtualKeyCode == VK_HOME || + KEV.wVirtualKeyCode == VK_UP || + KEV.wVirtualKeyCode == VK_PRIOR || + KEV.wVirtualKeyCode == VK_NUMPAD0 || + KEV.wVirtualKeyCode == VK_NUMPAD1 || + KEV.wVirtualKeyCode == VK_NUMPAD2 || + KEV.wVirtualKeyCode == VK_NUMPAD3 || + KEV.wVirtualKeyCode == VK_NUMPAD4 || + KEV.wVirtualKeyCode == VK_NUMPAD5 || + KEV.wVirtualKeyCode == VK_NUMPAD6 || + KEV.wVirtualKeyCode == VK_NUMPAD7 || + KEV.wVirtualKeyCode == VK_NUMPAD8 || + KEV.wVirtualKeyCode == VK_NUMPAD9)) { + continue; + } + + if (KEV.uChar.UnicodeChar != 0) { + int prefix_len, char_len; + + /* Character key pressed */ + if (KEV.uChar.UnicodeChar >= 0xD800 && + KEV.uChar.UnicodeChar < 0xDC00) { + /* UTF-16 high surrogate */ + handle->tty.rd.last_utf16_high_surrogate = KEV.uChar.UnicodeChar; + continue; + } + + /* Prefix with \u033 if alt was held, but alt was not used as part */ + /* a compose sequence. */ + if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) + && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED | + RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) { + handle->tty.rd.last_key[0] = '\033'; + prefix_len = 1; + } else { + prefix_len = 0; + } + + if (KEV.uChar.UnicodeChar >= 0xDC00 && + KEV.uChar.UnicodeChar < 0xE000) { + /* UTF-16 surrogate pair */ + WCHAR utf16_buffer[2] = { handle->tty.rd.last_utf16_high_surrogate, + KEV.uChar.UnicodeChar}; + char_len = WideCharToMultiByte(CP_UTF8, + 0, + utf16_buffer, + 2, + &handle->tty.rd.last_key[prefix_len], + sizeof handle->tty.rd.last_key, + NULL, + NULL); + } else { + /* Single UTF-16 character */ + char_len = WideCharToMultiByte(CP_UTF8, + 0, + &KEV.uChar.UnicodeChar, + 1, + &handle->tty.rd.last_key[prefix_len], + sizeof handle->tty.rd.last_key, + NULL, + NULL); + } + + /* Whatever happened, the last character wasn't a high surrogate. */ + handle->tty.rd.last_utf16_high_surrogate = 0; + + /* If the utf16 character(s) couldn't be converted something must */ + /* be wrong. */ + if (!char_len) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb((uv_stream_t*) handle, + uv_translate_sys_error(GetLastError()), + &buf); + goto out; + } + + handle->tty.rd.last_key_len = (unsigned char) (prefix_len + char_len); + handle->tty.rd.last_key_offset = 0; + continue; + + } else { + /* Function key pressed */ + const char* vt100; + size_t prefix_len, vt100_len; + + vt100 = get_vt100_fn_key(KEV.wVirtualKeyCode, + !!(KEV.dwControlKeyState & SHIFT_PRESSED), + !!(KEV.dwControlKeyState & ( + LEFT_CTRL_PRESSED | + RIGHT_CTRL_PRESSED)), + &vt100_len); + + /* If we were unable to map to a vt100 sequence, just ignore. */ + if (!vt100) { + continue; + } + + /* Prefix with \x033 when the alt key was held. */ + if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) { + handle->tty.rd.last_key[0] = '\033'; + prefix_len = 1; + } else { + prefix_len = 0; + } + + /* Copy the vt100 sequence to the handle buffer. */ + assert(prefix_len + vt100_len < sizeof handle->tty.rd.last_key); + memcpy(&handle->tty.rd.last_key[prefix_len], vt100, vt100_len); + + handle->tty.rd.last_key_len = (unsigned char) (prefix_len + vt100_len); + handle->tty.rd.last_key_offset = 0; + continue; + } + } else { + /* Copy any bytes left from the last keypress to the user buffer. */ + if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) { + /* Allocate a buffer if needed */ + if (buf_used == 0) { + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 1024, &buf); + if (buf.base == NULL || buf.len == 0) { + handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); + goto out; + } + assert(buf.base != NULL); + } + + buf.base[buf_used++] = handle->tty.rd.last_key[handle->tty.rd.last_key_offset++]; + + /* If the buffer is full, emit it */ + if ((size_t) buf_used == buf.len) { + handle->read_cb((uv_stream_t*) handle, buf_used, &buf); + buf = uv_null_buf_; + buf_used = 0; + } + + continue; + } + + /* Apply dwRepeat from the last input record. */ + if (--KEV.wRepeatCount > 0) { + handle->tty.rd.last_key_offset = 0; + continue; + } + + handle->tty.rd.last_key_len = 0; + continue; + } + } + + /* Send the buffer back to the user */ + if (buf_used > 0) { + handle->read_cb((uv_stream_t*) handle, buf_used, &buf); + } + + out: + /* Wait for more input events. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_tty_queue_read(loop, handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); + +#undef KEV +} + + + +void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* req) { + uv_buf_t buf; + + assert(handle->type == UV_TTY); + assert(handle->flags & UV_HANDLE_TTY_READABLE); + + buf = handle->tty.rd.read_line_buffer; + + handle->flags &= ~UV_HANDLE_READ_PENDING; + handle->tty.rd.read_line_buffer = uv_null_buf_; + + if (!REQ_SUCCESS(req)) { + /* Read was not successful */ + if (handle->flags & UV_HANDLE_READING) { + /* Real error */ + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb((uv_stream_t*) handle, + uv_translate_sys_error(GET_REQ_ERROR(req)), + &buf); + } else { + /* The read was cancelled, or whatever we don't care */ + handle->read_cb((uv_stream_t*) handle, 0, &buf); + } + + } else { + if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { + /* Read successful */ + /* TODO: read unicode, convert to utf-8 */ + DWORD bytes = req->u.io.overlapped.InternalHigh; + handle->read_cb((uv_stream_t*) handle, bytes, &buf); + } else { + handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING; + handle->read_cb((uv_stream_t*) handle, 0, &buf); + } + } + + /* Wait for more input events. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_tty_queue_read(loop, handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* req) { + assert(handle->type == UV_TTY); + assert(handle->flags & UV_HANDLE_TTY_READABLE); + + /* If the read_line_buffer member is zero, it must have been an raw read. */ + /* Otherwise it was a line-buffered read. */ + /* FIXME: This is quite obscure. Use a flag or something. */ + if (handle->tty.rd.read_line_buffer.len == 0) { + uv_process_tty_read_raw_req(loop, handle, req); + } else { + uv_process_tty_read_line_req(loop, handle, req); + } +} + + +int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { + uv_loop_t* loop = handle->loop; + + if (!(handle->flags & UV_HANDLE_TTY_READABLE)) { + return ERROR_INVALID_PARAMETER; + } + + handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb = read_cb; + handle->alloc_cb = alloc_cb; + + /* If reading was stopped and then started again, there could still be a */ + /* read request pending. */ + if (handle->flags & UV_HANDLE_READ_PENDING) { + return 0; + } + + /* Maybe the user stopped reading half-way while processing key events. */ + /* Short-circuit if this could be the case. */ + if (handle->tty.rd.last_key_len > 0) { + SET_REQ_SUCCESS(&handle->read_req); + uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req); + return 0; + } + + uv_tty_queue_read(loop, handle); + + return 0; +} + + +int uv_tty_read_stop(uv_tty_t* handle) { + INPUT_RECORD record; + DWORD written, err; + + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(handle->loop, handle); + + if (!(handle->flags & UV_HANDLE_READ_PENDING)) + return 0; + + if (handle->flags & UV_HANDLE_TTY_RAW) { + /* Cancel raw read */ + /* Write some bullshit event to force the console wait to return. */ + memset(&record, 0, sizeof record); + if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { + return GetLastError(); + } + } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { + /* Cancel line-buffered read if not already pending */ + err = uv__cancel_read_console(handle); + if (err) + return err; + + handle->flags |= UV_HANDLE_CANCELLATION_PENDING; + } + + return 0; +} + +static int uv__cancel_read_console(uv_tty_t* handle) { + HANDLE active_screen_buffer = INVALID_HANDLE_VALUE; + INPUT_RECORD record; + DWORD written; + DWORD err = 0; + LONG status; + + assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)); + + status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED); + if (status != IN_PROGRESS) { + /* Either we have managed to set a trap for the other thread before + ReadConsole is called, or ReadConsole has returned because the user + has pressed ENTER. In either case, there is nothing else to do. */ + return 0; + } + + /* Save screen state before sending the VK_RETURN event */ + active_screen_buffer = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (active_screen_buffer != INVALID_HANDLE_VALUE && + GetConsoleScreenBufferInfo(active_screen_buffer, + &uv__saved_screen_state)) { + InterlockedOr(&uv__restore_screen_state, 1); + } + + /* Write enter key event to force the console wait to return. */ + record.EventType = KEY_EVENT; + record.Event.KeyEvent.bKeyDown = TRUE; + record.Event.KeyEvent.wRepeatCount = 1; + record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN; + record.Event.KeyEvent.wVirtualScanCode = + MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC); + record.Event.KeyEvent.uChar.UnicodeChar = L'\r'; + record.Event.KeyEvent.dwControlKeyState = 0; + if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) + err = GetLastError(); + + if (active_screen_buffer != INVALID_HANDLE_VALUE) + CloseHandle(active_screen_buffer); + + return err; +} + + +static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { + int old_virtual_width = uv_tty_virtual_width; + int old_virtual_height = uv_tty_virtual_height; + + uv_tty_virtual_width = info->dwSize.X; + uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1; + + /* Recompute virtual window offset row. */ + if (uv_tty_virtual_offset == -1) { + uv_tty_virtual_offset = info->dwCursorPosition.Y; + } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y - + uv_tty_virtual_height + 1) { + /* If suddenly find the cursor outside of the virtual window, it must */ + /* have somehow scrolled. Update the virtual window offset. */ + uv_tty_virtual_offset = info->dwCursorPosition.Y - + uv_tty_virtual_height + 1; + } + if (uv_tty_virtual_offset + uv_tty_virtual_height > info->dwSize.Y) { + uv_tty_virtual_offset = info->dwSize.Y - uv_tty_virtual_height; + } + if (uv_tty_virtual_offset < 0) { + uv_tty_virtual_offset = 0; + } + + /* If the virtual window size changed, emit a SIGWINCH signal. Don't emit */ + /* if this was the first time the virtual window size was computed. */ + if (old_virtual_width != -1 && old_virtual_height != -1 && + (uv_tty_virtual_width != old_virtual_width || + uv_tty_virtual_height != old_virtual_height)) { + uv__signal_dispatch(SIGWINCH); + } +} + + +static COORD uv_tty_make_real_coord(uv_tty_t* handle, + CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y, + unsigned char y_relative) { + COORD result; + + uv_tty_update_virtual_window(info); + + /* Adjust y position */ + if (y_relative) { + y = info->dwCursorPosition.Y + y; + } else { + y = uv_tty_virtual_offset + y; + } + /* Clip y to virtual client rectangle */ + if (y < uv_tty_virtual_offset) { + y = uv_tty_virtual_offset; + } else if (y >= uv_tty_virtual_offset + uv_tty_virtual_height) { + y = uv_tty_virtual_offset + uv_tty_virtual_height - 1; + } + + /* Adjust x */ + if (x_relative) { + x = info->dwCursorPosition.X + x; + } + /* Clip x */ + if (x < 0) { + x = 0; + } else if (x >= uv_tty_virtual_width) { + x = uv_tty_virtual_width - 1; + } + + result.X = (unsigned short) x; + result.Y = (unsigned short) y; + return result; +} + + +static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length, + DWORD* error) { + DWORD written; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + if (!WriteConsoleW(handle->handle, + (void*) buffer, + length, + &written, + NULL)) { + *error = GetLastError(); + return -1; + } + + return 0; +} + + +static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative, + int y, unsigned char y_relative, DWORD* error) { + CONSOLE_SCREEN_BUFFER_INFO info; + COORD pos; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + retry: + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + } + + pos = uv_tty_make_real_coord(handle, &info, x, x_relative, y, y_relative); + + if (!SetConsoleCursorPosition(handle->handle, pos)) { + if (GetLastError() == ERROR_INVALID_PARAMETER) { + /* The console may be resized - retry */ + goto retry; + } else { + *error = GetLastError(); + return -1; + } + } + + return 0; +} + + +static int uv_tty_reset(uv_tty_t* handle, DWORD* error) { + const COORD origin = {0, 0}; + const WORD char_attrs = uv_tty_default_text_attributes; + CONSOLE_SCREEN_BUFFER_INFO info; + DWORD count, written; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + /* Reset original text attributes. */ + if (!SetConsoleTextAttribute(handle->handle, char_attrs)) { + *error = GetLastError(); + return -1; + } + + /* Move the cursor position to (0, 0). */ + if (!SetConsoleCursorPosition(handle->handle, origin)) { + *error = GetLastError(); + return -1; + } + + /* Clear the screen buffer. */ + retry: + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + return -1; + } + + count = info.dwSize.X * info.dwSize.Y; + + if (!(FillConsoleOutputCharacterW(handle->handle, + L'\x20', + count, + origin, + &written) && + FillConsoleOutputAttribute(handle->handle, + char_attrs, + written, + origin, + &written))) { + if (GetLastError() == ERROR_INVALID_PARAMETER) { + /* The console may be resized - retry */ + goto retry; + } else { + *error = GetLastError(); + return -1; + } + } + + /* Move the virtual window up to the top. */ + uv_tty_virtual_offset = 0; + uv_tty_update_virtual_window(&info); + + return 0; +} + + +static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen, + DWORD* error) { + CONSOLE_SCREEN_BUFFER_INFO info; + COORD start, end; + DWORD count, written; + + int x1, x2, y1, y2; + int x1r, x2r, y1r, y2r; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + if (dir == 0) { + /* Clear from current position */ + x1 = 0; + x1r = 1; + } else { + /* Clear from column 0 */ + x1 = 0; + x1r = 0; + } + + if (dir == 1) { + /* Clear to current position */ + x2 = 0; + x2r = 1; + } else { + /* Clear to end of row. We pretend the console is 65536 characters wide, */ + /* uv_tty_make_real_coord will clip it to the actual console width. */ + x2 = 0xffff; + x2r = 0; + } + + if (!entire_screen) { + /* Stay on our own row */ + y1 = y2 = 0; + y1r = y2r = 1; + } else { + /* Apply columns direction to row */ + y1 = x1; + y1r = x1r; + y2 = x2; + y2r = x2r; + } + + retry: + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + return -1; + } + + start = uv_tty_make_real_coord(handle, &info, x1, x1r, y1, y1r); + end = uv_tty_make_real_coord(handle, &info, x2, x2r, y2, y2r); + count = (end.Y * info.dwSize.X + end.X) - + (start.Y * info.dwSize.X + start.X) + 1; + + if (!(FillConsoleOutputCharacterW(handle->handle, + L'\x20', + count, + start, + &written) && + FillConsoleOutputAttribute(handle->handle, + info.wAttributes, + written, + start, + &written))) { + if (GetLastError() == ERROR_INVALID_PARAMETER) { + /* The console may be resized - retry */ + goto retry; + } else { + *error = GetLastError(); + return -1; + } + } + + return 0; +} + +#define FLIP_FGBG \ + do { \ + WORD fg = info.wAttributes & 0xF; \ + WORD bg = info.wAttributes & 0xF0; \ + info.wAttributes &= 0xFF00; \ + info.wAttributes |= fg << 4; \ + info.wAttributes |= bg >> 4; \ + } while (0) + +static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) { + unsigned short argc = handle->tty.wr.ansi_csi_argc; + unsigned short* argv = handle->tty.wr.ansi_csi_argv; + int i; + CONSOLE_SCREEN_BUFFER_INFO info; + + char fg_color = -1, bg_color = -1; + char fg_bright = -1, bg_bright = -1; + char inverse = -1; + + if (argc == 0) { + /* Reset mode */ + fg_color = uv_tty_default_fg_color; + bg_color = uv_tty_default_bg_color; + fg_bright = uv_tty_default_fg_bright; + bg_bright = uv_tty_default_bg_bright; + inverse = uv_tty_default_inverse; + } + + for (i = 0; i < argc; i++) { + short arg = argv[i]; + + if (arg == 0) { + /* Reset mode */ + fg_color = uv_tty_default_fg_color; + bg_color = uv_tty_default_bg_color; + fg_bright = uv_tty_default_fg_bright; + bg_bright = uv_tty_default_bg_bright; + inverse = uv_tty_default_inverse; + + } else if (arg == 1) { + /* Foreground bright on */ + fg_bright = 1; + + } else if (arg == 2) { + /* Both bright off */ + fg_bright = 0; + bg_bright = 0; + + } else if (arg == 5) { + /* Background bright on */ + bg_bright = 1; + + } else if (arg == 7) { + /* Inverse: on */ + inverse = 1; + + } else if (arg == 21 || arg == 22) { + /* Foreground bright off */ + fg_bright = 0; + + } else if (arg == 25) { + /* Background bright off */ + bg_bright = 0; + + } else if (arg == 27) { + /* Inverse: off */ + inverse = 0; + + } else if (arg >= 30 && arg <= 37) { + /* Set foreground color */ + fg_color = arg - 30; + + } else if (arg == 39) { + /* Default text color */ + fg_color = uv_tty_default_fg_color; + fg_bright = uv_tty_default_fg_bright; + + } else if (arg >= 40 && arg <= 47) { + /* Set background color */ + bg_color = arg - 40; + + } else if (arg == 49) { + /* Default background color */ + bg_color = uv_tty_default_bg_color; + bg_bright = uv_tty_default_bg_bright; + + } else if (arg >= 90 && arg <= 97) { + /* Set bold foreground color */ + fg_bright = 1; + fg_color = arg - 90; + + } else if (arg >= 100 && arg <= 107) { + /* Set bold background color */ + bg_bright = 1; + bg_color = arg - 100; + + } + } + + if (fg_color == -1 && bg_color == -1 && fg_bright == -1 && + bg_bright == -1 && inverse == -1) { + /* Nothing changed */ + return 0; + } + + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + return -1; + } + + if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) { + FLIP_FGBG; + } + + if (fg_color != -1) { + info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + if (fg_color & 1) info.wAttributes |= FOREGROUND_RED; + if (fg_color & 2) info.wAttributes |= FOREGROUND_GREEN; + if (fg_color & 4) info.wAttributes |= FOREGROUND_BLUE; + } + + if (fg_bright != -1) { + if (fg_bright) { + info.wAttributes |= FOREGROUND_INTENSITY; + } else { + info.wAttributes &= ~FOREGROUND_INTENSITY; + } + } + + if (bg_color != -1) { + info.wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + if (bg_color & 1) info.wAttributes |= BACKGROUND_RED; + if (bg_color & 2) info.wAttributes |= BACKGROUND_GREEN; + if (bg_color & 4) info.wAttributes |= BACKGROUND_BLUE; + } + + if (bg_bright != -1) { + if (bg_bright) { + info.wAttributes |= BACKGROUND_INTENSITY; + } else { + info.wAttributes &= ~BACKGROUND_INTENSITY; + } + } + + if (inverse != -1) { + if (inverse) { + info.wAttributes |= COMMON_LVB_REVERSE_VIDEO; + } else { + info.wAttributes &= ~COMMON_LVB_REVERSE_VIDEO; + } + } + + if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) { + FLIP_FGBG; + } + + if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) { + *error = GetLastError(); + return -1; + } + + return 0; +} + + +static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes, + DWORD* error) { + CONSOLE_SCREEN_BUFFER_INFO info; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + return -1; + } + + uv_tty_update_virtual_window(&info); + + handle->tty.wr.saved_position.X = info.dwCursorPosition.X; + handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset; + handle->flags |= UV_HANDLE_TTY_SAVED_POSITION; + + if (save_attributes) { + handle->tty.wr.saved_attributes = info.wAttributes & + (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY); + handle->flags |= UV_HANDLE_TTY_SAVED_ATTRIBUTES; + } + + return 0; +} + + +static int uv_tty_restore_state(uv_tty_t* handle, + unsigned char restore_attributes, DWORD* error) { + CONSOLE_SCREEN_BUFFER_INFO info; + WORD new_attributes; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) { + if (uv_tty_move_caret(handle, + handle->tty.wr.saved_position.X, + 0, + handle->tty.wr.saved_position.Y, + 0, + error) != 0) { + return -1; + } + } + + if (restore_attributes && + (handle->flags & UV_HANDLE_TTY_SAVED_ATTRIBUTES)) { + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + return -1; + } + + new_attributes = info.wAttributes; + new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY); + new_attributes |= handle->tty.wr.saved_attributes; + + if (!SetConsoleTextAttribute(handle->handle, new_attributes)) { + *error = GetLastError(); + return -1; + } + } + + return 0; +} + +static int uv_tty_set_cursor_visibility(uv_tty_t* handle, + BOOL visible, + DWORD* error) { + CONSOLE_CURSOR_INFO cursor_info; + + if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) { + *error = GetLastError(); + return -1; + } + + cursor_info.bVisible = visible; + + if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) { + *error = GetLastError(); + return -1; + } + + return 0; +} + +static int uv_tty_write_bufs(uv_tty_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + DWORD* error) { + /* We can only write 8k characters at a time. Windows can't handle */ + /* much more characters in a single console write anyway. */ + WCHAR utf16_buf[8192]; + DWORD utf16_buf_used = 0; + unsigned int i; + +#define FLUSH_TEXT() \ + do { \ + if (utf16_buf_used > 0) { \ + uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \ + utf16_buf_used = 0; \ + } \ + } while (0) + +#define ENSURE_BUFFER_SPACE(wchars_needed) \ + if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \ + FLUSH_TEXT(); \ + } + + /* Cache for fast access */ + unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left; + unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint; + unsigned char previous_eol = handle->tty.wr.previous_eol; + unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state; + + /* Store the error here. If we encounter an error, stop trying to do i/o */ + /* but keep parsing the buffer so we leave the parser in a consistent */ + /* state. */ + *error = ERROR_SUCCESS; + + EnterCriticalSection(&uv_tty_output_lock); + + for (i = 0; i < nbufs; i++) { + uv_buf_t buf = bufs[i]; + unsigned int j; + + if (uv__vterm_state == UV_SUPPORTED) { + utf16_buf_used = MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + NULL, + 0); + + if (utf16_buf_used == 0) { + *error = GetLastError(); + break; + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + utf16_buf, + utf16_buf_used)) { + *error = GetLastError(); + break; + } + + FLUSH_TEXT(); + continue; + } + + for (j = 0; j < buf.len; j++) { + unsigned char c = buf.base[j]; + + /* Run the character through the utf8 decoder We happily accept non */ + /* shortest form encodings and invalid code points - there's no real */ + /* harm that can be done. */ + if (utf8_bytes_left == 0) { + /* Read utf-8 start byte */ + DWORD first_zero_bit; + unsigned char not_c = ~c; +#ifdef _MSC_VER /* msvc */ + if (_BitScanReverse(&first_zero_bit, not_c)) { +#else /* assume gcc */ + if (c != 0) { + first_zero_bit = (sizeof(int) * 8) - 1 - __builtin_clz(not_c); +#endif + if (first_zero_bit == 7) { + /* Ascii - pass right through */ + utf8_codepoint = (unsigned int) c; + + } else if (first_zero_bit <= 5) { + /* Multibyte sequence */ + utf8_codepoint = (0xff >> (8 - first_zero_bit)) & c; + utf8_bytes_left = (char) (6 - first_zero_bit); + + } else { + /* Invalid continuation */ + utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; + } + + } else { + /* 0xff -- invalid */ + utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; + } + + } else if ((c & 0xc0) == 0x80) { + /* Valid continuation of utf-8 multibyte sequence */ + utf8_bytes_left--; + utf8_codepoint <<= 6; + utf8_codepoint |= ((unsigned int) c & 0x3f); + + } else { + /* Start byte where continuation was expected. */ + utf8_bytes_left = 0; + utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; + /* Patch buf offset so this character will be parsed again as a */ + /* start byte. */ + j--; + } + + /* Maybe we need to parse more bytes to find a character. */ + if (utf8_bytes_left != 0) { + continue; + } + + /* Parse vt100/ansi escape codes */ + if (ansi_parser_state == ANSI_NORMAL) { + switch (utf8_codepoint) { + case '\033': + ansi_parser_state = ANSI_ESCAPE_SEEN; + continue; + + case 0233: + ansi_parser_state = ANSI_CSI; + handle->tty.wr.ansi_csi_argc = 0; + continue; + } + + } else if (ansi_parser_state == ANSI_ESCAPE_SEEN) { + switch (utf8_codepoint) { + case '[': + ansi_parser_state = ANSI_CSI; + handle->tty.wr.ansi_csi_argc = 0; + continue; + + case '^': + case '_': + case 'P': + case ']': + /* Not supported, but we'll have to parse until we see a stop */ + /* code, e.g. ESC \ or BEL. */ + ansi_parser_state = ANSI_ST_CONTROL; + continue; + + case '\033': + /* Ignore double escape. */ + continue; + + case 'c': + /* Full console reset. */ + FLUSH_TEXT(); + uv_tty_reset(handle, error); + ansi_parser_state = ANSI_NORMAL; + continue; + + case '7': + /* Save the cursor position and text attributes. */ + FLUSH_TEXT(); + uv_tty_save_state(handle, 1, error); + ansi_parser_state = ANSI_NORMAL; + continue; + + case '8': + /* Restore the cursor position and text attributes */ + FLUSH_TEXT(); + uv_tty_restore_state(handle, 1, error); + ansi_parser_state = ANSI_NORMAL; + continue; + + default: + if (utf8_codepoint >= '@' && utf8_codepoint <= '_') { + /* Single-char control. */ + ansi_parser_state = ANSI_NORMAL; + continue; + } else { + /* Invalid - proceed as normal, */ + ansi_parser_state = ANSI_NORMAL; + } + } + + } else if (ansi_parser_state & ANSI_CSI) { + if (!(ansi_parser_state & ANSI_IGNORE)) { + if (utf8_codepoint >= '0' && utf8_codepoint <= '9') { + /* Parsing a numerical argument */ + + if (!(ansi_parser_state & ANSI_IN_ARG)) { + /* We were not currently parsing a number */ + + /* Check for too many arguments */ + if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) { + ansi_parser_state |= ANSI_IGNORE; + continue; + } + + ansi_parser_state |= ANSI_IN_ARG; + handle->tty.wr.ansi_csi_argc++; + handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = + (unsigned short) utf8_codepoint - '0'; + continue; + } else { + /* We were already parsing a number. Parse next digit. */ + uint32_t value = 10 * + handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1]; + + /* Check for overflow. */ + if (value > UINT16_MAX) { + ansi_parser_state |= ANSI_IGNORE; + continue; + } + + handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = + (unsigned short) value + (utf8_codepoint - '0'); + continue; + } + + } else if (utf8_codepoint == ';') { + /* Denotes the end of an argument. */ + if (ansi_parser_state & ANSI_IN_ARG) { + ansi_parser_state &= ~ANSI_IN_ARG; + continue; + + } else { + /* If ANSI_IN_ARG is not set, add another argument and */ + /* default it to 0. */ + /* Check for too many arguments */ + if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) { + ansi_parser_state |= ANSI_IGNORE; + continue; + } + + handle->tty.wr.ansi_csi_argc++; + handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0; + continue; + } + + } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) && + handle->tty.wr.ansi_csi_argc == 0) { + /* Ignores '?' if it is the first character after CSI[ */ + /* This is an extension character from the VT100 codeset */ + /* that is supported and used by most ANSI terminals today. */ + continue; + + } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' && + (handle->tty.wr.ansi_csi_argc > 0 || utf8_codepoint != '[')) { + int x, y, d; + + /* Command byte */ + switch (utf8_codepoint) { + case 'A': + /* cursor up */ + FLUSH_TEXT(); + y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1); + uv_tty_move_caret(handle, 0, 1, y, 1, error); + break; + + case 'B': + /* cursor down */ + FLUSH_TEXT(); + y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1; + uv_tty_move_caret(handle, 0, 1, y, 1, error); + break; + + case 'C': + /* cursor forward */ + FLUSH_TEXT(); + x = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1; + uv_tty_move_caret(handle, x, 1, 0, 1, error); + break; + + case 'D': + /* cursor back */ + FLUSH_TEXT(); + x = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1); + uv_tty_move_caret(handle, x, 1, 0, 1, error); + break; + + case 'E': + /* cursor next line */ + FLUSH_TEXT(); + y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1; + uv_tty_move_caret(handle, 0, 0, y, 1, error); + break; + + case 'F': + /* cursor previous line */ + FLUSH_TEXT(); + y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1); + uv_tty_move_caret(handle, 0, 0, y, 1, error); + break; + + case 'G': + /* cursor horizontal move absolute */ + FLUSH_TEXT(); + x = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0]) + ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0; + uv_tty_move_caret(handle, x, 0, 0, 1, error); + break; + + case 'H': + case 'f': + /* cursor move absolute */ + FLUSH_TEXT(); + y = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0]) + ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0; + x = (handle->tty.wr.ansi_csi_argc >= 2 && handle->tty.wr.ansi_csi_argv[1]) + ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0; + uv_tty_move_caret(handle, x, 0, y, 0, error); + break; + + case 'J': + /* Erase screen */ + FLUSH_TEXT(); + d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0; + if (d >= 0 && d <= 2) { + uv_tty_clear(handle, d, 1, error); + } + break; + + case 'K': + /* Erase line */ + FLUSH_TEXT(); + d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0; + if (d >= 0 && d <= 2) { + uv_tty_clear(handle, d, 0, error); + } + break; + + case 'm': + /* Set style */ + FLUSH_TEXT(); + uv_tty_set_style(handle, error); + break; + + case 's': + /* Save the cursor position. */ + FLUSH_TEXT(); + uv_tty_save_state(handle, 0, error); + break; + + case 'u': + /* Restore the cursor position */ + FLUSH_TEXT(); + uv_tty_restore_state(handle, 0, error); + break; + + case 'l': + /* Hide the cursor */ + if (handle->tty.wr.ansi_csi_argc == 1 && + handle->tty.wr.ansi_csi_argv[0] == 25) { + FLUSH_TEXT(); + uv_tty_set_cursor_visibility(handle, 0, error); + } + break; + + case 'h': + /* Show the cursor */ + if (handle->tty.wr.ansi_csi_argc == 1 && + handle->tty.wr.ansi_csi_argv[0] == 25) { + FLUSH_TEXT(); + uv_tty_set_cursor_visibility(handle, 1, error); + } + break; + } + + /* Sequence ended - go back to normal state. */ + ansi_parser_state = ANSI_NORMAL; + continue; + + } else { + /* We don't support commands that use private mode characters or */ + /* intermediaries. Ignore the rest of the sequence. */ + ansi_parser_state |= ANSI_IGNORE; + continue; + } + } else { + /* We're ignoring this command. Stop only on command character. */ + if (utf8_codepoint >= '@' && utf8_codepoint <= '~') { + ansi_parser_state = ANSI_NORMAL; + } + continue; + } + + } else if (ansi_parser_state & ANSI_ST_CONTROL) { + /* Unsupported control code */ + /* Ignore everything until we see BEL or ESC \ */ + if (ansi_parser_state & ANSI_IN_STRING) { + if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) { + if (utf8_codepoint == '"') { + ansi_parser_state &= ~ANSI_IN_STRING; + } else if (utf8_codepoint == '\\') { + ansi_parser_state |= ANSI_BACKSLASH_SEEN; + } + } else { + ansi_parser_state &= ~ANSI_BACKSLASH_SEEN; + } + } else { + if (utf8_codepoint == '\007' || (utf8_codepoint == '\\' && + (ansi_parser_state & ANSI_ESCAPE_SEEN))) { + /* End of sequence */ + ansi_parser_state = ANSI_NORMAL; + } else if (utf8_codepoint == '\033') { + /* Escape character */ + ansi_parser_state |= ANSI_ESCAPE_SEEN; + } else if (utf8_codepoint == '"') { + /* String starting */ + ansi_parser_state |= ANSI_IN_STRING; + ansi_parser_state &= ~ANSI_ESCAPE_SEEN; + ansi_parser_state &= ~ANSI_BACKSLASH_SEEN; + } else { + ansi_parser_state &= ~ANSI_ESCAPE_SEEN; + } + } + continue; + } else { + /* Inconsistent state */ + abort(); + } + + /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the */ + /* windows console doesn't really support UTF-16, so just emit the */ + /* replacement character. */ + if (utf8_codepoint > 0xffff) { + utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; + } + + if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) { + /* EOL conversion - emit \r\n when we see \n. */ + + if (utf8_codepoint == 0x0a && previous_eol != 0x0d) { + /* \n was not preceded by \r; print \r\n. */ + ENSURE_BUFFER_SPACE(2); + utf16_buf[utf16_buf_used++] = L'\r'; + utf16_buf[utf16_buf_used++] = L'\n'; + } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) { + /* \n was followed by \r; do not print the \r, since */ + /* the source was either \r\n\r (so the second \r is */ + /* redundant) or was \n\r (so the \n was processed */ + /* by the last case and an \r automatically inserted). */ + } else { + /* \r without \n; print \r as-is. */ + ENSURE_BUFFER_SPACE(1); + utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint; + } + + previous_eol = (char) utf8_codepoint; + + } else if (utf8_codepoint <= 0xffff) { + /* Encode character into utf-16 buffer. */ + ENSURE_BUFFER_SPACE(1); + utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint; + previous_eol = 0; + } + } + } + + /* Flush remaining characters */ + FLUSH_TEXT(); + + /* Copy cached values back to struct. */ + handle->tty.wr.utf8_bytes_left = utf8_bytes_left; + handle->tty.wr.utf8_codepoint = utf8_codepoint; + handle->tty.wr.previous_eol = previous_eol; + handle->tty.wr.ansi_parser_state = ansi_parser_state; + + LeaveCriticalSection(&uv_tty_output_lock); + + if (*error == STATUS_SUCCESS) { + return 0; + } else { + return -1; + } + +#undef FLUSH_TEXT +} + + +int uv_tty_write(uv_loop_t* loop, + uv_write_t* req, + uv_tty_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb) { + DWORD error; + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_WRITE; + req->handle = (uv_stream_t*) handle; + req->cb = cb; + + handle->reqs_pending++; + handle->stream.conn.write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + + req->u.io.queued_bytes = 0; + + if (!uv_tty_write_bufs(handle, bufs, nbufs, &error)) { + SET_REQ_SUCCESS(req); + } else { + SET_REQ_ERROR(req, error); + } + + uv_insert_pending_req(loop, (uv_req_t*) req); + + return 0; +} + + +int uv__tty_try_write(uv_tty_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs) { + DWORD error; + + if (handle->stream.conn.write_reqs_pending > 0) + return UV_EAGAIN; + + if (uv_tty_write_bufs(handle, bufs, nbufs, &error)) + return uv_translate_sys_error(error); + + return uv__count_bufs(bufs, nbufs); +} + + +void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, + uv_write_t* req) { + int err; + + handle->write_queue_size -= req->u.io.queued_bytes; + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (req->cb) { + err = GET_REQ_ERROR(req); + req->cb(req, uv_translate_sys_error(err)); + } + + handle->stream.conn.write_reqs_pending--; + if (handle->stream.conn.shutdown_req != NULL && + handle->stream.conn.write_reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_tty_close(uv_tty_t* handle) { + assert(handle->u.fd == -1 || handle->u.fd > 2); + if (handle->u.fd == -1) + CloseHandle(handle->handle); + else + close(handle->u.fd); + + if (handle->flags & UV_HANDLE_READING) + uv_tty_read_stop(handle); + + handle->u.fd = -1; + handle->handle = INVALID_HANDLE_VALUE; + handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); + uv__handle_closing(handle); + + if (handle->reqs_pending == 0) { + uv_want_endgame(handle->loop, (uv_handle_t*) handle); + } +} + + +void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { + if (!(handle->flags & UV_HANDLE_TTY_READABLE) && + handle->stream.conn.shutdown_req != NULL && + handle->stream.conn.write_reqs_pending == 0) { + UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req); + + /* TTY shutdown is really just a no-op */ + if (handle->stream.conn.shutdown_req->cb) { + if (handle->flags & UV__HANDLE_CLOSING) { + handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED); + } else { + handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0); + } + } + + handle->stream.conn.shutdown_req = NULL; + + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + if (handle->flags & UV__HANDLE_CLOSING && + handle->reqs_pending == 0) { + /* The wait handle used for raw reading should be unregistered when the */ + /* wait callback runs. */ + assert(!(handle->flags & UV_HANDLE_TTY_READABLE) || + handle->tty.rd.read_raw_wait == NULL); + + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); + } +} + + +/* TODO: remove me */ +void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* raw_req) { + abort(); +} + + +/* TODO: remove me */ +void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, + uv_connect_t* req) { + abort(); +} + + +int uv_tty_reset_mode(void) { + /* Not necessary to do anything. */ + return 0; +} + +/* Determine whether or not this version of windows supports + * proper ANSI color codes. Should be supported as of windows + * 10 version 1511, build number 10.0.10586. + */ +static void uv__determine_vterm_state(HANDLE handle) { + DWORD dwMode = 0; + + if (!GetConsoleMode(handle, &dwMode)) { + uv__vterm_state = UV_UNSUPPORTED; + return; + } + + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if (!SetConsoleMode(handle, dwMode)) { + uv__vterm_state = UV_UNSUPPORTED; + return; + } + + uv__vterm_state = UV_SUPPORTED; +} diff --git a/src/win/udp.c b/src/win/udp.c new file mode 100644 index 0000000..9bf1453 --- /dev/null +++ b/src/win/udp.c @@ -0,0 +1,928 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" + + +/* + * Threshold of active udp streams for which to preallocate udp read buffers. + */ +const unsigned int uv_active_udp_streams_threshold = 0; + +/* A zero-size buffer for use by uv_udp_read */ +static char uv_zero_[] = ""; + +int uv_udp_getsockname(const uv_udp_t* handle, + struct sockaddr* name, + int* namelen) { + int result; + + if (handle->socket == INVALID_SOCKET) { + return UV_EINVAL; + } + + result = getsockname(handle->socket, name, namelen); + if (result != 0) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket, + int family) { + DWORD yes = 1; + WSAPROTOCOL_INFOW info; + int opt_len; + + if (handle->socket != INVALID_SOCKET) + return UV_EBUSY; + + /* Set the socket to nonblocking mode */ + if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) { + return WSAGetLastError(); + } + + /* Make the socket non-inheritable */ + if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) { + return GetLastError(); + } + + /* Associate it with the I/O completion port. */ + /* Use uv_handle_t pointer as completion key. */ + if (CreateIoCompletionPort((HANDLE)socket, + loop->iocp, + (ULONG_PTR)socket, + 0) == NULL) { + return GetLastError(); + } + + if (pSetFileCompletionNotificationModes) { + /* All known Windows that support SetFileCompletionNotificationModes */ + /* have a bug that makes it impossible to use this function in */ + /* conjunction with datagram sockets. We can work around that but only */ + /* if the user is using the default UDP driver (AFD) and has no other */ + /* LSPs stacked on top. Here we check whether that is the case. */ + opt_len = (int) sizeof info; + if (getsockopt(socket, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &info, + &opt_len) == SOCKET_ERROR) { + return GetLastError(); + } + + if (info.ProtocolChain.ChainLen == 1) { + if (pSetFileCompletionNotificationModes((HANDLE)socket, + FILE_SKIP_SET_EVENT_ON_HANDLE | + FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { + handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; + handle->func_wsarecv = uv_wsarecv_workaround; + handle->func_wsarecvfrom = uv_wsarecvfrom_workaround; + } else if (GetLastError() != ERROR_INVALID_FUNCTION) { + return GetLastError(); + } + } + } + + handle->socket = socket; + + if (family == AF_INET6) { + handle->flags |= UV_HANDLE_IPV6; + } else { + assert(!(handle->flags & UV_HANDLE_IPV6)); + } + + return 0; +} + + +int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) { + int domain; + + /* Use the lower 8 bits for the domain */ + domain = flags & 0xFF; + if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) + return UV_EINVAL; + + if (flags & ~0xFF) + return UV_EINVAL; + + uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP); + handle->socket = INVALID_SOCKET; + handle->reqs_pending = 0; + handle->activecnt = 0; + handle->func_wsarecv = WSARecv; + handle->func_wsarecvfrom = WSARecvFrom; + handle->send_queue_size = 0; + handle->send_queue_count = 0; + uv_req_init(loop, (uv_req_t*) &(handle->recv_req)); + handle->recv_req.type = UV_UDP_RECV; + handle->recv_req.data = handle; + + /* If anything fails beyond this point we need to remove the handle from + * the handle queue, since it was added by uv__handle_init. + */ + + if (domain != AF_UNSPEC) { + SOCKET sock; + DWORD err; + + sock = socket(domain, SOCK_DGRAM, 0); + if (sock == INVALID_SOCKET) { + err = WSAGetLastError(); + QUEUE_REMOVE(&handle->handle_queue); + return uv_translate_sys_error(err); + } + + err = uv_udp_set_socket(handle->loop, handle, sock, domain); + if (err) { + closesocket(sock); + QUEUE_REMOVE(&handle->handle_queue); + return uv_translate_sys_error(err); + } + } + + return 0; +} + + +int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { + return uv_udp_init_ex(loop, handle, AF_UNSPEC); +} + + +void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) { + uv_udp_recv_stop(handle); + closesocket(handle->socket); + handle->socket = INVALID_SOCKET; + + uv__handle_closing(handle); + + if (handle->reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) { + if (handle->flags & UV__HANDLE_CLOSING && + handle->reqs_pending == 0) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); + } +} + + +static int uv_udp_maybe_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + int r; + int err; + DWORD no = 0; + + if (handle->flags & UV_HANDLE_BOUND) + return 0; + + if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) { + /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */ + return ERROR_INVALID_PARAMETER; + } + + if (handle->socket == INVALID_SOCKET) { + SOCKET sock = socket(addr->sa_family, SOCK_DGRAM, 0); + if (sock == INVALID_SOCKET) { + return WSAGetLastError(); + } + + err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family); + if (err) { + closesocket(sock); + return err; + } + } + + if (flags & UV_UDP_REUSEADDR) { + DWORD yes = 1; + /* Set SO_REUSEADDR on the socket. */ + if (setsockopt(handle->socket, + SOL_SOCKET, + SO_REUSEADDR, + (char*) &yes, + sizeof yes) == SOCKET_ERROR) { + err = WSAGetLastError(); + return err; + } + } + + if (addr->sa_family == AF_INET6) + handle->flags |= UV_HANDLE_IPV6; + + if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) { + /* On windows IPV6ONLY is on by default. */ + /* If the user doesn't specify it libuv turns it off. */ + + /* TODO: how to handle errors? This may fail if there is no ipv4 stack */ + /* available, or when run on XP/2003 which have no support for dualstack */ + /* sockets. For now we're silently ignoring the error. */ + setsockopt(handle->socket, + IPPROTO_IPV6, + IPV6_V6ONLY, + (char*) &no, + sizeof no); + } + + r = bind(handle->socket, addr, addrlen); + if (r == SOCKET_ERROR) { + return WSAGetLastError(); + } + + handle->flags |= UV_HANDLE_BOUND; + + return 0; +} + + +static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { + uv_req_t* req; + uv_buf_t buf; + DWORD bytes, flags; + int result; + + assert(handle->flags & UV_HANDLE_READING); + assert(!(handle->flags & UV_HANDLE_READ_PENDING)); + + req = &handle->recv_req; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + + /* + * Preallocate a read buffer if the number of active streams is below + * the threshold. + */ + if (loop->active_udp_streams < uv_active_udp_streams_threshold) { + handle->flags &= ~UV_HANDLE_ZERO_READ; + + handle->recv_buffer = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer); + if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) { + handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0); + return; + } + assert(handle->recv_buffer.base != NULL); + + buf = handle->recv_buffer; + memset(&handle->recv_from, 0, sizeof handle->recv_from); + handle->recv_from_len = sizeof handle->recv_from; + flags = 0; + + result = handle->func_wsarecvfrom(handle->socket, + (WSABUF*) &buf, + 1, + &bytes, + &flags, + (struct sockaddr*) &handle->recv_from, + &handle->recv_from_len, + &req->u.io.overlapped, + NULL); + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Process the req without IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + req->u.io.overlapped.InternalHigh = bytes; + handle->reqs_pending++; + uv_insert_pending_req(loop, req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* The req will be processed with IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + } else { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, req); + handle->reqs_pending++; + } + + } else { + handle->flags |= UV_HANDLE_ZERO_READ; + + buf.base = (char*) uv_zero_; + buf.len = 0; + flags = MSG_PEEK; + + result = handle->func_wsarecv(handle->socket, + (WSABUF*) &buf, + 1, + &bytes, + &flags, + &req->u.io.overlapped, + NULL); + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Process the req without IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + req->u.io.overlapped.InternalHigh = bytes; + handle->reqs_pending++; + uv_insert_pending_req(loop, req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* The req will be processed with IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + } else { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, req); + handle->reqs_pending++; + } + } +} + + +int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, + uv_udp_recv_cb recv_cb) { + uv_loop_t* loop = handle->loop; + int err; + + if (handle->flags & UV_HANDLE_READING) { + return WSAEALREADY; + } + + err = uv_udp_maybe_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + 0); + if (err) + return err; + + handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); + loop->active_udp_streams++; + + handle->recv_cb = recv_cb; + handle->alloc_cb = alloc_cb; + + /* If reading was stopped and then started again, there could still be a */ + /* recv request pending. */ + if (!(handle->flags & UV_HANDLE_READ_PENDING)) + uv_udp_queue_recv(loop, handle); + + return 0; +} + + +int uv__udp_recv_stop(uv_udp_t* handle) { + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + handle->loop->active_udp_streams--; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + return 0; +} + + +static int uv__send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen, + uv_udp_send_cb cb) { + uv_loop_t* loop = handle->loop; + DWORD result, bytes; + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_UDP_SEND; + req->handle = handle; + req->cb = cb; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + + result = WSASendTo(handle->socket, + (WSABUF*)bufs, + nbufs, + &bytes, + 0, + addr, + addrlen, + &req->u.io.overlapped, + NULL); + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Request completed immediately. */ + req->u.io.queued_bytes = 0; + handle->reqs_pending++; + handle->send_queue_size += req->u.io.queued_bytes; + handle->send_queue_count++; + REGISTER_HANDLE_REQ(loop, handle, req); + uv_insert_pending_req(loop, (uv_req_t*)req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* Request queued by the kernel. */ + req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs); + handle->reqs_pending++; + handle->send_queue_size += req->u.io.queued_bytes; + handle->send_queue_count++; + REGISTER_HANDLE_REQ(loop, handle, req); + } else { + /* Send failed due to an error. */ + return WSAGetLastError(); + } + + return 0; +} + + +void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, + uv_req_t* req) { + uv_buf_t buf; + int partial; + + assert(handle->type == UV_UDP); + + handle->flags &= ~UV_HANDLE_READ_PENDING; + + if (!REQ_SUCCESS(req)) { + DWORD err = GET_REQ_SOCK_ERROR(req); + if (err == WSAEMSGSIZE) { + /* Not a real error, it just indicates that the received packet */ + /* was bigger than the receive buffer. */ + } else if (err == WSAECONNRESET || err == WSAENETRESET) { + /* A previous sendto operation failed; ignore this error. If */ + /* zero-reading we need to call WSARecv/WSARecvFrom _without_ the */ + /* MSG_PEEK flag to clear out the error queue. For nonzero reads, */ + /* immediately queue a new receive. */ + if (!(handle->flags & UV_HANDLE_ZERO_READ)) { + goto done; + } + } else { + /* A real error occurred. Report the error to the user only if we're */ + /* currently reading. */ + if (handle->flags & UV_HANDLE_READING) { + uv_udp_recv_stop(handle); + buf = (handle->flags & UV_HANDLE_ZERO_READ) ? + uv_buf_init(NULL, 0) : handle->recv_buffer; + handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0); + } + goto done; + } + } + + if (!(handle->flags & UV_HANDLE_ZERO_READ)) { + /* Successful read */ + partial = !REQ_SUCCESS(req); + handle->recv_cb(handle, + req->u.io.overlapped.InternalHigh, + &handle->recv_buffer, + (const struct sockaddr*) &handle->recv_from, + partial ? UV_UDP_PARTIAL : 0); + } else if (handle->flags & UV_HANDLE_READING) { + DWORD bytes, err, flags; + struct sockaddr_storage from; + int from_len; + + /* Do a nonblocking receive */ + /* TODO: try to read multiple datagrams at once. FIONREAD maybe? */ + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); + if (buf.base == NULL || buf.len == 0) { + handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); + goto done; + } + assert(buf.base != NULL); + + memset(&from, 0, sizeof from); + from_len = sizeof from; + + flags = 0; + + if (WSARecvFrom(handle->socket, + (WSABUF*)&buf, + 1, + &bytes, + &flags, + (struct sockaddr*) &from, + &from_len, + NULL, + NULL) != SOCKET_ERROR) { + + /* Message received */ + handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0); + } else { + err = WSAGetLastError(); + if (err == WSAEMSGSIZE) { + /* Message truncated */ + handle->recv_cb(handle, + bytes, + &buf, + (const struct sockaddr*) &from, + UV_UDP_PARTIAL); + } else if (err == WSAEWOULDBLOCK) { + /* Kernel buffer empty */ + handle->recv_cb(handle, 0, &buf, NULL, 0); + } else if (err == WSAECONNRESET || err == WSAENETRESET) { + /* WSAECONNRESET/WSANETRESET is ignored because this just indicates + * that a previous sendto operation failed. + */ + handle->recv_cb(handle, 0, &buf, NULL, 0); + } else { + /* Any other error that we want to report back to the user. */ + uv_udp_recv_stop(handle); + handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0); + } + } + } + +done: + /* Post another read if still reading and not closing. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_udp_queue_recv(loop, handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, + uv_udp_send_t* req) { + int err; + + assert(handle->type == UV_UDP); + + assert(handle->send_queue_size >= req->u.io.queued_bytes); + assert(handle->send_queue_count >= 1); + handle->send_queue_size -= req->u.io.queued_bytes; + handle->send_queue_count--; + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (req->cb) { + err = 0; + if (!REQ_SUCCESS(req)) { + err = GET_REQ_SOCK_ERROR(req); + } + req->cb(req, uv_translate_sys_error(err)); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +static int uv__udp_set_membership4(uv_udp_t* handle, + const struct sockaddr_in* multicast_addr, + const char* interface_addr, + uv_membership membership) { + int err; + int optname; + struct ip_mreq mreq; + + if (handle->flags & UV_HANDLE_IPV6) + return UV_EINVAL; + + /* If the socket is unbound, bind to inaddr_any. */ + err = uv_udp_maybe_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + UV_UDP_REUSEADDR); + if (err) + return uv_translate_sys_error(err); + + memset(&mreq, 0, sizeof mreq); + + if (interface_addr) { + err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr); + if (err) + return err; + } else { + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + } + + mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr; + + switch (membership) { + case UV_JOIN_GROUP: + optname = IP_ADD_MEMBERSHIP; + break; + case UV_LEAVE_GROUP: + optname = IP_DROP_MEMBERSHIP; + break; + default: + return UV_EINVAL; + } + + if (setsockopt(handle->socket, + IPPROTO_IP, + optname, + (char*) &mreq, + sizeof mreq) == SOCKET_ERROR) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +int uv__udp_set_membership6(uv_udp_t* handle, + const struct sockaddr_in6* multicast_addr, + const char* interface_addr, + uv_membership membership) { + int optname; + int err; + struct ipv6_mreq mreq; + struct sockaddr_in6 addr6; + + if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6)) + return UV_EINVAL; + + err = uv_udp_maybe_bind(handle, + (const struct sockaddr*) &uv_addr_ip6_any_, + sizeof(uv_addr_ip6_any_), + UV_UDP_REUSEADDR); + + if (err) + return uv_translate_sys_error(err); + + memset(&mreq, 0, sizeof(mreq)); + + if (interface_addr) { + if (uv_ip6_addr(interface_addr, 0, &addr6)) + return UV_EINVAL; + mreq.ipv6mr_interface = addr6.sin6_scope_id; + } else { + mreq.ipv6mr_interface = 0; + } + + mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr; + + switch (membership) { + case UV_JOIN_GROUP: + optname = IPV6_ADD_MEMBERSHIP; + break; + case UV_LEAVE_GROUP: + optname = IPV6_DROP_MEMBERSHIP; + break; + default: + return UV_EINVAL; + } + + if (setsockopt(handle->socket, + IPPROTO_IPV6, + optname, + (char*) &mreq, + sizeof mreq) == SOCKET_ERROR) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +int uv_udp_set_membership(uv_udp_t* handle, + const char* multicast_addr, + const char* interface_addr, + uv_membership membership) { + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; + + if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0) + return uv__udp_set_membership4(handle, &addr4, interface_addr, membership); + else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0) + return uv__udp_set_membership6(handle, &addr6, interface_addr, membership); + else + return UV_EINVAL; +} + + +int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) { + struct sockaddr_storage addr_st; + struct sockaddr_in* addr4; + struct sockaddr_in6* addr6; + + addr4 = (struct sockaddr_in*) &addr_st; + addr6 = (struct sockaddr_in6*) &addr_st; + + if (!interface_addr) { + memset(&addr_st, 0, sizeof addr_st); + if (handle->flags & UV_HANDLE_IPV6) { + addr_st.ss_family = AF_INET6; + addr6->sin6_scope_id = 0; + } else { + addr_st.ss_family = AF_INET; + addr4->sin_addr.s_addr = htonl(INADDR_ANY); + } + } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) { + /* nothing, address was parsed */ + } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) { + /* nothing, address was parsed */ + } else { + return UV_EINVAL; + } + + if (!(handle->flags & UV_HANDLE_BOUND)) + return UV_EBADF; + + if (addr_st.ss_family == AF_INET) { + if (setsockopt(handle->socket, + IPPROTO_IP, + IP_MULTICAST_IF, + (char*) &addr4->sin_addr, + sizeof(addr4->sin_addr)) == SOCKET_ERROR) { + return uv_translate_sys_error(WSAGetLastError()); + } + } else if (addr_st.ss_family == AF_INET6) { + if (setsockopt(handle->socket, + IPPROTO_IPV6, + IPV6_MULTICAST_IF, + (char*) &addr6->sin6_scope_id, + sizeof(addr6->sin6_scope_id)) == SOCKET_ERROR) { + return uv_translate_sys_error(WSAGetLastError()); + } + } else { + assert(0 && "unexpected address family"); + abort(); + } + + return 0; +} + + +int uv_udp_set_broadcast(uv_udp_t* handle, int value) { + BOOL optval = (BOOL) value; + + if (!(handle->flags & UV_HANDLE_BOUND)) + return UV_EBADF; + + if (setsockopt(handle->socket, + SOL_SOCKET, + SO_BROADCAST, + (char*) &optval, + sizeof optval)) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { + WSAPROTOCOL_INFOW protocol_info; + int opt_len; + int err; + + /* Detect the address family of the socket. */ + opt_len = (int) sizeof protocol_info; + if (getsockopt(sock, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &opt_len) == SOCKET_ERROR) { + return uv_translate_sys_error(GetLastError()); + } + + err = uv_udp_set_socket(handle->loop, + handle, + sock, + protocol_info.iAddressFamily); + return uv_translate_sys_error(err); +} + + +#define SOCKOPT_SETTER(name, option4, option6, validate) \ + int uv_udp_set_##name(uv_udp_t* handle, int value) { \ + DWORD optval = (DWORD) value; \ + \ + if (!(validate(value))) { \ + return UV_EINVAL; \ + } \ + \ + if (!(handle->flags & UV_HANDLE_BOUND)) \ + return UV_EBADF; \ + \ + if (!(handle->flags & UV_HANDLE_IPV6)) { \ + /* Set IPv4 socket option */ \ + if (setsockopt(handle->socket, \ + IPPROTO_IP, \ + option4, \ + (char*) &optval, \ + sizeof optval)) { \ + return uv_translate_sys_error(WSAGetLastError()); \ + } \ + } else { \ + /* Set IPv6 socket option */ \ + if (setsockopt(handle->socket, \ + IPPROTO_IPV6, \ + option6, \ + (char*) &optval, \ + sizeof optval)) { \ + return uv_translate_sys_error(WSAGetLastError()); \ + } \ + } \ + return 0; \ + } + +#define VALIDATE_TTL(value) ((value) >= 1 && (value) <= 255) +#define VALIDATE_MULTICAST_TTL(value) ((value) >= -1 && (value) <= 255) +#define VALIDATE_MULTICAST_LOOP(value) (1) + +SOCKOPT_SETTER(ttl, + IP_TTL, + IPV6_HOPLIMIT, + VALIDATE_TTL) +SOCKOPT_SETTER(multicast_ttl, + IP_MULTICAST_TTL, + IPV6_MULTICAST_HOPS, + VALIDATE_MULTICAST_TTL) +SOCKOPT_SETTER(multicast_loop, + IP_MULTICAST_LOOP, + IPV6_MULTICAST_LOOP, + VALIDATE_MULTICAST_LOOP) + +#undef SOCKOPT_SETTER +#undef VALIDATE_TTL +#undef VALIDATE_MULTICAST_TTL +#undef VALIDATE_MULTICAST_LOOP + + +/* This function is an egress point, i.e. it returns libuv errors rather than + * system errors. + */ +int uv__udp_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + int err; + + err = uv_udp_maybe_bind(handle, addr, addrlen, flags); + if (err) + return uv_translate_sys_error(err); + + return 0; +} + + +/* This function is an egress point, i.e. it returns libuv errors rather than + * system errors. + */ +int uv__udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen, + uv_udp_send_cb send_cb) { + const struct sockaddr* bind_addr; + int err; + + if (!(handle->flags & UV_HANDLE_BOUND)) { + if (addrlen == sizeof(uv_addr_ip4_any_)) { + bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_; + } else if (addrlen == sizeof(uv_addr_ip6_any_)) { + bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_; + } else { + abort(); + } + err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); + if (err) + return uv_translate_sys_error(err); + } + + err = uv__send(req, handle, bufs, nbufs, addr, addrlen, send_cb); + if (err) + return uv_translate_sys_error(err); + + return 0; +} + + +int uv__udp_try_send(uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen) { + return UV_ENOSYS; +} diff --git a/src/win/util.c b/src/win/util.c new file mode 100644 index 0000000..4a2e501 --- /dev/null +++ b/src/win/util.c @@ -0,0 +1,1380 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include +#include + + +/* + * Max title length; the only thing MSDN tells us about the maximum length + * of the console title is that it is smaller than 64K. However in practice + * it is much smaller, and there is no way to figure out what the exact length + * of the title is or can be, at least not on XP. To make it even more + * annoying, GetConsoleTitle fails when the buffer to be read into is bigger + * than the actual maximum length. So we make a conservative guess here; + * just don't put the novel you're writing in the title, unless the plot + * survives truncation. + */ +#define MAX_TITLE_LENGTH 8192 + +/* The number of nanoseconds in one second. */ +#define UV__NANOSEC 1000000000 + +/* Max user name length, from iphlpapi.h */ +#ifndef UNLEN +# define UNLEN 256 +#endif + +/* Cached copy of the process title, plus a mutex guarding it. */ +static char *process_title; +static CRITICAL_SECTION process_title_lock; + +/* Cached copy of the process id, written once. */ +static DWORD current_pid = 0; + + +/* Interval (in seconds) of the high-resolution clock. */ +static double hrtime_interval_ = 0; + + +/* + * One-time initialization code for functionality defined in util.c. + */ +void uv__util_init() { + LARGE_INTEGER perf_frequency; + + /* Initialize process title access mutex. */ + InitializeCriticalSection(&process_title_lock); + + /* Retrieve high-resolution timer frequency + * and precompute its reciprocal. + */ + if (QueryPerformanceFrequency(&perf_frequency)) { + hrtime_interval_ = 1.0 / perf_frequency.QuadPart; + } else { + hrtime_interval_= 0; + } +} + + +int uv_exepath(char* buffer, size_t* size_ptr) { + int utf8_len, utf16_buffer_len, utf16_len; + WCHAR* utf16_buffer; + int err; + + if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) { + return UV_EINVAL; + } + + if (*size_ptr > 32768) { + /* Windows paths can never be longer than this. */ + utf16_buffer_len = 32768; + } else { + utf16_buffer_len = (int) *size_ptr; + } + + utf16_buffer = (WCHAR*) uv__malloc(sizeof(WCHAR) * utf16_buffer_len); + if (!utf16_buffer) { + return UV_ENOMEM; + } + + /* Get the path as UTF-16. */ + utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len); + if (utf16_len <= 0) { + err = GetLastError(); + goto error; + } + + /* utf16_len contains the length, *not* including the terminating null. */ + utf16_buffer[utf16_len] = L'\0'; + + /* Convert to UTF-8 */ + utf8_len = WideCharToMultiByte(CP_UTF8, + 0, + utf16_buffer, + -1, + buffer, + (int) *size_ptr, + NULL, + NULL); + if (utf8_len == 0) { + err = GetLastError(); + goto error; + } + + uv__free(utf16_buffer); + + /* utf8_len *does* include the terminating null at this point, but the */ + /* returned size shouldn't. */ + *size_ptr = utf8_len - 1; + return 0; + + error: + uv__free(utf16_buffer); + return uv_translate_sys_error(err); +} + + +int uv_cwd(char* buffer, size_t* size) { + DWORD utf16_len; + WCHAR utf16_buffer[MAX_PATH]; + int r; + + if (buffer == NULL || size == NULL) { + return UV_EINVAL; + } + + utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer); + if (utf16_len == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (utf16_len > MAX_PATH) { + /* This should be impossible; however the CRT has a code path to deal */ + /* with this scenario, so I added a check anyway. */ + return UV_EIO; + } + + /* utf16_len contains the length, *not* including the terminating null. */ + utf16_buffer[utf16_len] = L'\0'; + + /* The returned directory should not have a trailing slash, unless it */ + /* points at a drive root, like c:\. Remove it if needed.*/ + if (utf16_buffer[utf16_len - 1] == L'\\' && + !(utf16_len == 3 && utf16_buffer[1] == L':')) { + utf16_len--; + utf16_buffer[utf16_len] = L'\0'; + } + + /* Check how much space we need */ + r = WideCharToMultiByte(CP_UTF8, + 0, + utf16_buffer, + -1, + NULL, + 0, + NULL, + NULL); + if (r == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (r > (int) *size) { + *size = r; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + r = WideCharToMultiByte(CP_UTF8, + 0, + utf16_buffer, + -1, + buffer, + *size > INT_MAX ? INT_MAX : (int) *size, + NULL, + NULL); + if (r == 0) { + return uv_translate_sys_error(GetLastError()); + } + + *size = r - 1; + return 0; +} + + +int uv_chdir(const char* dir) { + WCHAR utf16_buffer[MAX_PATH]; + size_t utf16_len; + WCHAR drive_letter, env_var[4]; + + if (dir == NULL) { + return UV_EINVAL; + } + + if (MultiByteToWideChar(CP_UTF8, + 0, + dir, + -1, + utf16_buffer, + MAX_PATH) == 0) { + DWORD error = GetLastError(); + /* The maximum length of the current working directory is 260 chars, */ + /* including terminating null. If it doesn't fit, the path name must be */ + /* too long. */ + if (error == ERROR_INSUFFICIENT_BUFFER) { + return UV_ENAMETOOLONG; + } else { + return uv_translate_sys_error(error); + } + } + + if (!SetCurrentDirectoryW(utf16_buffer)) { + return uv_translate_sys_error(GetLastError()); + } + + /* Windows stores the drive-local path in an "hidden" environment variable, */ + /* which has the form "=C:=C:\Windows". SetCurrentDirectory does not */ + /* update this, so we'll have to do it. */ + utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer); + if (utf16_len == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (utf16_len > MAX_PATH) { + return UV_EIO; + } + + /* The returned directory should not have a trailing slash, unless it */ + /* points at a drive root, like c:\. Remove it if needed. */ + if (utf16_buffer[utf16_len - 1] == L'\\' && + !(utf16_len == 3 && utf16_buffer[1] == L':')) { + utf16_len--; + utf16_buffer[utf16_len] = L'\0'; + } + + if (utf16_len < 2 || utf16_buffer[1] != L':') { + /* Doesn't look like a drive letter could be there - probably an UNC */ + /* path. TODO: Need to handle win32 namespaces like \\?\C:\ ? */ + drive_letter = 0; + } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') { + drive_letter = utf16_buffer[0]; + } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') { + /* Convert to uppercase. */ + drive_letter = utf16_buffer[0] - L'a' + L'A'; + } else { + /* Not valid. */ + drive_letter = 0; + } + + if (drive_letter != 0) { + /* Construct the environment variable name and set it. */ + env_var[0] = L'='; + env_var[1] = drive_letter; + env_var[2] = L':'; + env_var[3] = L'\0'; + + if (!SetEnvironmentVariableW(env_var, utf16_buffer)) { + return uv_translate_sys_error(GetLastError()); + } + } + + return 0; +} + + +void uv_loadavg(double avg[3]) { + /* Can't be implemented */ + avg[0] = avg[1] = avg[2] = 0; +} + + +uint64_t uv_get_free_memory(void) { + MEMORYSTATUSEX memory_status; + memory_status.dwLength = sizeof(memory_status); + + if (!GlobalMemoryStatusEx(&memory_status)) { + return -1; + } + + return (uint64_t)memory_status.ullAvailPhys; +} + + +uint64_t uv_get_total_memory(void) { + MEMORYSTATUSEX memory_status; + memory_status.dwLength = sizeof(memory_status); + + if (!GlobalMemoryStatusEx(&memory_status)) { + return -1; + } + + return (uint64_t)memory_status.ullTotalPhys; +} + + +int uv_parent_pid() { + int parent_pid = -1; + HANDLE handle; + PROCESSENTRY32 pe; + DWORD current_pid = GetCurrentProcessId(); + + pe.dwSize = sizeof(PROCESSENTRY32); + handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + + if (Process32First(handle, &pe)) { + do { + if (pe.th32ProcessID == current_pid) { + parent_pid = pe.th32ParentProcessID; + break; + } + } while( Process32Next(handle, &pe)); + } + + CloseHandle(handle); + return parent_pid; +} + + +int uv_current_pid() { + if (current_pid == 0) { + current_pid = GetCurrentProcessId(); + } + return current_pid; +} + + +char** uv_setup_args(int argc, char** argv) { + return argv; +} + + +int uv_set_process_title(const char* title) { + int err; + int length; + WCHAR* title_w = NULL; + + uv__once_init(); + + /* Find out how big the buffer for the wide-char title must be */ + length = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0); + if (!length) { + err = GetLastError(); + goto done; + } + + /* Convert to wide-char string */ + title_w = (WCHAR*)uv__malloc(sizeof(WCHAR) * length); + if (!title_w) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + length = MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, length); + if (!length) { + err = GetLastError(); + goto done; + } + + /* If the title must be truncated insert a \0 terminator there */ + if (length > MAX_TITLE_LENGTH) { + title_w[MAX_TITLE_LENGTH - 1] = L'\0'; + } + + if (!SetConsoleTitleW(title_w)) { + err = GetLastError(); + goto done; + } + + EnterCriticalSection(&process_title_lock); + uv__free(process_title); + process_title = uv__strdup(title); + LeaveCriticalSection(&process_title_lock); + + err = 0; + +done: + uv__free(title_w); + return uv_translate_sys_error(err); +} + + +static int uv__get_process_title() { + WCHAR title_w[MAX_TITLE_LENGTH]; + + if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) { + return -1; + } + + if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0) + return -1; + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return UV_EINVAL; + + uv__once_init(); + + EnterCriticalSection(&process_title_lock); + /* + * If the process_title was never read before nor explicitly set, + * we must query it with getConsoleTitleW + */ + if (!process_title && uv__get_process_title() == -1) { + LeaveCriticalSection(&process_title_lock); + return uv_translate_sys_error(GetLastError()); + } + + assert(process_title); + len = strlen(process_title) + 1; + + if (size < len) { + LeaveCriticalSection(&process_title_lock); + return UV_ENOBUFS; + } + + memcpy(buffer, process_title, len); + LeaveCriticalSection(&process_title_lock); + + return 0; +} + + +uint64_t uv_hrtime(void) { + uv__once_init(); + return uv__hrtime(UV__NANOSEC); +} + +uint64_t uv__hrtime(double scale) { + LARGE_INTEGER counter; + + /* If the performance interval is zero, there's no support. */ + if (hrtime_interval_ == 0) { + return 0; + } + + if (!QueryPerformanceCounter(&counter)) { + return 0; + } + + /* Because we have no guarantee about the order of magnitude of the + * performance counter interval, integer math could cause this computation + * to overflow. Therefore we resort to floating point math. + */ + return (uint64_t) ((double) counter.QuadPart * hrtime_interval_ * scale); +} + + +int uv_resident_set_memory(size_t* rss) { + HANDLE current_process; + PROCESS_MEMORY_COUNTERS pmc; + + current_process = GetCurrentProcess(); + + if (!GetProcessMemoryInfo(current_process, &pmc, sizeof(pmc))) { + return uv_translate_sys_error(GetLastError()); + } + + *rss = pmc.WorkingSetSize; + + return 0; +} + + +int uv_uptime(double* uptime) { + BYTE stack_buffer[4096]; + BYTE* malloced_buffer = NULL; + BYTE* buffer = (BYTE*) stack_buffer; + size_t buffer_size = sizeof(stack_buffer); + DWORD data_size; + + PERF_DATA_BLOCK* data_block; + PERF_OBJECT_TYPE* object_type; + PERF_COUNTER_DEFINITION* counter_definition; + + DWORD i; + + for (;;) { + LONG result; + + data_size = (DWORD) buffer_size; + result = RegQueryValueExW(HKEY_PERFORMANCE_DATA, + L"2", + NULL, + NULL, + buffer, + &data_size); + if (result == ERROR_SUCCESS) { + break; + } else if (result != ERROR_MORE_DATA) { + *uptime = 0; + return uv_translate_sys_error(result); + } + + buffer_size *= 2; + /* Don't let the buffer grow infinitely. */ + if (buffer_size > 1 << 20) { + goto internalError; + } + + uv__free(malloced_buffer); + + buffer = malloced_buffer = (BYTE*) uv__malloc(buffer_size); + if (malloced_buffer == NULL) { + *uptime = 0; + return UV_ENOMEM; + } + } + + if (data_size < sizeof(*data_block)) + goto internalError; + + data_block = (PERF_DATA_BLOCK*) buffer; + + if (wmemcmp(data_block->Signature, L"PERF", 4) != 0) + goto internalError; + + if (data_size < data_block->HeaderLength + sizeof(*object_type)) + goto internalError; + + object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength); + + if (object_type->NumInstances != PERF_NO_INSTANCES) + goto internalError; + + counter_definition = (PERF_COUNTER_DEFINITION*) (buffer + + data_block->HeaderLength + object_type->HeaderLength); + for (i = 0; i < object_type->NumCounters; i++) { + if ((BYTE*) counter_definition + sizeof(*counter_definition) > + buffer + data_size) { + break; + } + + if (counter_definition->CounterNameTitleIndex == 674 && + counter_definition->CounterSize == sizeof(uint64_t)) { + if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size || + !(counter_definition->CounterType & PERF_OBJECT_TIMER)) { + goto internalError; + } else { + BYTE* address = (BYTE*) object_type + object_type->DefinitionLength + + counter_definition->CounterOffset; + uint64_t value = *((uint64_t*) address); + *uptime = (double) (object_type->PerfTime.QuadPart - value) / + (double) object_type->PerfFreq.QuadPart; + uv__free(malloced_buffer); + return 0; + } + } + + counter_definition = (PERF_COUNTER_DEFINITION*) + ((BYTE*) counter_definition + counter_definition->ByteLength); + } + + /* If we get here, the uptime value was not found. */ + uv__free(malloced_buffer); + *uptime = 0; + return UV_ENOSYS; + + internalError: + uv__free(malloced_buffer); + *uptime = 0; + return UV_EIO; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { + uv_cpu_info_t* cpu_infos; + SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi; + DWORD sppi_size; + SYSTEM_INFO system_info; + DWORD cpu_count, r, i; + NTSTATUS status; + ULONG result_size; + int err; + uv_cpu_info_t* cpu_info; + + cpu_infos = NULL; + cpu_count = 0; + sppi = NULL; + + uv__once_init(); + + GetSystemInfo(&system_info); + cpu_count = system_info.dwNumberOfProcessors; + + cpu_infos = uv__calloc(cpu_count, sizeof *cpu_infos); + if (cpu_infos == NULL) { + err = ERROR_OUTOFMEMORY; + goto error; + } + + sppi_size = cpu_count * sizeof(*sppi); + sppi = uv__malloc(sppi_size); + if (sppi == NULL) { + err = ERROR_OUTOFMEMORY; + goto error; + } + + status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, + sppi, + sppi_size, + &result_size); + if (!NT_SUCCESS(status)) { + err = pRtlNtStatusToDosError(status); + goto error; + } + + assert(result_size == sppi_size); + + for (i = 0; i < cpu_count; i++) { + WCHAR key_name[128]; + HKEY processor_key; + DWORD cpu_speed; + DWORD cpu_speed_size = sizeof(cpu_speed); + WCHAR cpu_brand[256]; + DWORD cpu_brand_size = sizeof(cpu_brand); + size_t len; + + len = _snwprintf(key_name, + ARRAY_SIZE(key_name), + L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", + i); + + assert(len > 0 && len < ARRAY_SIZE(key_name)); + + r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + key_name, + 0, + KEY_QUERY_VALUE, + &processor_key); + if (r != ERROR_SUCCESS) { + err = GetLastError(); + goto error; + } + + if (RegQueryValueExW(processor_key, + L"~MHz", + NULL, + NULL, + (BYTE*) &cpu_speed, + &cpu_speed_size) != ERROR_SUCCESS) { + err = GetLastError(); + RegCloseKey(processor_key); + goto error; + } + + if (RegQueryValueExW(processor_key, + L"ProcessorNameString", + NULL, + NULL, + (BYTE*) &cpu_brand, + &cpu_brand_size) != ERROR_SUCCESS) { + err = GetLastError(); + RegCloseKey(processor_key); + goto error; + } + + RegCloseKey(processor_key); + + cpu_info = &cpu_infos[i]; + cpu_info->speed = cpu_speed; + cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000; + cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart - + sppi[i].IdleTime.QuadPart) / 10000; + cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000; + cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000; + cpu_info->cpu_times.nice = 0; + + uv__convert_utf16_to_utf8(cpu_brand, + cpu_brand_size / sizeof(WCHAR), + &(cpu_info->model)); + } + + uv__free(sppi); + + *cpu_count_ptr = cpu_count; + *cpu_infos_ptr = cpu_infos; + + return 0; + + error: + /* This is safe because the cpu_infos array is zeroed on allocation. */ + for (i = 0; i < cpu_count; i++) + uv__free(cpu_infos[i].model); + + uv__free(cpu_infos); + uv__free(sppi); + + return uv_translate_sys_error(err); +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +static int is_windows_version_or_greater(DWORD os_major, + DWORD os_minor, + WORD service_pack_major, + WORD service_pack_minor) { + OSVERSIONINFOEX osvi; + DWORDLONG condition_mask = 0; + int op = VER_GREATER_EQUAL; + + /* Initialize the OSVERSIONINFOEX structure. */ + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + osvi.dwMajorVersion = os_major; + osvi.dwMinorVersion = os_minor; + osvi.wServicePackMajor = service_pack_major; + osvi.wServicePackMinor = service_pack_minor; + + /* Initialize the condition mask. */ + VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op); + VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op); + VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op); + VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op); + + /* Perform the test. */ + return (int) VerifyVersionInfo( + &osvi, + VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, + condition_mask); +} + + +static int address_prefix_match(int family, + struct sockaddr* address, + struct sockaddr* prefix_address, + int prefix_len) { + uint8_t* address_data; + uint8_t* prefix_address_data; + int i; + + assert(address->sa_family == family); + assert(prefix_address->sa_family == family); + + if (family == AF_INET6) { + address_data = (uint8_t*) &(((struct sockaddr_in6 *) address)->sin6_addr); + prefix_address_data = + (uint8_t*) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr); + } else { + address_data = (uint8_t*) &(((struct sockaddr_in *) address)->sin_addr); + prefix_address_data = + (uint8_t*) &(((struct sockaddr_in *) prefix_address)->sin_addr); + } + + for (i = 0; i < prefix_len >> 3; i++) { + if (address_data[i] != prefix_address_data[i]) + return 0; + } + + if (prefix_len % 8) + return prefix_address_data[i] == + (address_data[i] & (0xff << (8 - prefix_len % 8))); + + return 1; +} + + +int uv_interface_addresses(uv_interface_address_t** addresses_ptr, + int* count_ptr) { + IP_ADAPTER_ADDRESSES* win_address_buf; + ULONG win_address_buf_size; + IP_ADAPTER_ADDRESSES* adapter; + + uv_interface_address_t* uv_address_buf; + char* name_buf; + size_t uv_address_buf_size; + uv_interface_address_t* uv_address; + + int count; + + int is_vista_or_greater; + ULONG flags; + + is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0); + if (is_vista_or_greater) { + flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | + GAA_FLAG_SKIP_DNS_SERVER; + } else { + /* We need at least XP SP1. */ + if (!is_windows_version_or_greater(5, 1, 1, 0)) + return UV_ENOTSUP; + + flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | + GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX; + } + + + /* Fetch the size of the adapters reported by windows, and then get the */ + /* list itself. */ + win_address_buf_size = 0; + win_address_buf = NULL; + + for (;;) { + ULONG r; + + /* If win_address_buf is 0, then GetAdaptersAddresses will fail with */ + /* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */ + /* win_address_buf_size. */ + r = GetAdaptersAddresses(AF_UNSPEC, + flags, + NULL, + win_address_buf, + &win_address_buf_size); + + if (r == ERROR_SUCCESS) + break; + + uv__free(win_address_buf); + + switch (r) { + case ERROR_BUFFER_OVERFLOW: + /* This happens when win_address_buf is NULL or too small to hold */ + /* all adapters. */ + win_address_buf = uv__malloc(win_address_buf_size); + if (win_address_buf == NULL) + return UV_ENOMEM; + + continue; + + case ERROR_NO_DATA: { + /* No adapters were found. */ + uv_address_buf = uv__malloc(1); + if (uv_address_buf == NULL) + return UV_ENOMEM; + + *count_ptr = 0; + *addresses_ptr = uv_address_buf; + + return 0; + } + + case ERROR_ADDRESS_NOT_ASSOCIATED: + return UV_EAGAIN; + + case ERROR_INVALID_PARAMETER: + /* MSDN says: + * "This error is returned for any of the following conditions: the + * SizePointer parameter is NULL, the Address parameter is not + * AF_INET, AF_INET6, or AF_UNSPEC, or the address information for + * the parameters requested is greater than ULONG_MAX." + * Since the first two conditions are not met, it must be that the + * adapter data is too big. + */ + return UV_ENOBUFS; + + default: + /* Other (unspecified) errors can happen, but we don't have any */ + /* special meaning for them. */ + assert(r != ERROR_SUCCESS); + return uv_translate_sys_error(r); + } + } + + /* Count the number of enabled interfaces and compute how much space is */ + /* needed to store their info. */ + count = 0; + uv_address_buf_size = 0; + + for (adapter = win_address_buf; + adapter != NULL; + adapter = adapter->Next) { + IP_ADAPTER_UNICAST_ADDRESS* unicast_address; + int name_size; + + /* Interfaces that are not 'up' should not be reported. Also skip */ + /* interfaces that have no associated unicast address, as to avoid */ + /* allocating space for the name for this interface. */ + if (adapter->OperStatus != IfOperStatusUp || + adapter->FirstUnicastAddress == NULL) + continue; + + /* Compute the size of the interface name. */ + name_size = WideCharToMultiByte(CP_UTF8, + 0, + adapter->FriendlyName, + -1, + NULL, + 0, + NULL, + FALSE); + if (name_size <= 0) { + uv__free(win_address_buf); + return uv_translate_sys_error(GetLastError()); + } + uv_address_buf_size += name_size; + + /* Count the number of addresses associated with this interface, and */ + /* compute the size. */ + for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*) + adapter->FirstUnicastAddress; + unicast_address != NULL; + unicast_address = unicast_address->Next) { + count++; + uv_address_buf_size += sizeof(uv_interface_address_t); + } + } + + /* Allocate space to store interface data plus adapter names. */ + uv_address_buf = uv__malloc(uv_address_buf_size); + if (uv_address_buf == NULL) { + uv__free(win_address_buf); + return UV_ENOMEM; + } + + /* Compute the start of the uv_interface_address_t array, and the place in */ + /* the buffer where the interface names will be stored. */ + uv_address = uv_address_buf; + name_buf = (char*) (uv_address_buf + count); + + /* Fill out the output buffer. */ + for (adapter = win_address_buf; + adapter != NULL; + adapter = adapter->Next) { + IP_ADAPTER_UNICAST_ADDRESS* unicast_address; + int name_size; + size_t max_name_size; + + if (adapter->OperStatus != IfOperStatusUp || + adapter->FirstUnicastAddress == NULL) + continue; + + /* Convert the interface name to UTF8. */ + max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf; + if (max_name_size > (size_t) INT_MAX) + max_name_size = INT_MAX; + name_size = WideCharToMultiByte(CP_UTF8, + 0, + adapter->FriendlyName, + -1, + name_buf, + (int) max_name_size, + NULL, + FALSE); + if (name_size <= 0) { + uv__free(win_address_buf); + uv__free(uv_address_buf); + return uv_translate_sys_error(GetLastError()); + } + + /* Add an uv_interface_address_t element for every unicast address. */ + for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*) + adapter->FirstUnicastAddress; + unicast_address != NULL; + unicast_address = unicast_address->Next) { + struct sockaddr* sa; + ULONG prefix_len; + + sa = unicast_address->Address.lpSockaddr; + + /* XP has no OnLinkPrefixLength field. */ + if (is_vista_or_greater) { + prefix_len = + ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength; + } else { + /* Prior to Windows Vista the FirstPrefix pointed to the list with + * single prefix for each IP address assigned to the adapter. + * Order of FirstPrefix does not match order of FirstUnicastAddress, + * so we need to find corresponding prefix. + */ + IP_ADAPTER_PREFIX* prefix; + prefix_len = 0; + + for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) { + /* We want the longest matching prefix. */ + if (prefix->Address.lpSockaddr->sa_family != sa->sa_family || + prefix->PrefixLength <= prefix_len) + continue; + + if (address_prefix_match(sa->sa_family, sa, + prefix->Address.lpSockaddr, prefix->PrefixLength)) { + prefix_len = prefix->PrefixLength; + } + } + + /* If there is no matching prefix information, return a single-host + * subnet mask (e.g. 255.255.255.255 for IPv4). + */ + if (!prefix_len) + prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32; + } + + memset(uv_address, 0, sizeof *uv_address); + + uv_address->name = name_buf; + + if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) { + memcpy(uv_address->phys_addr, + adapter->PhysicalAddress, + sizeof(uv_address->phys_addr)); + } + + uv_address->is_internal = + (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK); + + if (sa->sa_family == AF_INET6) { + uv_address->address.address6 = *((struct sockaddr_in6 *) sa); + + uv_address->netmask.netmask6.sin6_family = AF_INET6; + memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3); + /* This check ensures that we don't write past the size of the data. */ + if (prefix_len % 8) { + uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] = + 0xff << (8 - prefix_len % 8); + } + + } else { + uv_address->address.address4 = *((struct sockaddr_in *) sa); + + uv_address->netmask.netmask4.sin_family = AF_INET; + uv_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ? + htonl(0xffffffff << (32 - prefix_len)) : 0; + } + + uv_address++; + } + + name_buf += name_size; + } + + uv__free(win_address_buf); + + *addresses_ptr = uv_address_buf; + *count_ptr = count; + + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + uv__free(addresses); +} + + +int uv_getrusage(uv_rusage_t *uv_rusage) { + FILETIME createTime, exitTime, kernelTime, userTime; + SYSTEMTIME kernelSystemTime, userSystemTime; + PROCESS_MEMORY_COUNTERS memCounters; + int ret; + + ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + ret = FileTimeToSystemTime(&userTime, &userSystemTime); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + ret = GetProcessMemoryInfo(GetCurrentProcess(), + &memCounters, + sizeof(memCounters)); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + memset(uv_rusage, 0, sizeof(*uv_rusage)); + + uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 + + userSystemTime.wMinute * 60 + + userSystemTime.wSecond; + uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000; + + uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 + + kernelSystemTime.wMinute * 60 + + kernelSystemTime.wSecond; + uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000; + + uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount; + uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024; + + return 0; +} + + +int uv_os_homedir(char* buffer, size_t* size) { + uv_passwd_t pwd; + wchar_t path[MAX_PATH]; + DWORD bufsize; + size_t len; + int r; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + /* Check if the USERPROFILE environment variable is set first */ + len = GetEnvironmentVariableW(L"USERPROFILE", path, MAX_PATH); + + if (len == 0) { + r = GetLastError(); + + /* Don't return an error if USERPROFILE was not found */ + if (r != ERROR_ENVVAR_NOT_FOUND) + return uv_translate_sys_error(r); + } else if (len > MAX_PATH) { + /* This should not be possible */ + return UV_EIO; + } else { + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; + } + + /* USERPROFILE is not set, so call uv__getpwuid_r() */ + r = uv__getpwuid_r(&pwd); + + if (r != 0) { + return r; + } + + len = strlen(pwd.homedir); + + if (len >= *size) { + *size = len + 1; + uv_os_free_passwd(&pwd); + return UV_ENOBUFS; + } + + memcpy(buffer, pwd.homedir, len + 1); + *size = len; + uv_os_free_passwd(&pwd); + + return 0; +} + + +int uv_os_tmpdir(char* buffer, size_t* size) { + wchar_t path[MAX_PATH + 1]; + DWORD bufsize; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + len = GetTempPathW(MAX_PATH + 1, path); + + if (len == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (len > MAX_PATH + 1) { + /* This should not be possible */ + return UV_EIO; + } + + /* The returned directory should not have a trailing slash, unless it */ + /* points at a drive root, like c:\. Remove it if needed.*/ + if (path[len - 1] == L'\\' && + !(len == 3 && path[1] == L':')) { + len--; + path[len] = L'\0'; + } + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; +} + + +void uv_os_free_passwd(uv_passwd_t* pwd) { + if (pwd == NULL) + return; + + uv__free(pwd->username); + uv__free(pwd->homedir); + pwd->username = NULL; + pwd->homedir = NULL; +} + + +/* + * Converts a UTF-16 string into a UTF-8 one. The resulting string is + * null-terminated. + * + * If utf16 is null terminated, utf16len can be set to -1, otherwise it must + * be specified. + */ +int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) { + DWORD bufsize; + + if (utf16 == NULL) + return UV_EINVAL; + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + utf16len, + NULL, + 0, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + /* Allocate the destination buffer adding an extra byte for the terminating + * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so + * we do it ourselves always, just in case. */ + *utf8 = uv__malloc(bufsize + 1); + + if (*utf8 == NULL) + return UV_ENOMEM; + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + utf16len, + *utf8, + bufsize, + NULL, + NULL); + + if (bufsize == 0) { + uv__free(*utf8); + *utf8 = NULL; + return uv_translate_sys_error(GetLastError()); + } + + (*utf8)[bufsize] = '\0'; + return 0; +} + + +int uv__getpwuid_r(uv_passwd_t* pwd) { + HANDLE token; + wchar_t username[UNLEN + 1]; + wchar_t path[MAX_PATH]; + DWORD bufsize; + int r; + + if (pwd == NULL) + return UV_EINVAL; + + /* Get the home directory using GetUserProfileDirectoryW() */ + if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0) + return uv_translate_sys_error(GetLastError()); + + bufsize = sizeof(path); + if (!GetUserProfileDirectoryW(token, path, &bufsize)) { + r = GetLastError(); + CloseHandle(token); + + /* This should not be possible */ + if (r == ERROR_INSUFFICIENT_BUFFER) + return UV_ENOMEM; + + return uv_translate_sys_error(r); + } + + CloseHandle(token); + + /* Get the username using GetUserNameW() */ + bufsize = sizeof(username); + if (!GetUserNameW(username, &bufsize)) { + r = GetLastError(); + + /* This should not be possible */ + if (r == ERROR_INSUFFICIENT_BUFFER) + return UV_ENOMEM; + + return uv_translate_sys_error(r); + } + + pwd->homedir = NULL; + r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir); + + if (r != 0) + return r; + + pwd->username = NULL; + r = uv__convert_utf16_to_utf8(username, -1, &pwd->username); + + if (r != 0) { + uv__free(pwd->homedir); + return r; + } + + pwd->shell = NULL; + pwd->uid = -1; + pwd->gid = -1; + + return 0; +} + + +int uv_os_get_passwd(uv_passwd_t* pwd) { + return uv__getpwuid_r(pwd); +} diff --git a/src/win/winapi.c b/src/win/winapi.c new file mode 100644 index 0000000..1fa179b --- /dev/null +++ b/src/win/winapi.c @@ -0,0 +1,159 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include + +#include "uv.h" +#include "internal.h" + + +/* Ntdll function pointers */ +sRtlNtStatusToDosError pRtlNtStatusToDosError; +sNtDeviceIoControlFile pNtDeviceIoControlFile; +sNtQueryInformationFile pNtQueryInformationFile; +sNtSetInformationFile pNtSetInformationFile; +sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile; +sNtQueryDirectoryFile pNtQueryDirectoryFile; +sNtQuerySystemInformation pNtQuerySystemInformation; + + +/* Kernel32 function pointers */ +sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; +sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; +sCreateSymbolicLinkW pCreateSymbolicLinkW; +sCancelIoEx pCancelIoEx; +sInitializeConditionVariable pInitializeConditionVariable; +sSleepConditionVariableCS pSleepConditionVariableCS; +sSleepConditionVariableSRW pSleepConditionVariableSRW; +sWakeAllConditionVariable pWakeAllConditionVariable; +sWakeConditionVariable pWakeConditionVariable; +sCancelSynchronousIo pCancelSynchronousIo; +sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; + + +/* Powrprof.dll function pointer */ +sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; + + +void uv_winapi_init() { + HMODULE ntdll_module; + HMODULE kernel32_module; + HMODULE powrprof_module; + + ntdll_module = GetModuleHandleA("ntdll.dll"); + if (ntdll_module == NULL) { + uv_fatal_error(GetLastError(), "GetModuleHandleA"); + } + + pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress( + ntdll_module, + "RtlNtStatusToDosError"); + if (pRtlNtStatusToDosError == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtDeviceIoControlFile = (sNtDeviceIoControlFile) GetProcAddress( + ntdll_module, + "NtDeviceIoControlFile"); + if (pNtDeviceIoControlFile == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress( + ntdll_module, + "NtQueryInformationFile"); + if (pNtQueryInformationFile == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtSetInformationFile = (sNtSetInformationFile) GetProcAddress( + ntdll_module, + "NtSetInformationFile"); + if (pNtSetInformationFile == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtQueryVolumeInformationFile = (sNtQueryVolumeInformationFile) + GetProcAddress(ntdll_module, "NtQueryVolumeInformationFile"); + if (pNtQueryVolumeInformationFile == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtQueryDirectoryFile = (sNtQueryDirectoryFile) + GetProcAddress(ntdll_module, "NtQueryDirectoryFile"); + if (pNtQueryVolumeInformationFile == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress( + ntdll_module, + "NtQuerySystemInformation"); + if (pNtQuerySystemInformation == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + kernel32_module = GetModuleHandleA("kernel32.dll"); + if (kernel32_module == NULL) { + uv_fatal_error(GetLastError(), "GetModuleHandleA"); + } + + pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress( + kernel32_module, + "GetQueuedCompletionStatusEx"); + + pSetFileCompletionNotificationModes = (sSetFileCompletionNotificationModes) + GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes"); + + pCreateSymbolicLinkW = (sCreateSymbolicLinkW) + GetProcAddress(kernel32_module, "CreateSymbolicLinkW"); + + pCancelIoEx = (sCancelIoEx) + GetProcAddress(kernel32_module, "CancelIoEx"); + + pInitializeConditionVariable = (sInitializeConditionVariable) + GetProcAddress(kernel32_module, "InitializeConditionVariable"); + + pSleepConditionVariableCS = (sSleepConditionVariableCS) + GetProcAddress(kernel32_module, "SleepConditionVariableCS"); + + pSleepConditionVariableSRW = (sSleepConditionVariableSRW) + GetProcAddress(kernel32_module, "SleepConditionVariableSRW"); + + pWakeAllConditionVariable = (sWakeAllConditionVariable) + GetProcAddress(kernel32_module, "WakeAllConditionVariable"); + + pWakeConditionVariable = (sWakeConditionVariable) + GetProcAddress(kernel32_module, "WakeConditionVariable"); + + pCancelSynchronousIo = (sCancelSynchronousIo) + GetProcAddress(kernel32_module, "CancelSynchronousIo"); + + pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW) + GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW"); + + + powrprof_module = LoadLibraryA("powrprof.dll"); + if (powrprof_module != NULL) { + pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) + GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification"); + } + +} diff --git a/src/win/winapi.h b/src/win/winapi.h new file mode 100644 index 0000000..16d9365 --- /dev/null +++ b/src/win/winapi.h @@ -0,0 +1,4748 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_WIN_WINAPI_H_ +#define UV_WIN_WINAPI_H_ + +#include + + +/* + * Ntdll headers + */ +#ifndef STATUS_SEVERITY_SUCCESS +# define STATUS_SEVERITY_SUCCESS 0x0 +#endif + +#ifndef STATUS_SEVERITY_INFORMATIONAL +# define STATUS_SEVERITY_INFORMATIONAL 0x1 +#endif + +#ifndef STATUS_SEVERITY_WARNING +# define STATUS_SEVERITY_WARNING 0x2 +#endif + +#ifndef STATUS_SEVERITY_ERROR +# define STATUS_SEVERITY_ERROR 0x3 +#endif + +#ifndef FACILITY_NTWIN32 +# define FACILITY_NTWIN32 0x7 +#endif + +#ifndef NT_SUCCESS +# define NT_SUCCESS(status) (((NTSTATUS) (status)) >= 0) +#endif + +#ifndef NT_INFORMATION +# define NT_INFORMATION(status) ((((ULONG) (status)) >> 30) == 1) +#endif + +#ifndef NT_WARNING +# define NT_WARNING(status) ((((ULONG) (status)) >> 30) == 2) +#endif + +#ifndef NT_ERROR +# define NT_ERROR(status) ((((ULONG) (status)) >> 30) == 3) +#endif + +#ifndef STATUS_SUCCESS +# define STATUS_SUCCESS ((NTSTATUS) 0x00000000L) +#endif + +#ifndef STATUS_WAIT_0 +# define STATUS_WAIT_0 ((NTSTATUS) 0x00000000L) +#endif + +#ifndef STATUS_WAIT_1 +# define STATUS_WAIT_1 ((NTSTATUS) 0x00000001L) +#endif + +#ifndef STATUS_WAIT_2 +# define STATUS_WAIT_2 ((NTSTATUS) 0x00000002L) +#endif + +#ifndef STATUS_WAIT_3 +# define STATUS_WAIT_3 ((NTSTATUS) 0x00000003L) +#endif + +#ifndef STATUS_WAIT_63 +# define STATUS_WAIT_63 ((NTSTATUS) 0x0000003FL) +#endif + +#ifndef STATUS_ABANDONED +# define STATUS_ABANDONED ((NTSTATUS) 0x00000080L) +#endif + +#ifndef STATUS_ABANDONED_WAIT_0 +# define STATUS_ABANDONED_WAIT_0 ((NTSTATUS) 0x00000080L) +#endif + +#ifndef STATUS_ABANDONED_WAIT_63 +# define STATUS_ABANDONED_WAIT_63 ((NTSTATUS) 0x000000BFL) +#endif + +#ifndef STATUS_USER_APC +# define STATUS_USER_APC ((NTSTATUS) 0x000000C0L) +#endif + +#ifndef STATUS_KERNEL_APC +# define STATUS_KERNEL_APC ((NTSTATUS) 0x00000100L) +#endif + +#ifndef STATUS_ALERTED +# define STATUS_ALERTED ((NTSTATUS) 0x00000101L) +#endif + +#ifndef STATUS_TIMEOUT +# define STATUS_TIMEOUT ((NTSTATUS) 0x00000102L) +#endif + +#ifndef STATUS_PENDING +# define STATUS_PENDING ((NTSTATUS) 0x00000103L) +#endif + +#ifndef STATUS_REPARSE +# define STATUS_REPARSE ((NTSTATUS) 0x00000104L) +#endif + +#ifndef STATUS_MORE_ENTRIES +# define STATUS_MORE_ENTRIES ((NTSTATUS) 0x00000105L) +#endif + +#ifndef STATUS_NOT_ALL_ASSIGNED +# define STATUS_NOT_ALL_ASSIGNED ((NTSTATUS) 0x00000106L) +#endif + +#ifndef STATUS_SOME_NOT_MAPPED +# define STATUS_SOME_NOT_MAPPED ((NTSTATUS) 0x00000107L) +#endif + +#ifndef STATUS_OPLOCK_BREAK_IN_PROGRESS +# define STATUS_OPLOCK_BREAK_IN_PROGRESS ((NTSTATUS) 0x00000108L) +#endif + +#ifndef STATUS_VOLUME_MOUNTED +# define STATUS_VOLUME_MOUNTED ((NTSTATUS) 0x00000109L) +#endif + +#ifndef STATUS_RXACT_COMMITTED +# define STATUS_RXACT_COMMITTED ((NTSTATUS) 0x0000010AL) +#endif + +#ifndef STATUS_NOTIFY_CLEANUP +# define STATUS_NOTIFY_CLEANUP ((NTSTATUS) 0x0000010BL) +#endif + +#ifndef STATUS_NOTIFY_ENUM_DIR +# define STATUS_NOTIFY_ENUM_DIR ((NTSTATUS) 0x0000010CL) +#endif + +#ifndef STATUS_NO_QUOTAS_FOR_ACCOUNT +# define STATUS_NO_QUOTAS_FOR_ACCOUNT ((NTSTATUS) 0x0000010DL) +#endif + +#ifndef STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED +# define STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED ((NTSTATUS) 0x0000010EL) +#endif + +#ifndef STATUS_PAGE_FAULT_TRANSITION +# define STATUS_PAGE_FAULT_TRANSITION ((NTSTATUS) 0x00000110L) +#endif + +#ifndef STATUS_PAGE_FAULT_DEMAND_ZERO +# define STATUS_PAGE_FAULT_DEMAND_ZERO ((NTSTATUS) 0x00000111L) +#endif + +#ifndef STATUS_PAGE_FAULT_COPY_ON_WRITE +# define STATUS_PAGE_FAULT_COPY_ON_WRITE ((NTSTATUS) 0x00000112L) +#endif + +#ifndef STATUS_PAGE_FAULT_GUARD_PAGE +# define STATUS_PAGE_FAULT_GUARD_PAGE ((NTSTATUS) 0x00000113L) +#endif + +#ifndef STATUS_PAGE_FAULT_PAGING_FILE +# define STATUS_PAGE_FAULT_PAGING_FILE ((NTSTATUS) 0x00000114L) +#endif + +#ifndef STATUS_CACHE_PAGE_LOCKED +# define STATUS_CACHE_PAGE_LOCKED ((NTSTATUS) 0x00000115L) +#endif + +#ifndef STATUS_CRASH_DUMP +# define STATUS_CRASH_DUMP ((NTSTATUS) 0x00000116L) +#endif + +#ifndef STATUS_BUFFER_ALL_ZEROS +# define STATUS_BUFFER_ALL_ZEROS ((NTSTATUS) 0x00000117L) +#endif + +#ifndef STATUS_REPARSE_OBJECT +# define STATUS_REPARSE_OBJECT ((NTSTATUS) 0x00000118L) +#endif + +#ifndef STATUS_RESOURCE_REQUIREMENTS_CHANGED +# define STATUS_RESOURCE_REQUIREMENTS_CHANGED ((NTSTATUS) 0x00000119L) +#endif + +#ifndef STATUS_TRANSLATION_COMPLETE +# define STATUS_TRANSLATION_COMPLETE ((NTSTATUS) 0x00000120L) +#endif + +#ifndef STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY +# define STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY ((NTSTATUS) 0x00000121L) +#endif + +#ifndef STATUS_NOTHING_TO_TERMINATE +# define STATUS_NOTHING_TO_TERMINATE ((NTSTATUS) 0x00000122L) +#endif + +#ifndef STATUS_PROCESS_NOT_IN_JOB +# define STATUS_PROCESS_NOT_IN_JOB ((NTSTATUS) 0x00000123L) +#endif + +#ifndef STATUS_PROCESS_IN_JOB +# define STATUS_PROCESS_IN_JOB ((NTSTATUS) 0x00000124L) +#endif + +#ifndef STATUS_VOLSNAP_HIBERNATE_READY +# define STATUS_VOLSNAP_HIBERNATE_READY ((NTSTATUS) 0x00000125L) +#endif + +#ifndef STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY +# define STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY ((NTSTATUS) 0x00000126L) +#endif + +#ifndef STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED +# define STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED ((NTSTATUS) 0x00000127L) +#endif + +#ifndef STATUS_INTERRUPT_STILL_CONNECTED +# define STATUS_INTERRUPT_STILL_CONNECTED ((NTSTATUS) 0x00000128L) +#endif + +#ifndef STATUS_PROCESS_CLONED +# define STATUS_PROCESS_CLONED ((NTSTATUS) 0x00000129L) +#endif + +#ifndef STATUS_FILE_LOCKED_WITH_ONLY_READERS +# define STATUS_FILE_LOCKED_WITH_ONLY_READERS ((NTSTATUS) 0x0000012AL) +#endif + +#ifndef STATUS_FILE_LOCKED_WITH_WRITERS +# define STATUS_FILE_LOCKED_WITH_WRITERS ((NTSTATUS) 0x0000012BL) +#endif + +#ifndef STATUS_RESOURCEMANAGER_READ_ONLY +# define STATUS_RESOURCEMANAGER_READ_ONLY ((NTSTATUS) 0x00000202L) +#endif + +#ifndef STATUS_RING_PREVIOUSLY_EMPTY +# define STATUS_RING_PREVIOUSLY_EMPTY ((NTSTATUS) 0x00000210L) +#endif + +#ifndef STATUS_RING_PREVIOUSLY_FULL +# define STATUS_RING_PREVIOUSLY_FULL ((NTSTATUS) 0x00000211L) +#endif + +#ifndef STATUS_RING_PREVIOUSLY_ABOVE_QUOTA +# define STATUS_RING_PREVIOUSLY_ABOVE_QUOTA ((NTSTATUS) 0x00000212L) +#endif + +#ifndef STATUS_RING_NEWLY_EMPTY +# define STATUS_RING_NEWLY_EMPTY ((NTSTATUS) 0x00000213L) +#endif + +#ifndef STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT +# define STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT ((NTSTATUS) 0x00000214L) +#endif + +#ifndef STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE +# define STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE ((NTSTATUS) 0x00000215L) +#endif + +#ifndef STATUS_OPLOCK_HANDLE_CLOSED +# define STATUS_OPLOCK_HANDLE_CLOSED ((NTSTATUS) 0x00000216L) +#endif + +#ifndef STATUS_WAIT_FOR_OPLOCK +# define STATUS_WAIT_FOR_OPLOCK ((NTSTATUS) 0x00000367L) +#endif + +#ifndef STATUS_OBJECT_NAME_EXISTS +# define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS) 0x40000000L) +#endif + +#ifndef STATUS_THREAD_WAS_SUSPENDED +# define STATUS_THREAD_WAS_SUSPENDED ((NTSTATUS) 0x40000001L) +#endif + +#ifndef STATUS_WORKING_SET_LIMIT_RANGE +# define STATUS_WORKING_SET_LIMIT_RANGE ((NTSTATUS) 0x40000002L) +#endif + +#ifndef STATUS_IMAGE_NOT_AT_BASE +# define STATUS_IMAGE_NOT_AT_BASE ((NTSTATUS) 0x40000003L) +#endif + +#ifndef STATUS_RXACT_STATE_CREATED +# define STATUS_RXACT_STATE_CREATED ((NTSTATUS) 0x40000004L) +#endif + +#ifndef STATUS_SEGMENT_NOTIFICATION +# define STATUS_SEGMENT_NOTIFICATION ((NTSTATUS) 0x40000005L) +#endif + +#ifndef STATUS_LOCAL_USER_SESSION_KEY +# define STATUS_LOCAL_USER_SESSION_KEY ((NTSTATUS) 0x40000006L) +#endif + +#ifndef STATUS_BAD_CURRENT_DIRECTORY +# define STATUS_BAD_CURRENT_DIRECTORY ((NTSTATUS) 0x40000007L) +#endif + +#ifndef STATUS_SERIAL_MORE_WRITES +# define STATUS_SERIAL_MORE_WRITES ((NTSTATUS) 0x40000008L) +#endif + +#ifndef STATUS_REGISTRY_RECOVERED +# define STATUS_REGISTRY_RECOVERED ((NTSTATUS) 0x40000009L) +#endif + +#ifndef STATUS_FT_READ_RECOVERY_FROM_BACKUP +# define STATUS_FT_READ_RECOVERY_FROM_BACKUP ((NTSTATUS) 0x4000000AL) +#endif + +#ifndef STATUS_FT_WRITE_RECOVERY +# define STATUS_FT_WRITE_RECOVERY ((NTSTATUS) 0x4000000BL) +#endif + +#ifndef STATUS_SERIAL_COUNTER_TIMEOUT +# define STATUS_SERIAL_COUNTER_TIMEOUT ((NTSTATUS) 0x4000000CL) +#endif + +#ifndef STATUS_NULL_LM_PASSWORD +# define STATUS_NULL_LM_PASSWORD ((NTSTATUS) 0x4000000DL) +#endif + +#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH +# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH ((NTSTATUS) 0x4000000EL) +#endif + +#ifndef STATUS_RECEIVE_PARTIAL +# define STATUS_RECEIVE_PARTIAL ((NTSTATUS) 0x4000000FL) +#endif + +#ifndef STATUS_RECEIVE_EXPEDITED +# define STATUS_RECEIVE_EXPEDITED ((NTSTATUS) 0x40000010L) +#endif + +#ifndef STATUS_RECEIVE_PARTIAL_EXPEDITED +# define STATUS_RECEIVE_PARTIAL_EXPEDITED ((NTSTATUS) 0x40000011L) +#endif + +#ifndef STATUS_EVENT_DONE +# define STATUS_EVENT_DONE ((NTSTATUS) 0x40000012L) +#endif + +#ifndef STATUS_EVENT_PENDING +# define STATUS_EVENT_PENDING ((NTSTATUS) 0x40000013L) +#endif + +#ifndef STATUS_CHECKING_FILE_SYSTEM +# define STATUS_CHECKING_FILE_SYSTEM ((NTSTATUS) 0x40000014L) +#endif + +#ifndef STATUS_FATAL_APP_EXIT +# define STATUS_FATAL_APP_EXIT ((NTSTATUS) 0x40000015L) +#endif + +#ifndef STATUS_PREDEFINED_HANDLE +# define STATUS_PREDEFINED_HANDLE ((NTSTATUS) 0x40000016L) +#endif + +#ifndef STATUS_WAS_UNLOCKED +# define STATUS_WAS_UNLOCKED ((NTSTATUS) 0x40000017L) +#endif + +#ifndef STATUS_SERVICE_NOTIFICATION +# define STATUS_SERVICE_NOTIFICATION ((NTSTATUS) 0x40000018L) +#endif + +#ifndef STATUS_WAS_LOCKED +# define STATUS_WAS_LOCKED ((NTSTATUS) 0x40000019L) +#endif + +#ifndef STATUS_LOG_HARD_ERROR +# define STATUS_LOG_HARD_ERROR ((NTSTATUS) 0x4000001AL) +#endif + +#ifndef STATUS_ALREADY_WIN32 +# define STATUS_ALREADY_WIN32 ((NTSTATUS) 0x4000001BL) +#endif + +#ifndef STATUS_WX86_UNSIMULATE +# define STATUS_WX86_UNSIMULATE ((NTSTATUS) 0x4000001CL) +#endif + +#ifndef STATUS_WX86_CONTINUE +# define STATUS_WX86_CONTINUE ((NTSTATUS) 0x4000001DL) +#endif + +#ifndef STATUS_WX86_SINGLE_STEP +# define STATUS_WX86_SINGLE_STEP ((NTSTATUS) 0x4000001EL) +#endif + +#ifndef STATUS_WX86_BREAKPOINT +# define STATUS_WX86_BREAKPOINT ((NTSTATUS) 0x4000001FL) +#endif + +#ifndef STATUS_WX86_EXCEPTION_CONTINUE +# define STATUS_WX86_EXCEPTION_CONTINUE ((NTSTATUS) 0x40000020L) +#endif + +#ifndef STATUS_WX86_EXCEPTION_LASTCHANCE +# define STATUS_WX86_EXCEPTION_LASTCHANCE ((NTSTATUS) 0x40000021L) +#endif + +#ifndef STATUS_WX86_EXCEPTION_CHAIN +# define STATUS_WX86_EXCEPTION_CHAIN ((NTSTATUS) 0x40000022L) +#endif + +#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE +# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE ((NTSTATUS) 0x40000023L) +#endif + +#ifndef STATUS_NO_YIELD_PERFORMED +# define STATUS_NO_YIELD_PERFORMED ((NTSTATUS) 0x40000024L) +#endif + +#ifndef STATUS_TIMER_RESUME_IGNORED +# define STATUS_TIMER_RESUME_IGNORED ((NTSTATUS) 0x40000025L) +#endif + +#ifndef STATUS_ARBITRATION_UNHANDLED +# define STATUS_ARBITRATION_UNHANDLED ((NTSTATUS) 0x40000026L) +#endif + +#ifndef STATUS_CARDBUS_NOT_SUPPORTED +# define STATUS_CARDBUS_NOT_SUPPORTED ((NTSTATUS) 0x40000027L) +#endif + +#ifndef STATUS_WX86_CREATEWX86TIB +# define STATUS_WX86_CREATEWX86TIB ((NTSTATUS) 0x40000028L) +#endif + +#ifndef STATUS_MP_PROCESSOR_MISMATCH +# define STATUS_MP_PROCESSOR_MISMATCH ((NTSTATUS) 0x40000029L) +#endif + +#ifndef STATUS_HIBERNATED +# define STATUS_HIBERNATED ((NTSTATUS) 0x4000002AL) +#endif + +#ifndef STATUS_RESUME_HIBERNATION +# define STATUS_RESUME_HIBERNATION ((NTSTATUS) 0x4000002BL) +#endif + +#ifndef STATUS_FIRMWARE_UPDATED +# define STATUS_FIRMWARE_UPDATED ((NTSTATUS) 0x4000002CL) +#endif + +#ifndef STATUS_DRIVERS_LEAKING_LOCKED_PAGES +# define STATUS_DRIVERS_LEAKING_LOCKED_PAGES ((NTSTATUS) 0x4000002DL) +#endif + +#ifndef STATUS_MESSAGE_RETRIEVED +# define STATUS_MESSAGE_RETRIEVED ((NTSTATUS) 0x4000002EL) +#endif + +#ifndef STATUS_SYSTEM_POWERSTATE_TRANSITION +# define STATUS_SYSTEM_POWERSTATE_TRANSITION ((NTSTATUS) 0x4000002FL) +#endif + +#ifndef STATUS_ALPC_CHECK_COMPLETION_LIST +# define STATUS_ALPC_CHECK_COMPLETION_LIST ((NTSTATUS) 0x40000030L) +#endif + +#ifndef STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION +# define STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION ((NTSTATUS) 0x40000031L) +#endif + +#ifndef STATUS_ACCESS_AUDIT_BY_POLICY +# define STATUS_ACCESS_AUDIT_BY_POLICY ((NTSTATUS) 0x40000032L) +#endif + +#ifndef STATUS_ABANDON_HIBERFILE +# define STATUS_ABANDON_HIBERFILE ((NTSTATUS) 0x40000033L) +#endif + +#ifndef STATUS_BIZRULES_NOT_ENABLED +# define STATUS_BIZRULES_NOT_ENABLED ((NTSTATUS) 0x40000034L) +#endif + +#ifndef STATUS_GUARD_PAGE_VIOLATION +# define STATUS_GUARD_PAGE_VIOLATION ((NTSTATUS) 0x80000001L) +#endif + +#ifndef STATUS_DATATYPE_MISALIGNMENT +# define STATUS_DATATYPE_MISALIGNMENT ((NTSTATUS) 0x80000002L) +#endif + +#ifndef STATUS_BREAKPOINT +# define STATUS_BREAKPOINT ((NTSTATUS) 0x80000003L) +#endif + +#ifndef STATUS_SINGLE_STEP +# define STATUS_SINGLE_STEP ((NTSTATUS) 0x80000004L) +#endif + +#ifndef STATUS_BUFFER_OVERFLOW +# define STATUS_BUFFER_OVERFLOW ((NTSTATUS) 0x80000005L) +#endif + +#ifndef STATUS_NO_MORE_FILES +# define STATUS_NO_MORE_FILES ((NTSTATUS) 0x80000006L) +#endif + +#ifndef STATUS_WAKE_SYSTEM_DEBUGGER +# define STATUS_WAKE_SYSTEM_DEBUGGER ((NTSTATUS) 0x80000007L) +#endif + +#ifndef STATUS_HANDLES_CLOSED +# define STATUS_HANDLES_CLOSED ((NTSTATUS) 0x8000000AL) +#endif + +#ifndef STATUS_NO_INHERITANCE +# define STATUS_NO_INHERITANCE ((NTSTATUS) 0x8000000BL) +#endif + +#ifndef STATUS_GUID_SUBSTITUTION_MADE +# define STATUS_GUID_SUBSTITUTION_MADE ((NTSTATUS) 0x8000000CL) +#endif + +#ifndef STATUS_PARTIAL_COPY +# define STATUS_PARTIAL_COPY ((NTSTATUS) 0x8000000DL) +#endif + +#ifndef STATUS_DEVICE_PAPER_EMPTY +# define STATUS_DEVICE_PAPER_EMPTY ((NTSTATUS) 0x8000000EL) +#endif + +#ifndef STATUS_DEVICE_POWERED_OFF +# define STATUS_DEVICE_POWERED_OFF ((NTSTATUS) 0x8000000FL) +#endif + +#ifndef STATUS_DEVICE_OFF_LINE +# define STATUS_DEVICE_OFF_LINE ((NTSTATUS) 0x80000010L) +#endif + +#ifndef STATUS_DEVICE_BUSY +# define STATUS_DEVICE_BUSY ((NTSTATUS) 0x80000011L) +#endif + +#ifndef STATUS_NO_MORE_EAS +# define STATUS_NO_MORE_EAS ((NTSTATUS) 0x80000012L) +#endif + +#ifndef STATUS_INVALID_EA_NAME +# define STATUS_INVALID_EA_NAME ((NTSTATUS) 0x80000013L) +#endif + +#ifndef STATUS_EA_LIST_INCONSISTENT +# define STATUS_EA_LIST_INCONSISTENT ((NTSTATUS) 0x80000014L) +#endif + +#ifndef STATUS_INVALID_EA_FLAG +# define STATUS_INVALID_EA_FLAG ((NTSTATUS) 0x80000015L) +#endif + +#ifndef STATUS_VERIFY_REQUIRED +# define STATUS_VERIFY_REQUIRED ((NTSTATUS) 0x80000016L) +#endif + +#ifndef STATUS_EXTRANEOUS_INFORMATION +# define STATUS_EXTRANEOUS_INFORMATION ((NTSTATUS) 0x80000017L) +#endif + +#ifndef STATUS_RXACT_COMMIT_NECESSARY +# define STATUS_RXACT_COMMIT_NECESSARY ((NTSTATUS) 0x80000018L) +#endif + +#ifndef STATUS_NO_MORE_ENTRIES +# define STATUS_NO_MORE_ENTRIES ((NTSTATUS) 0x8000001AL) +#endif + +#ifndef STATUS_FILEMARK_DETECTED +# define STATUS_FILEMARK_DETECTED ((NTSTATUS) 0x8000001BL) +#endif + +#ifndef STATUS_MEDIA_CHANGED +# define STATUS_MEDIA_CHANGED ((NTSTATUS) 0x8000001CL) +#endif + +#ifndef STATUS_BUS_RESET +# define STATUS_BUS_RESET ((NTSTATUS) 0x8000001DL) +#endif + +#ifndef STATUS_END_OF_MEDIA +# define STATUS_END_OF_MEDIA ((NTSTATUS) 0x8000001EL) +#endif + +#ifndef STATUS_BEGINNING_OF_MEDIA +# define STATUS_BEGINNING_OF_MEDIA ((NTSTATUS) 0x8000001FL) +#endif + +#ifndef STATUS_MEDIA_CHECK +# define STATUS_MEDIA_CHECK ((NTSTATUS) 0x80000020L) +#endif + +#ifndef STATUS_SETMARK_DETECTED +# define STATUS_SETMARK_DETECTED ((NTSTATUS) 0x80000021L) +#endif + +#ifndef STATUS_NO_DATA_DETECTED +# define STATUS_NO_DATA_DETECTED ((NTSTATUS) 0x80000022L) +#endif + +#ifndef STATUS_REDIRECTOR_HAS_OPEN_HANDLES +# define STATUS_REDIRECTOR_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000023L) +#endif + +#ifndef STATUS_SERVER_HAS_OPEN_HANDLES +# define STATUS_SERVER_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000024L) +#endif + +#ifndef STATUS_ALREADY_DISCONNECTED +# define STATUS_ALREADY_DISCONNECTED ((NTSTATUS) 0x80000025L) +#endif + +#ifndef STATUS_LONGJUMP +# define STATUS_LONGJUMP ((NTSTATUS) 0x80000026L) +#endif + +#ifndef STATUS_CLEANER_CARTRIDGE_INSTALLED +# define STATUS_CLEANER_CARTRIDGE_INSTALLED ((NTSTATUS) 0x80000027L) +#endif + +#ifndef STATUS_PLUGPLAY_QUERY_VETOED +# define STATUS_PLUGPLAY_QUERY_VETOED ((NTSTATUS) 0x80000028L) +#endif + +#ifndef STATUS_UNWIND_CONSOLIDATE +# define STATUS_UNWIND_CONSOLIDATE ((NTSTATUS) 0x80000029L) +#endif + +#ifndef STATUS_REGISTRY_HIVE_RECOVERED +# define STATUS_REGISTRY_HIVE_RECOVERED ((NTSTATUS) 0x8000002AL) +#endif + +#ifndef STATUS_DLL_MIGHT_BE_INSECURE +# define STATUS_DLL_MIGHT_BE_INSECURE ((NTSTATUS) 0x8000002BL) +#endif + +#ifndef STATUS_DLL_MIGHT_BE_INCOMPATIBLE +# define STATUS_DLL_MIGHT_BE_INCOMPATIBLE ((NTSTATUS) 0x8000002CL) +#endif + +#ifndef STATUS_STOPPED_ON_SYMLINK +# define STATUS_STOPPED_ON_SYMLINK ((NTSTATUS) 0x8000002DL) +#endif + +#ifndef STATUS_CANNOT_GRANT_REQUESTED_OPLOCK +# define STATUS_CANNOT_GRANT_REQUESTED_OPLOCK ((NTSTATUS) 0x8000002EL) +#endif + +#ifndef STATUS_NO_ACE_CONDITION +# define STATUS_NO_ACE_CONDITION ((NTSTATUS) 0x8000002FL) +#endif + +#ifndef STATUS_UNSUCCESSFUL +# define STATUS_UNSUCCESSFUL ((NTSTATUS) 0xC0000001L) +#endif + +#ifndef STATUS_NOT_IMPLEMENTED +# define STATUS_NOT_IMPLEMENTED ((NTSTATUS) 0xC0000002L) +#endif + +#ifndef STATUS_INVALID_INFO_CLASS +# define STATUS_INVALID_INFO_CLASS ((NTSTATUS) 0xC0000003L) +#endif + +#ifndef STATUS_INFO_LENGTH_MISMATCH +# define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xC0000004L) +#endif + +#ifndef STATUS_ACCESS_VIOLATION +# define STATUS_ACCESS_VIOLATION ((NTSTATUS) 0xC0000005L) +#endif + +#ifndef STATUS_IN_PAGE_ERROR +# define STATUS_IN_PAGE_ERROR ((NTSTATUS) 0xC0000006L) +#endif + +#ifndef STATUS_PAGEFILE_QUOTA +# define STATUS_PAGEFILE_QUOTA ((NTSTATUS) 0xC0000007L) +#endif + +#ifndef STATUS_INVALID_HANDLE +# define STATUS_INVALID_HANDLE ((NTSTATUS) 0xC0000008L) +#endif + +#ifndef STATUS_BAD_INITIAL_STACK +# define STATUS_BAD_INITIAL_STACK ((NTSTATUS) 0xC0000009L) +#endif + +#ifndef STATUS_BAD_INITIAL_PC +# define STATUS_BAD_INITIAL_PC ((NTSTATUS) 0xC000000AL) +#endif + +#ifndef STATUS_INVALID_CID +# define STATUS_INVALID_CID ((NTSTATUS) 0xC000000BL) +#endif + +#ifndef STATUS_TIMER_NOT_CANCELED +# define STATUS_TIMER_NOT_CANCELED ((NTSTATUS) 0xC000000CL) +#endif + +#ifndef STATUS_INVALID_PARAMETER +# define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xC000000DL) +#endif + +#ifndef STATUS_NO_SUCH_DEVICE +# define STATUS_NO_SUCH_DEVICE ((NTSTATUS) 0xC000000EL) +#endif + +#ifndef STATUS_NO_SUCH_FILE +# define STATUS_NO_SUCH_FILE ((NTSTATUS) 0xC000000FL) +#endif + +#ifndef STATUS_INVALID_DEVICE_REQUEST +# define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS) 0xC0000010L) +#endif + +#ifndef STATUS_END_OF_FILE +# define STATUS_END_OF_FILE ((NTSTATUS) 0xC0000011L) +#endif + +#ifndef STATUS_WRONG_VOLUME +# define STATUS_WRONG_VOLUME ((NTSTATUS) 0xC0000012L) +#endif + +#ifndef STATUS_NO_MEDIA_IN_DEVICE +# define STATUS_NO_MEDIA_IN_DEVICE ((NTSTATUS) 0xC0000013L) +#endif + +#ifndef STATUS_UNRECOGNIZED_MEDIA +# define STATUS_UNRECOGNIZED_MEDIA ((NTSTATUS) 0xC0000014L) +#endif + +#ifndef STATUS_NONEXISTENT_SECTOR +# define STATUS_NONEXISTENT_SECTOR ((NTSTATUS) 0xC0000015L) +#endif + +#ifndef STATUS_MORE_PROCESSING_REQUIRED +# define STATUS_MORE_PROCESSING_REQUIRED ((NTSTATUS) 0xC0000016L) +#endif + +#ifndef STATUS_NO_MEMORY +# define STATUS_NO_MEMORY ((NTSTATUS) 0xC0000017L) +#endif + +#ifndef STATUS_CONFLICTING_ADDRESSES +# define STATUS_CONFLICTING_ADDRESSES ((NTSTATUS) 0xC0000018L) +#endif + +#ifndef STATUS_NOT_MAPPED_VIEW +# define STATUS_NOT_MAPPED_VIEW ((NTSTATUS) 0xC0000019L) +#endif + +#ifndef STATUS_UNABLE_TO_FREE_VM +# define STATUS_UNABLE_TO_FREE_VM ((NTSTATUS) 0xC000001AL) +#endif + +#ifndef STATUS_UNABLE_TO_DELETE_SECTION +# define STATUS_UNABLE_TO_DELETE_SECTION ((NTSTATUS) 0xC000001BL) +#endif + +#ifndef STATUS_INVALID_SYSTEM_SERVICE +# define STATUS_INVALID_SYSTEM_SERVICE ((NTSTATUS) 0xC000001CL) +#endif + +#ifndef STATUS_ILLEGAL_INSTRUCTION +# define STATUS_ILLEGAL_INSTRUCTION ((NTSTATUS) 0xC000001DL) +#endif + +#ifndef STATUS_INVALID_LOCK_SEQUENCE +# define STATUS_INVALID_LOCK_SEQUENCE ((NTSTATUS) 0xC000001EL) +#endif + +#ifndef STATUS_INVALID_VIEW_SIZE +# define STATUS_INVALID_VIEW_SIZE ((NTSTATUS) 0xC000001FL) +#endif + +#ifndef STATUS_INVALID_FILE_FOR_SECTION +# define STATUS_INVALID_FILE_FOR_SECTION ((NTSTATUS) 0xC0000020L) +#endif + +#ifndef STATUS_ALREADY_COMMITTED +# define STATUS_ALREADY_COMMITTED ((NTSTATUS) 0xC0000021L) +#endif + +#ifndef STATUS_ACCESS_DENIED +# define STATUS_ACCESS_DENIED ((NTSTATUS) 0xC0000022L) +#endif + +#ifndef STATUS_BUFFER_TOO_SMALL +# define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xC0000023L) +#endif + +#ifndef STATUS_OBJECT_TYPE_MISMATCH +# define STATUS_OBJECT_TYPE_MISMATCH ((NTSTATUS) 0xC0000024L) +#endif + +#ifndef STATUS_NONCONTINUABLE_EXCEPTION +# define STATUS_NONCONTINUABLE_EXCEPTION ((NTSTATUS) 0xC0000025L) +#endif + +#ifndef STATUS_INVALID_DISPOSITION +# define STATUS_INVALID_DISPOSITION ((NTSTATUS) 0xC0000026L) +#endif + +#ifndef STATUS_UNWIND +# define STATUS_UNWIND ((NTSTATUS) 0xC0000027L) +#endif + +#ifndef STATUS_BAD_STACK +# define STATUS_BAD_STACK ((NTSTATUS) 0xC0000028L) +#endif + +#ifndef STATUS_INVALID_UNWIND_TARGET +# define STATUS_INVALID_UNWIND_TARGET ((NTSTATUS) 0xC0000029L) +#endif + +#ifndef STATUS_NOT_LOCKED +# define STATUS_NOT_LOCKED ((NTSTATUS) 0xC000002AL) +#endif + +#ifndef STATUS_PARITY_ERROR +# define STATUS_PARITY_ERROR ((NTSTATUS) 0xC000002BL) +#endif + +#ifndef STATUS_UNABLE_TO_DECOMMIT_VM +# define STATUS_UNABLE_TO_DECOMMIT_VM ((NTSTATUS) 0xC000002CL) +#endif + +#ifndef STATUS_NOT_COMMITTED +# define STATUS_NOT_COMMITTED ((NTSTATUS) 0xC000002DL) +#endif + +#ifndef STATUS_INVALID_PORT_ATTRIBUTES +# define STATUS_INVALID_PORT_ATTRIBUTES ((NTSTATUS) 0xC000002EL) +#endif + +#ifndef STATUS_PORT_MESSAGE_TOO_LONG +# define STATUS_PORT_MESSAGE_TOO_LONG ((NTSTATUS) 0xC000002FL) +#endif + +#ifndef STATUS_INVALID_PARAMETER_MIX +# define STATUS_INVALID_PARAMETER_MIX ((NTSTATUS) 0xC0000030L) +#endif + +#ifndef STATUS_INVALID_QUOTA_LOWER +# define STATUS_INVALID_QUOTA_LOWER ((NTSTATUS) 0xC0000031L) +#endif + +#ifndef STATUS_DISK_CORRUPT_ERROR +# define STATUS_DISK_CORRUPT_ERROR ((NTSTATUS) 0xC0000032L) +#endif + +#ifndef STATUS_OBJECT_NAME_INVALID +# define STATUS_OBJECT_NAME_INVALID ((NTSTATUS) 0xC0000033L) +#endif + +#ifndef STATUS_OBJECT_NAME_NOT_FOUND +# define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xC0000034L) +#endif + +#ifndef STATUS_OBJECT_NAME_COLLISION +# define STATUS_OBJECT_NAME_COLLISION ((NTSTATUS) 0xC0000035L) +#endif + +#ifndef STATUS_PORT_DISCONNECTED +# define STATUS_PORT_DISCONNECTED ((NTSTATUS) 0xC0000037L) +#endif + +#ifndef STATUS_DEVICE_ALREADY_ATTACHED +# define STATUS_DEVICE_ALREADY_ATTACHED ((NTSTATUS) 0xC0000038L) +#endif + +#ifndef STATUS_OBJECT_PATH_INVALID +# define STATUS_OBJECT_PATH_INVALID ((NTSTATUS) 0xC0000039L) +#endif + +#ifndef STATUS_OBJECT_PATH_NOT_FOUND +# define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS) 0xC000003AL) +#endif + +#ifndef STATUS_OBJECT_PATH_SYNTAX_BAD +# define STATUS_OBJECT_PATH_SYNTAX_BAD ((NTSTATUS) 0xC000003BL) +#endif + +#ifndef STATUS_DATA_OVERRUN +# define STATUS_DATA_OVERRUN ((NTSTATUS) 0xC000003CL) +#endif + +#ifndef STATUS_DATA_LATE_ERROR +# define STATUS_DATA_LATE_ERROR ((NTSTATUS) 0xC000003DL) +#endif + +#ifndef STATUS_DATA_ERROR +# define STATUS_DATA_ERROR ((NTSTATUS) 0xC000003EL) +#endif + +#ifndef STATUS_CRC_ERROR +# define STATUS_CRC_ERROR ((NTSTATUS) 0xC000003FL) +#endif + +#ifndef STATUS_SECTION_TOO_BIG +# define STATUS_SECTION_TOO_BIG ((NTSTATUS) 0xC0000040L) +#endif + +#ifndef STATUS_PORT_CONNECTION_REFUSED +# define STATUS_PORT_CONNECTION_REFUSED ((NTSTATUS) 0xC0000041L) +#endif + +#ifndef STATUS_INVALID_PORT_HANDLE +# define STATUS_INVALID_PORT_HANDLE ((NTSTATUS) 0xC0000042L) +#endif + +#ifndef STATUS_SHARING_VIOLATION +# define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xC0000043L) +#endif + +#ifndef STATUS_QUOTA_EXCEEDED +# define STATUS_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000044L) +#endif + +#ifndef STATUS_INVALID_PAGE_PROTECTION +# define STATUS_INVALID_PAGE_PROTECTION ((NTSTATUS) 0xC0000045L) +#endif + +#ifndef STATUS_MUTANT_NOT_OWNED +# define STATUS_MUTANT_NOT_OWNED ((NTSTATUS) 0xC0000046L) +#endif + +#ifndef STATUS_SEMAPHORE_LIMIT_EXCEEDED +# define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000047L) +#endif + +#ifndef STATUS_PORT_ALREADY_SET +# define STATUS_PORT_ALREADY_SET ((NTSTATUS) 0xC0000048L) +#endif + +#ifndef STATUS_SECTION_NOT_IMAGE +# define STATUS_SECTION_NOT_IMAGE ((NTSTATUS) 0xC0000049L) +#endif + +#ifndef STATUS_SUSPEND_COUNT_EXCEEDED +# define STATUS_SUSPEND_COUNT_EXCEEDED ((NTSTATUS) 0xC000004AL) +#endif + +#ifndef STATUS_THREAD_IS_TERMINATING +# define STATUS_THREAD_IS_TERMINATING ((NTSTATUS) 0xC000004BL) +#endif + +#ifndef STATUS_BAD_WORKING_SET_LIMIT +# define STATUS_BAD_WORKING_SET_LIMIT ((NTSTATUS) 0xC000004CL) +#endif + +#ifndef STATUS_INCOMPATIBLE_FILE_MAP +# define STATUS_INCOMPATIBLE_FILE_MAP ((NTSTATUS) 0xC000004DL) +#endif + +#ifndef STATUS_SECTION_PROTECTION +# define STATUS_SECTION_PROTECTION ((NTSTATUS) 0xC000004EL) +#endif + +#ifndef STATUS_EAS_NOT_SUPPORTED +# define STATUS_EAS_NOT_SUPPORTED ((NTSTATUS) 0xC000004FL) +#endif + +#ifndef STATUS_EA_TOO_LARGE +# define STATUS_EA_TOO_LARGE ((NTSTATUS) 0xC0000050L) +#endif + +#ifndef STATUS_NONEXISTENT_EA_ENTRY +# define STATUS_NONEXISTENT_EA_ENTRY ((NTSTATUS) 0xC0000051L) +#endif + +#ifndef STATUS_NO_EAS_ON_FILE +# define STATUS_NO_EAS_ON_FILE ((NTSTATUS) 0xC0000052L) +#endif + +#ifndef STATUS_EA_CORRUPT_ERROR +# define STATUS_EA_CORRUPT_ERROR ((NTSTATUS) 0xC0000053L) +#endif + +#ifndef STATUS_FILE_LOCK_CONFLICT +# define STATUS_FILE_LOCK_CONFLICT ((NTSTATUS) 0xC0000054L) +#endif + +#ifndef STATUS_LOCK_NOT_GRANTED +# define STATUS_LOCK_NOT_GRANTED ((NTSTATUS) 0xC0000055L) +#endif + +#ifndef STATUS_DELETE_PENDING +# define STATUS_DELETE_PENDING ((NTSTATUS) 0xC0000056L) +#endif + +#ifndef STATUS_CTL_FILE_NOT_SUPPORTED +# define STATUS_CTL_FILE_NOT_SUPPORTED ((NTSTATUS) 0xC0000057L) +#endif + +#ifndef STATUS_UNKNOWN_REVISION +# define STATUS_UNKNOWN_REVISION ((NTSTATUS) 0xC0000058L) +#endif + +#ifndef STATUS_REVISION_MISMATCH +# define STATUS_REVISION_MISMATCH ((NTSTATUS) 0xC0000059L) +#endif + +#ifndef STATUS_INVALID_OWNER +# define STATUS_INVALID_OWNER ((NTSTATUS) 0xC000005AL) +#endif + +#ifndef STATUS_INVALID_PRIMARY_GROUP +# define STATUS_INVALID_PRIMARY_GROUP ((NTSTATUS) 0xC000005BL) +#endif + +#ifndef STATUS_NO_IMPERSONATION_TOKEN +# define STATUS_NO_IMPERSONATION_TOKEN ((NTSTATUS) 0xC000005CL) +#endif + +#ifndef STATUS_CANT_DISABLE_MANDATORY +# define STATUS_CANT_DISABLE_MANDATORY ((NTSTATUS) 0xC000005DL) +#endif + +#ifndef STATUS_NO_LOGON_SERVERS +# define STATUS_NO_LOGON_SERVERS ((NTSTATUS) 0xC000005EL) +#endif + +#ifndef STATUS_NO_SUCH_LOGON_SESSION +# define STATUS_NO_SUCH_LOGON_SESSION ((NTSTATUS) 0xC000005FL) +#endif + +#ifndef STATUS_NO_SUCH_PRIVILEGE +# define STATUS_NO_SUCH_PRIVILEGE ((NTSTATUS) 0xC0000060L) +#endif + +#ifndef STATUS_PRIVILEGE_NOT_HELD +# define STATUS_PRIVILEGE_NOT_HELD ((NTSTATUS) 0xC0000061L) +#endif + +#ifndef STATUS_INVALID_ACCOUNT_NAME +# define STATUS_INVALID_ACCOUNT_NAME ((NTSTATUS) 0xC0000062L) +#endif + +#ifndef STATUS_USER_EXISTS +# define STATUS_USER_EXISTS ((NTSTATUS) 0xC0000063L) +#endif + +#ifndef STATUS_NO_SUCH_USER +# define STATUS_NO_SUCH_USER ((NTSTATUS) 0xC0000064L) +#endif + +#ifndef STATUS_GROUP_EXISTS +# define STATUS_GROUP_EXISTS ((NTSTATUS) 0xC0000065L) +#endif + +#ifndef STATUS_NO_SUCH_GROUP +# define STATUS_NO_SUCH_GROUP ((NTSTATUS) 0xC0000066L) +#endif + +#ifndef STATUS_MEMBER_IN_GROUP +# define STATUS_MEMBER_IN_GROUP ((NTSTATUS) 0xC0000067L) +#endif + +#ifndef STATUS_MEMBER_NOT_IN_GROUP +# define STATUS_MEMBER_NOT_IN_GROUP ((NTSTATUS) 0xC0000068L) +#endif + +#ifndef STATUS_LAST_ADMIN +# define STATUS_LAST_ADMIN ((NTSTATUS) 0xC0000069L) +#endif + +#ifndef STATUS_WRONG_PASSWORD +# define STATUS_WRONG_PASSWORD ((NTSTATUS) 0xC000006AL) +#endif + +#ifndef STATUS_ILL_FORMED_PASSWORD +# define STATUS_ILL_FORMED_PASSWORD ((NTSTATUS) 0xC000006BL) +#endif + +#ifndef STATUS_PASSWORD_RESTRICTION +# define STATUS_PASSWORD_RESTRICTION ((NTSTATUS) 0xC000006CL) +#endif + +#ifndef STATUS_LOGON_FAILURE +# define STATUS_LOGON_FAILURE ((NTSTATUS) 0xC000006DL) +#endif + +#ifndef STATUS_ACCOUNT_RESTRICTION +# define STATUS_ACCOUNT_RESTRICTION ((NTSTATUS) 0xC000006EL) +#endif + +#ifndef STATUS_INVALID_LOGON_HOURS +# define STATUS_INVALID_LOGON_HOURS ((NTSTATUS) 0xC000006FL) +#endif + +#ifndef STATUS_INVALID_WORKSTATION +# define STATUS_INVALID_WORKSTATION ((NTSTATUS) 0xC0000070L) +#endif + +#ifndef STATUS_PASSWORD_EXPIRED +# define STATUS_PASSWORD_EXPIRED ((NTSTATUS) 0xC0000071L) +#endif + +#ifndef STATUS_ACCOUNT_DISABLED +# define STATUS_ACCOUNT_DISABLED ((NTSTATUS) 0xC0000072L) +#endif + +#ifndef STATUS_NONE_MAPPED +# define STATUS_NONE_MAPPED ((NTSTATUS) 0xC0000073L) +#endif + +#ifndef STATUS_TOO_MANY_LUIDS_REQUESTED +# define STATUS_TOO_MANY_LUIDS_REQUESTED ((NTSTATUS) 0xC0000074L) +#endif + +#ifndef STATUS_LUIDS_EXHAUSTED +# define STATUS_LUIDS_EXHAUSTED ((NTSTATUS) 0xC0000075L) +#endif + +#ifndef STATUS_INVALID_SUB_AUTHORITY +# define STATUS_INVALID_SUB_AUTHORITY ((NTSTATUS) 0xC0000076L) +#endif + +#ifndef STATUS_INVALID_ACL +# define STATUS_INVALID_ACL ((NTSTATUS) 0xC0000077L) +#endif + +#ifndef STATUS_INVALID_SID +# define STATUS_INVALID_SID ((NTSTATUS) 0xC0000078L) +#endif + +#ifndef STATUS_INVALID_SECURITY_DESCR +# define STATUS_INVALID_SECURITY_DESCR ((NTSTATUS) 0xC0000079L) +#endif + +#ifndef STATUS_PROCEDURE_NOT_FOUND +# define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS) 0xC000007AL) +#endif + +#ifndef STATUS_INVALID_IMAGE_FORMAT +# define STATUS_INVALID_IMAGE_FORMAT ((NTSTATUS) 0xC000007BL) +#endif + +#ifndef STATUS_NO_TOKEN +# define STATUS_NO_TOKEN ((NTSTATUS) 0xC000007CL) +#endif + +#ifndef STATUS_BAD_INHERITANCE_ACL +# define STATUS_BAD_INHERITANCE_ACL ((NTSTATUS) 0xC000007DL) +#endif + +#ifndef STATUS_RANGE_NOT_LOCKED +# define STATUS_RANGE_NOT_LOCKED ((NTSTATUS) 0xC000007EL) +#endif + +#ifndef STATUS_DISK_FULL +# define STATUS_DISK_FULL ((NTSTATUS) 0xC000007FL) +#endif + +#ifndef STATUS_SERVER_DISABLED +# define STATUS_SERVER_DISABLED ((NTSTATUS) 0xC0000080L) +#endif + +#ifndef STATUS_SERVER_NOT_DISABLED +# define STATUS_SERVER_NOT_DISABLED ((NTSTATUS) 0xC0000081L) +#endif + +#ifndef STATUS_TOO_MANY_GUIDS_REQUESTED +# define STATUS_TOO_MANY_GUIDS_REQUESTED ((NTSTATUS) 0xC0000082L) +#endif + +#ifndef STATUS_GUIDS_EXHAUSTED +# define STATUS_GUIDS_EXHAUSTED ((NTSTATUS) 0xC0000083L) +#endif + +#ifndef STATUS_INVALID_ID_AUTHORITY +# define STATUS_INVALID_ID_AUTHORITY ((NTSTATUS) 0xC0000084L) +#endif + +#ifndef STATUS_AGENTS_EXHAUSTED +# define STATUS_AGENTS_EXHAUSTED ((NTSTATUS) 0xC0000085L) +#endif + +#ifndef STATUS_INVALID_VOLUME_LABEL +# define STATUS_INVALID_VOLUME_LABEL ((NTSTATUS) 0xC0000086L) +#endif + +#ifndef STATUS_SECTION_NOT_EXTENDED +# define STATUS_SECTION_NOT_EXTENDED ((NTSTATUS) 0xC0000087L) +#endif + +#ifndef STATUS_NOT_MAPPED_DATA +# define STATUS_NOT_MAPPED_DATA ((NTSTATUS) 0xC0000088L) +#endif + +#ifndef STATUS_RESOURCE_DATA_NOT_FOUND +# define STATUS_RESOURCE_DATA_NOT_FOUND ((NTSTATUS) 0xC0000089L) +#endif + +#ifndef STATUS_RESOURCE_TYPE_NOT_FOUND +# define STATUS_RESOURCE_TYPE_NOT_FOUND ((NTSTATUS) 0xC000008AL) +#endif + +#ifndef STATUS_RESOURCE_NAME_NOT_FOUND +# define STATUS_RESOURCE_NAME_NOT_FOUND ((NTSTATUS) 0xC000008BL) +#endif + +#ifndef STATUS_ARRAY_BOUNDS_EXCEEDED +# define STATUS_ARRAY_BOUNDS_EXCEEDED ((NTSTATUS) 0xC000008CL) +#endif + +#ifndef STATUS_FLOAT_DENORMAL_OPERAND +# define STATUS_FLOAT_DENORMAL_OPERAND ((NTSTATUS) 0xC000008DL) +#endif + +#ifndef STATUS_FLOAT_DIVIDE_BY_ZERO +# define STATUS_FLOAT_DIVIDE_BY_ZERO ((NTSTATUS) 0xC000008EL) +#endif + +#ifndef STATUS_FLOAT_INEXACT_RESULT +# define STATUS_FLOAT_INEXACT_RESULT ((NTSTATUS) 0xC000008FL) +#endif + +#ifndef STATUS_FLOAT_INVALID_OPERATION +# define STATUS_FLOAT_INVALID_OPERATION ((NTSTATUS) 0xC0000090L) +#endif + +#ifndef STATUS_FLOAT_OVERFLOW +# define STATUS_FLOAT_OVERFLOW ((NTSTATUS) 0xC0000091L) +#endif + +#ifndef STATUS_FLOAT_STACK_CHECK +# define STATUS_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000092L) +#endif + +#ifndef STATUS_FLOAT_UNDERFLOW +# define STATUS_FLOAT_UNDERFLOW ((NTSTATUS) 0xC0000093L) +#endif + +#ifndef STATUS_INTEGER_DIVIDE_BY_ZERO +# define STATUS_INTEGER_DIVIDE_BY_ZERO ((NTSTATUS) 0xC0000094L) +#endif + +#ifndef STATUS_INTEGER_OVERFLOW +# define STATUS_INTEGER_OVERFLOW ((NTSTATUS) 0xC0000095L) +#endif + +#ifndef STATUS_PRIVILEGED_INSTRUCTION +# define STATUS_PRIVILEGED_INSTRUCTION ((NTSTATUS) 0xC0000096L) +#endif + +#ifndef STATUS_TOO_MANY_PAGING_FILES +# define STATUS_TOO_MANY_PAGING_FILES ((NTSTATUS) 0xC0000097L) +#endif + +#ifndef STATUS_FILE_INVALID +# define STATUS_FILE_INVALID ((NTSTATUS) 0xC0000098L) +#endif + +#ifndef STATUS_ALLOTTED_SPACE_EXCEEDED +# define STATUS_ALLOTTED_SPACE_EXCEEDED ((NTSTATUS) 0xC0000099L) +#endif + +#ifndef STATUS_INSUFFICIENT_RESOURCES +# define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS) 0xC000009AL) +#endif + +#ifndef STATUS_DFS_EXIT_PATH_FOUND +# define STATUS_DFS_EXIT_PATH_FOUND ((NTSTATUS) 0xC000009BL) +#endif + +#ifndef STATUS_DEVICE_DATA_ERROR +# define STATUS_DEVICE_DATA_ERROR ((NTSTATUS) 0xC000009CL) +#endif + +#ifndef STATUS_DEVICE_NOT_CONNECTED +# define STATUS_DEVICE_NOT_CONNECTED ((NTSTATUS) 0xC000009DL) +#endif + +#ifndef STATUS_DEVICE_POWER_FAILURE +# define STATUS_DEVICE_POWER_FAILURE ((NTSTATUS) 0xC000009EL) +#endif + +#ifndef STATUS_FREE_VM_NOT_AT_BASE +# define STATUS_FREE_VM_NOT_AT_BASE ((NTSTATUS) 0xC000009FL) +#endif + +#ifndef STATUS_MEMORY_NOT_ALLOCATED +# define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS) 0xC00000A0L) +#endif + +#ifndef STATUS_WORKING_SET_QUOTA +# define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xC00000A1L) +#endif + +#ifndef STATUS_MEDIA_WRITE_PROTECTED +# define STATUS_MEDIA_WRITE_PROTECTED ((NTSTATUS) 0xC00000A2L) +#endif + +#ifndef STATUS_DEVICE_NOT_READY +# define STATUS_DEVICE_NOT_READY ((NTSTATUS) 0xC00000A3L) +#endif + +#ifndef STATUS_INVALID_GROUP_ATTRIBUTES +# define STATUS_INVALID_GROUP_ATTRIBUTES ((NTSTATUS) 0xC00000A4L) +#endif + +#ifndef STATUS_BAD_IMPERSONATION_LEVEL +# define STATUS_BAD_IMPERSONATION_LEVEL ((NTSTATUS) 0xC00000A5L) +#endif + +#ifndef STATUS_CANT_OPEN_ANONYMOUS +# define STATUS_CANT_OPEN_ANONYMOUS ((NTSTATUS) 0xC00000A6L) +#endif + +#ifndef STATUS_BAD_VALIDATION_CLASS +# define STATUS_BAD_VALIDATION_CLASS ((NTSTATUS) 0xC00000A7L) +#endif + +#ifndef STATUS_BAD_TOKEN_TYPE +# define STATUS_BAD_TOKEN_TYPE ((NTSTATUS) 0xC00000A8L) +#endif + +#ifndef STATUS_BAD_MASTER_BOOT_RECORD +# define STATUS_BAD_MASTER_BOOT_RECORD ((NTSTATUS) 0xC00000A9L) +#endif + +#ifndef STATUS_INSTRUCTION_MISALIGNMENT +# define STATUS_INSTRUCTION_MISALIGNMENT ((NTSTATUS) 0xC00000AAL) +#endif + +#ifndef STATUS_INSTANCE_NOT_AVAILABLE +# define STATUS_INSTANCE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ABL) +#endif + +#ifndef STATUS_PIPE_NOT_AVAILABLE +# define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ACL) +#endif + +#ifndef STATUS_INVALID_PIPE_STATE +# define STATUS_INVALID_PIPE_STATE ((NTSTATUS) 0xC00000ADL) +#endif + +#ifndef STATUS_PIPE_BUSY +# define STATUS_PIPE_BUSY ((NTSTATUS) 0xC00000AEL) +#endif + +#ifndef STATUS_ILLEGAL_FUNCTION +# define STATUS_ILLEGAL_FUNCTION ((NTSTATUS) 0xC00000AFL) +#endif + +#ifndef STATUS_PIPE_DISCONNECTED +# define STATUS_PIPE_DISCONNECTED ((NTSTATUS) 0xC00000B0L) +#endif + +#ifndef STATUS_PIPE_CLOSING +# define STATUS_PIPE_CLOSING ((NTSTATUS) 0xC00000B1L) +#endif + +#ifndef STATUS_PIPE_CONNECTED +# define STATUS_PIPE_CONNECTED ((NTSTATUS) 0xC00000B2L) +#endif + +#ifndef STATUS_PIPE_LISTENING +# define STATUS_PIPE_LISTENING ((NTSTATUS) 0xC00000B3L) +#endif + +#ifndef STATUS_INVALID_READ_MODE +# define STATUS_INVALID_READ_MODE ((NTSTATUS) 0xC00000B4L) +#endif + +#ifndef STATUS_IO_TIMEOUT +# define STATUS_IO_TIMEOUT ((NTSTATUS) 0xC00000B5L) +#endif + +#ifndef STATUS_FILE_FORCED_CLOSED +# define STATUS_FILE_FORCED_CLOSED ((NTSTATUS) 0xC00000B6L) +#endif + +#ifndef STATUS_PROFILING_NOT_STARTED +# define STATUS_PROFILING_NOT_STARTED ((NTSTATUS) 0xC00000B7L) +#endif + +#ifndef STATUS_PROFILING_NOT_STOPPED +# define STATUS_PROFILING_NOT_STOPPED ((NTSTATUS) 0xC00000B8L) +#endif + +#ifndef STATUS_COULD_NOT_INTERPRET +# define STATUS_COULD_NOT_INTERPRET ((NTSTATUS) 0xC00000B9L) +#endif + +#ifndef STATUS_FILE_IS_A_DIRECTORY +# define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS) 0xC00000BAL) +#endif + +#ifndef STATUS_NOT_SUPPORTED +# define STATUS_NOT_SUPPORTED ((NTSTATUS) 0xC00000BBL) +#endif + +#ifndef STATUS_REMOTE_NOT_LISTENING +# define STATUS_REMOTE_NOT_LISTENING ((NTSTATUS) 0xC00000BCL) +#endif + +#ifndef STATUS_DUPLICATE_NAME +# define STATUS_DUPLICATE_NAME ((NTSTATUS) 0xC00000BDL) +#endif + +#ifndef STATUS_BAD_NETWORK_PATH +# define STATUS_BAD_NETWORK_PATH ((NTSTATUS) 0xC00000BEL) +#endif + +#ifndef STATUS_NETWORK_BUSY +# define STATUS_NETWORK_BUSY ((NTSTATUS) 0xC00000BFL) +#endif + +#ifndef STATUS_DEVICE_DOES_NOT_EXIST +# define STATUS_DEVICE_DOES_NOT_EXIST ((NTSTATUS) 0xC00000C0L) +#endif + +#ifndef STATUS_TOO_MANY_COMMANDS +# define STATUS_TOO_MANY_COMMANDS ((NTSTATUS) 0xC00000C1L) +#endif + +#ifndef STATUS_ADAPTER_HARDWARE_ERROR +# define STATUS_ADAPTER_HARDWARE_ERROR ((NTSTATUS) 0xC00000C2L) +#endif + +#ifndef STATUS_INVALID_NETWORK_RESPONSE +# define STATUS_INVALID_NETWORK_RESPONSE ((NTSTATUS) 0xC00000C3L) +#endif + +#ifndef STATUS_UNEXPECTED_NETWORK_ERROR +# define STATUS_UNEXPECTED_NETWORK_ERROR ((NTSTATUS) 0xC00000C4L) +#endif + +#ifndef STATUS_BAD_REMOTE_ADAPTER +# define STATUS_BAD_REMOTE_ADAPTER ((NTSTATUS) 0xC00000C5L) +#endif + +#ifndef STATUS_PRINT_QUEUE_FULL +# define STATUS_PRINT_QUEUE_FULL ((NTSTATUS) 0xC00000C6L) +#endif + +#ifndef STATUS_NO_SPOOL_SPACE +# define STATUS_NO_SPOOL_SPACE ((NTSTATUS) 0xC00000C7L) +#endif + +#ifndef STATUS_PRINT_CANCELLED +# define STATUS_PRINT_CANCELLED ((NTSTATUS) 0xC00000C8L) +#endif + +#ifndef STATUS_NETWORK_NAME_DELETED +# define STATUS_NETWORK_NAME_DELETED ((NTSTATUS) 0xC00000C9L) +#endif + +#ifndef STATUS_NETWORK_ACCESS_DENIED +# define STATUS_NETWORK_ACCESS_DENIED ((NTSTATUS) 0xC00000CAL) +#endif + +#ifndef STATUS_BAD_DEVICE_TYPE +# define STATUS_BAD_DEVICE_TYPE ((NTSTATUS) 0xC00000CBL) +#endif + +#ifndef STATUS_BAD_NETWORK_NAME +# define STATUS_BAD_NETWORK_NAME ((NTSTATUS) 0xC00000CCL) +#endif + +#ifndef STATUS_TOO_MANY_NAMES +# define STATUS_TOO_MANY_NAMES ((NTSTATUS) 0xC00000CDL) +#endif + +#ifndef STATUS_TOO_MANY_SESSIONS +# define STATUS_TOO_MANY_SESSIONS ((NTSTATUS) 0xC00000CEL) +#endif + +#ifndef STATUS_SHARING_PAUSED +# define STATUS_SHARING_PAUSED ((NTSTATUS) 0xC00000CFL) +#endif + +#ifndef STATUS_REQUEST_NOT_ACCEPTED +# define STATUS_REQUEST_NOT_ACCEPTED ((NTSTATUS) 0xC00000D0L) +#endif + +#ifndef STATUS_REDIRECTOR_PAUSED +# define STATUS_REDIRECTOR_PAUSED ((NTSTATUS) 0xC00000D1L) +#endif + +#ifndef STATUS_NET_WRITE_FAULT +# define STATUS_NET_WRITE_FAULT ((NTSTATUS) 0xC00000D2L) +#endif + +#ifndef STATUS_PROFILING_AT_LIMIT +# define STATUS_PROFILING_AT_LIMIT ((NTSTATUS) 0xC00000D3L) +#endif + +#ifndef STATUS_NOT_SAME_DEVICE +# define STATUS_NOT_SAME_DEVICE ((NTSTATUS) 0xC00000D4L) +#endif + +#ifndef STATUS_FILE_RENAMED +# define STATUS_FILE_RENAMED ((NTSTATUS) 0xC00000D5L) +#endif + +#ifndef STATUS_VIRTUAL_CIRCUIT_CLOSED +# define STATUS_VIRTUAL_CIRCUIT_CLOSED ((NTSTATUS) 0xC00000D6L) +#endif + +#ifndef STATUS_NO_SECURITY_ON_OBJECT +# define STATUS_NO_SECURITY_ON_OBJECT ((NTSTATUS) 0xC00000D7L) +#endif + +#ifndef STATUS_CANT_WAIT +# define STATUS_CANT_WAIT ((NTSTATUS) 0xC00000D8L) +#endif + +#ifndef STATUS_PIPE_EMPTY +# define STATUS_PIPE_EMPTY ((NTSTATUS) 0xC00000D9L) +#endif + +#ifndef STATUS_CANT_ACCESS_DOMAIN_INFO +# define STATUS_CANT_ACCESS_DOMAIN_INFO ((NTSTATUS) 0xC00000DAL) +#endif + +#ifndef STATUS_CANT_TERMINATE_SELF +# define STATUS_CANT_TERMINATE_SELF ((NTSTATUS) 0xC00000DBL) +#endif + +#ifndef STATUS_INVALID_SERVER_STATE +# define STATUS_INVALID_SERVER_STATE ((NTSTATUS) 0xC00000DCL) +#endif + +#ifndef STATUS_INVALID_DOMAIN_STATE +# define STATUS_INVALID_DOMAIN_STATE ((NTSTATUS) 0xC00000DDL) +#endif + +#ifndef STATUS_INVALID_DOMAIN_ROLE +# define STATUS_INVALID_DOMAIN_ROLE ((NTSTATUS) 0xC00000DEL) +#endif + +#ifndef STATUS_NO_SUCH_DOMAIN +# define STATUS_NO_SUCH_DOMAIN ((NTSTATUS) 0xC00000DFL) +#endif + +#ifndef STATUS_DOMAIN_EXISTS +# define STATUS_DOMAIN_EXISTS ((NTSTATUS) 0xC00000E0L) +#endif + +#ifndef STATUS_DOMAIN_LIMIT_EXCEEDED +# define STATUS_DOMAIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00000E1L) +#endif + +#ifndef STATUS_OPLOCK_NOT_GRANTED +# define STATUS_OPLOCK_NOT_GRANTED ((NTSTATUS) 0xC00000E2L) +#endif + +#ifndef STATUS_INVALID_OPLOCK_PROTOCOL +# define STATUS_INVALID_OPLOCK_PROTOCOL ((NTSTATUS) 0xC00000E3L) +#endif + +#ifndef STATUS_INTERNAL_DB_CORRUPTION +# define STATUS_INTERNAL_DB_CORRUPTION ((NTSTATUS) 0xC00000E4L) +#endif + +#ifndef STATUS_INTERNAL_ERROR +# define STATUS_INTERNAL_ERROR ((NTSTATUS) 0xC00000E5L) +#endif + +#ifndef STATUS_GENERIC_NOT_MAPPED +# define STATUS_GENERIC_NOT_MAPPED ((NTSTATUS) 0xC00000E6L) +#endif + +#ifndef STATUS_BAD_DESCRIPTOR_FORMAT +# define STATUS_BAD_DESCRIPTOR_FORMAT ((NTSTATUS) 0xC00000E7L) +#endif + +#ifndef STATUS_INVALID_USER_BUFFER +# define STATUS_INVALID_USER_BUFFER ((NTSTATUS) 0xC00000E8L) +#endif + +#ifndef STATUS_UNEXPECTED_IO_ERROR +# define STATUS_UNEXPECTED_IO_ERROR ((NTSTATUS) 0xC00000E9L) +#endif + +#ifndef STATUS_UNEXPECTED_MM_CREATE_ERR +# define STATUS_UNEXPECTED_MM_CREATE_ERR ((NTSTATUS) 0xC00000EAL) +#endif + +#ifndef STATUS_UNEXPECTED_MM_MAP_ERROR +# define STATUS_UNEXPECTED_MM_MAP_ERROR ((NTSTATUS) 0xC00000EBL) +#endif + +#ifndef STATUS_UNEXPECTED_MM_EXTEND_ERR +# define STATUS_UNEXPECTED_MM_EXTEND_ERR ((NTSTATUS) 0xC00000ECL) +#endif + +#ifndef STATUS_NOT_LOGON_PROCESS +# define STATUS_NOT_LOGON_PROCESS ((NTSTATUS) 0xC00000EDL) +#endif + +#ifndef STATUS_LOGON_SESSION_EXISTS +# define STATUS_LOGON_SESSION_EXISTS ((NTSTATUS) 0xC00000EEL) +#endif + +#ifndef STATUS_INVALID_PARAMETER_1 +# define STATUS_INVALID_PARAMETER_1 ((NTSTATUS) 0xC00000EFL) +#endif + +#ifndef STATUS_INVALID_PARAMETER_2 +# define STATUS_INVALID_PARAMETER_2 ((NTSTATUS) 0xC00000F0L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_3 +# define STATUS_INVALID_PARAMETER_3 ((NTSTATUS) 0xC00000F1L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_4 +# define STATUS_INVALID_PARAMETER_4 ((NTSTATUS) 0xC00000F2L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_5 +# define STATUS_INVALID_PARAMETER_5 ((NTSTATUS) 0xC00000F3L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_6 +# define STATUS_INVALID_PARAMETER_6 ((NTSTATUS) 0xC00000F4L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_7 +# define STATUS_INVALID_PARAMETER_7 ((NTSTATUS) 0xC00000F5L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_8 +# define STATUS_INVALID_PARAMETER_8 ((NTSTATUS) 0xC00000F6L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_9 +# define STATUS_INVALID_PARAMETER_9 ((NTSTATUS) 0xC00000F7L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_10 +# define STATUS_INVALID_PARAMETER_10 ((NTSTATUS) 0xC00000F8L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_11 +# define STATUS_INVALID_PARAMETER_11 ((NTSTATUS) 0xC00000F9L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_12 +# define STATUS_INVALID_PARAMETER_12 ((NTSTATUS) 0xC00000FAL) +#endif + +#ifndef STATUS_REDIRECTOR_NOT_STARTED +# define STATUS_REDIRECTOR_NOT_STARTED ((NTSTATUS) 0xC00000FBL) +#endif + +#ifndef STATUS_REDIRECTOR_STARTED +# define STATUS_REDIRECTOR_STARTED ((NTSTATUS) 0xC00000FCL) +#endif + +#ifndef STATUS_STACK_OVERFLOW +# define STATUS_STACK_OVERFLOW ((NTSTATUS) 0xC00000FDL) +#endif + +#ifndef STATUS_NO_SUCH_PACKAGE +# define STATUS_NO_SUCH_PACKAGE ((NTSTATUS) 0xC00000FEL) +#endif + +#ifndef STATUS_BAD_FUNCTION_TABLE +# define STATUS_BAD_FUNCTION_TABLE ((NTSTATUS) 0xC00000FFL) +#endif + +#ifndef STATUS_VARIABLE_NOT_FOUND +# define STATUS_VARIABLE_NOT_FOUND ((NTSTATUS) 0xC0000100L) +#endif + +#ifndef STATUS_DIRECTORY_NOT_EMPTY +# define STATUS_DIRECTORY_NOT_EMPTY ((NTSTATUS) 0xC0000101L) +#endif + +#ifndef STATUS_FILE_CORRUPT_ERROR +# define STATUS_FILE_CORRUPT_ERROR ((NTSTATUS) 0xC0000102L) +#endif + +#ifndef STATUS_NOT_A_DIRECTORY +# define STATUS_NOT_A_DIRECTORY ((NTSTATUS) 0xC0000103L) +#endif + +#ifndef STATUS_BAD_LOGON_SESSION_STATE +# define STATUS_BAD_LOGON_SESSION_STATE ((NTSTATUS) 0xC0000104L) +#endif + +#ifndef STATUS_LOGON_SESSION_COLLISION +# define STATUS_LOGON_SESSION_COLLISION ((NTSTATUS) 0xC0000105L) +#endif + +#ifndef STATUS_NAME_TOO_LONG +# define STATUS_NAME_TOO_LONG ((NTSTATUS) 0xC0000106L) +#endif + +#ifndef STATUS_FILES_OPEN +# define STATUS_FILES_OPEN ((NTSTATUS) 0xC0000107L) +#endif + +#ifndef STATUS_CONNECTION_IN_USE +# define STATUS_CONNECTION_IN_USE ((NTSTATUS) 0xC0000108L) +#endif + +#ifndef STATUS_MESSAGE_NOT_FOUND +# define STATUS_MESSAGE_NOT_FOUND ((NTSTATUS) 0xC0000109L) +#endif + +#ifndef STATUS_PROCESS_IS_TERMINATING +# define STATUS_PROCESS_IS_TERMINATING ((NTSTATUS) 0xC000010AL) +#endif + +#ifndef STATUS_INVALID_LOGON_TYPE +# define STATUS_INVALID_LOGON_TYPE ((NTSTATUS) 0xC000010BL) +#endif + +#ifndef STATUS_NO_GUID_TRANSLATION +# define STATUS_NO_GUID_TRANSLATION ((NTSTATUS) 0xC000010CL) +#endif + +#ifndef STATUS_CANNOT_IMPERSONATE +# define STATUS_CANNOT_IMPERSONATE ((NTSTATUS) 0xC000010DL) +#endif + +#ifndef STATUS_IMAGE_ALREADY_LOADED +# define STATUS_IMAGE_ALREADY_LOADED ((NTSTATUS) 0xC000010EL) +#endif + +#ifndef STATUS_ABIOS_NOT_PRESENT +# define STATUS_ABIOS_NOT_PRESENT ((NTSTATUS) 0xC000010FL) +#endif + +#ifndef STATUS_ABIOS_LID_NOT_EXIST +# define STATUS_ABIOS_LID_NOT_EXIST ((NTSTATUS) 0xC0000110L) +#endif + +#ifndef STATUS_ABIOS_LID_ALREADY_OWNED +# define STATUS_ABIOS_LID_ALREADY_OWNED ((NTSTATUS) 0xC0000111L) +#endif + +#ifndef STATUS_ABIOS_NOT_LID_OWNER +# define STATUS_ABIOS_NOT_LID_OWNER ((NTSTATUS) 0xC0000112L) +#endif + +#ifndef STATUS_ABIOS_INVALID_COMMAND +# define STATUS_ABIOS_INVALID_COMMAND ((NTSTATUS) 0xC0000113L) +#endif + +#ifndef STATUS_ABIOS_INVALID_LID +# define STATUS_ABIOS_INVALID_LID ((NTSTATUS) 0xC0000114L) +#endif + +#ifndef STATUS_ABIOS_SELECTOR_NOT_AVAILABLE +# define STATUS_ABIOS_SELECTOR_NOT_AVAILABLE ((NTSTATUS) 0xC0000115L) +#endif + +#ifndef STATUS_ABIOS_INVALID_SELECTOR +# define STATUS_ABIOS_INVALID_SELECTOR ((NTSTATUS) 0xC0000116L) +#endif + +#ifndef STATUS_NO_LDT +# define STATUS_NO_LDT ((NTSTATUS) 0xC0000117L) +#endif + +#ifndef STATUS_INVALID_LDT_SIZE +# define STATUS_INVALID_LDT_SIZE ((NTSTATUS) 0xC0000118L) +#endif + +#ifndef STATUS_INVALID_LDT_OFFSET +# define STATUS_INVALID_LDT_OFFSET ((NTSTATUS) 0xC0000119L) +#endif + +#ifndef STATUS_INVALID_LDT_DESCRIPTOR +# define STATUS_INVALID_LDT_DESCRIPTOR ((NTSTATUS) 0xC000011AL) +#endif + +#ifndef STATUS_INVALID_IMAGE_NE_FORMAT +# define STATUS_INVALID_IMAGE_NE_FORMAT ((NTSTATUS) 0xC000011BL) +#endif + +#ifndef STATUS_RXACT_INVALID_STATE +# define STATUS_RXACT_INVALID_STATE ((NTSTATUS) 0xC000011CL) +#endif + +#ifndef STATUS_RXACT_COMMIT_FAILURE +# define STATUS_RXACT_COMMIT_FAILURE ((NTSTATUS) 0xC000011DL) +#endif + +#ifndef STATUS_MAPPED_FILE_SIZE_ZERO +# define STATUS_MAPPED_FILE_SIZE_ZERO ((NTSTATUS) 0xC000011EL) +#endif + +#ifndef STATUS_TOO_MANY_OPENED_FILES +# define STATUS_TOO_MANY_OPENED_FILES ((NTSTATUS) 0xC000011FL) +#endif + +#ifndef STATUS_CANCELLED +# define STATUS_CANCELLED ((NTSTATUS) 0xC0000120L) +#endif + +#ifndef STATUS_CANNOT_DELETE +# define STATUS_CANNOT_DELETE ((NTSTATUS) 0xC0000121L) +#endif + +#ifndef STATUS_INVALID_COMPUTER_NAME +# define STATUS_INVALID_COMPUTER_NAME ((NTSTATUS) 0xC0000122L) +#endif + +#ifndef STATUS_FILE_DELETED +# define STATUS_FILE_DELETED ((NTSTATUS) 0xC0000123L) +#endif + +#ifndef STATUS_SPECIAL_ACCOUNT +# define STATUS_SPECIAL_ACCOUNT ((NTSTATUS) 0xC0000124L) +#endif + +#ifndef STATUS_SPECIAL_GROUP +# define STATUS_SPECIAL_GROUP ((NTSTATUS) 0xC0000125L) +#endif + +#ifndef STATUS_SPECIAL_USER +# define STATUS_SPECIAL_USER ((NTSTATUS) 0xC0000126L) +#endif + +#ifndef STATUS_MEMBERS_PRIMARY_GROUP +# define STATUS_MEMBERS_PRIMARY_GROUP ((NTSTATUS) 0xC0000127L) +#endif + +#ifndef STATUS_FILE_CLOSED +# define STATUS_FILE_CLOSED ((NTSTATUS) 0xC0000128L) +#endif + +#ifndef STATUS_TOO_MANY_THREADS +# define STATUS_TOO_MANY_THREADS ((NTSTATUS) 0xC0000129L) +#endif + +#ifndef STATUS_THREAD_NOT_IN_PROCESS +# define STATUS_THREAD_NOT_IN_PROCESS ((NTSTATUS) 0xC000012AL) +#endif + +#ifndef STATUS_TOKEN_ALREADY_IN_USE +# define STATUS_TOKEN_ALREADY_IN_USE ((NTSTATUS) 0xC000012BL) +#endif + +#ifndef STATUS_PAGEFILE_QUOTA_EXCEEDED +# define STATUS_PAGEFILE_QUOTA_EXCEEDED ((NTSTATUS) 0xC000012CL) +#endif + +#ifndef STATUS_COMMITMENT_LIMIT +# define STATUS_COMMITMENT_LIMIT ((NTSTATUS) 0xC000012DL) +#endif + +#ifndef STATUS_INVALID_IMAGE_LE_FORMAT +# define STATUS_INVALID_IMAGE_LE_FORMAT ((NTSTATUS) 0xC000012EL) +#endif + +#ifndef STATUS_INVALID_IMAGE_NOT_MZ +# define STATUS_INVALID_IMAGE_NOT_MZ ((NTSTATUS) 0xC000012FL) +#endif + +#ifndef STATUS_INVALID_IMAGE_PROTECT +# define STATUS_INVALID_IMAGE_PROTECT ((NTSTATUS) 0xC0000130L) +#endif + +#ifndef STATUS_INVALID_IMAGE_WIN_16 +# define STATUS_INVALID_IMAGE_WIN_16 ((NTSTATUS) 0xC0000131L) +#endif + +#ifndef STATUS_LOGON_SERVER_CONFLICT +# define STATUS_LOGON_SERVER_CONFLICT ((NTSTATUS) 0xC0000132L) +#endif + +#ifndef STATUS_TIME_DIFFERENCE_AT_DC +# define STATUS_TIME_DIFFERENCE_AT_DC ((NTSTATUS) 0xC0000133L) +#endif + +#ifndef STATUS_SYNCHRONIZATION_REQUIRED +# define STATUS_SYNCHRONIZATION_REQUIRED ((NTSTATUS) 0xC0000134L) +#endif + +#ifndef STATUS_DLL_NOT_FOUND +# define STATUS_DLL_NOT_FOUND ((NTSTATUS) 0xC0000135L) +#endif + +#ifndef STATUS_OPEN_FAILED +# define STATUS_OPEN_FAILED ((NTSTATUS) 0xC0000136L) +#endif + +#ifndef STATUS_IO_PRIVILEGE_FAILED +# define STATUS_IO_PRIVILEGE_FAILED ((NTSTATUS) 0xC0000137L) +#endif + +#ifndef STATUS_ORDINAL_NOT_FOUND +# define STATUS_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000138L) +#endif + +#ifndef STATUS_ENTRYPOINT_NOT_FOUND +# define STATUS_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000139L) +#endif + +#ifndef STATUS_CONTROL_C_EXIT +# define STATUS_CONTROL_C_EXIT ((NTSTATUS) 0xC000013AL) +#endif + +#ifndef STATUS_LOCAL_DISCONNECT +# define STATUS_LOCAL_DISCONNECT ((NTSTATUS) 0xC000013BL) +#endif + +#ifndef STATUS_REMOTE_DISCONNECT +# define STATUS_REMOTE_DISCONNECT ((NTSTATUS) 0xC000013CL) +#endif + +#ifndef STATUS_REMOTE_RESOURCES +# define STATUS_REMOTE_RESOURCES ((NTSTATUS) 0xC000013DL) +#endif + +#ifndef STATUS_LINK_FAILED +# define STATUS_LINK_FAILED ((NTSTATUS) 0xC000013EL) +#endif + +#ifndef STATUS_LINK_TIMEOUT +# define STATUS_LINK_TIMEOUT ((NTSTATUS) 0xC000013FL) +#endif + +#ifndef STATUS_INVALID_CONNECTION +# define STATUS_INVALID_CONNECTION ((NTSTATUS) 0xC0000140L) +#endif + +#ifndef STATUS_INVALID_ADDRESS +# define STATUS_INVALID_ADDRESS ((NTSTATUS) 0xC0000141L) +#endif + +#ifndef STATUS_DLL_INIT_FAILED +# define STATUS_DLL_INIT_FAILED ((NTSTATUS) 0xC0000142L) +#endif + +#ifndef STATUS_MISSING_SYSTEMFILE +# define STATUS_MISSING_SYSTEMFILE ((NTSTATUS) 0xC0000143L) +#endif + +#ifndef STATUS_UNHANDLED_EXCEPTION +# define STATUS_UNHANDLED_EXCEPTION ((NTSTATUS) 0xC0000144L) +#endif + +#ifndef STATUS_APP_INIT_FAILURE +# define STATUS_APP_INIT_FAILURE ((NTSTATUS) 0xC0000145L) +#endif + +#ifndef STATUS_PAGEFILE_CREATE_FAILED +# define STATUS_PAGEFILE_CREATE_FAILED ((NTSTATUS) 0xC0000146L) +#endif + +#ifndef STATUS_NO_PAGEFILE +# define STATUS_NO_PAGEFILE ((NTSTATUS) 0xC0000147L) +#endif + +#ifndef STATUS_INVALID_LEVEL +# define STATUS_INVALID_LEVEL ((NTSTATUS) 0xC0000148L) +#endif + +#ifndef STATUS_WRONG_PASSWORD_CORE +# define STATUS_WRONG_PASSWORD_CORE ((NTSTATUS) 0xC0000149L) +#endif + +#ifndef STATUS_ILLEGAL_FLOAT_CONTEXT +# define STATUS_ILLEGAL_FLOAT_CONTEXT ((NTSTATUS) 0xC000014AL) +#endif + +#ifndef STATUS_PIPE_BROKEN +# define STATUS_PIPE_BROKEN ((NTSTATUS) 0xC000014BL) +#endif + +#ifndef STATUS_REGISTRY_CORRUPT +# define STATUS_REGISTRY_CORRUPT ((NTSTATUS) 0xC000014CL) +#endif + +#ifndef STATUS_REGISTRY_IO_FAILED +# define STATUS_REGISTRY_IO_FAILED ((NTSTATUS) 0xC000014DL) +#endif + +#ifndef STATUS_NO_EVENT_PAIR +# define STATUS_NO_EVENT_PAIR ((NTSTATUS) 0xC000014EL) +#endif + +#ifndef STATUS_UNRECOGNIZED_VOLUME +# define STATUS_UNRECOGNIZED_VOLUME ((NTSTATUS) 0xC000014FL) +#endif + +#ifndef STATUS_SERIAL_NO_DEVICE_INITED +# define STATUS_SERIAL_NO_DEVICE_INITED ((NTSTATUS) 0xC0000150L) +#endif + +#ifndef STATUS_NO_SUCH_ALIAS +# define STATUS_NO_SUCH_ALIAS ((NTSTATUS) 0xC0000151L) +#endif + +#ifndef STATUS_MEMBER_NOT_IN_ALIAS +# define STATUS_MEMBER_NOT_IN_ALIAS ((NTSTATUS) 0xC0000152L) +#endif + +#ifndef STATUS_MEMBER_IN_ALIAS +# define STATUS_MEMBER_IN_ALIAS ((NTSTATUS) 0xC0000153L) +#endif + +#ifndef STATUS_ALIAS_EXISTS +# define STATUS_ALIAS_EXISTS ((NTSTATUS) 0xC0000154L) +#endif + +#ifndef STATUS_LOGON_NOT_GRANTED +# define STATUS_LOGON_NOT_GRANTED ((NTSTATUS) 0xC0000155L) +#endif + +#ifndef STATUS_TOO_MANY_SECRETS +# define STATUS_TOO_MANY_SECRETS ((NTSTATUS) 0xC0000156L) +#endif + +#ifndef STATUS_SECRET_TOO_LONG +# define STATUS_SECRET_TOO_LONG ((NTSTATUS) 0xC0000157L) +#endif + +#ifndef STATUS_INTERNAL_DB_ERROR +# define STATUS_INTERNAL_DB_ERROR ((NTSTATUS) 0xC0000158L) +#endif + +#ifndef STATUS_FULLSCREEN_MODE +# define STATUS_FULLSCREEN_MODE ((NTSTATUS) 0xC0000159L) +#endif + +#ifndef STATUS_TOO_MANY_CONTEXT_IDS +# define STATUS_TOO_MANY_CONTEXT_IDS ((NTSTATUS) 0xC000015AL) +#endif + +#ifndef STATUS_LOGON_TYPE_NOT_GRANTED +# define STATUS_LOGON_TYPE_NOT_GRANTED ((NTSTATUS) 0xC000015BL) +#endif + +#ifndef STATUS_NOT_REGISTRY_FILE +# define STATUS_NOT_REGISTRY_FILE ((NTSTATUS) 0xC000015CL) +#endif + +#ifndef STATUS_NT_CROSS_ENCRYPTION_REQUIRED +# define STATUS_NT_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000015DL) +#endif + +#ifndef STATUS_DOMAIN_CTRLR_CONFIG_ERROR +# define STATUS_DOMAIN_CTRLR_CONFIG_ERROR ((NTSTATUS) 0xC000015EL) +#endif + +#ifndef STATUS_FT_MISSING_MEMBER +# define STATUS_FT_MISSING_MEMBER ((NTSTATUS) 0xC000015FL) +#endif + +#ifndef STATUS_ILL_FORMED_SERVICE_ENTRY +# define STATUS_ILL_FORMED_SERVICE_ENTRY ((NTSTATUS) 0xC0000160L) +#endif + +#ifndef STATUS_ILLEGAL_CHARACTER +# define STATUS_ILLEGAL_CHARACTER ((NTSTATUS) 0xC0000161L) +#endif + +#ifndef STATUS_UNMAPPABLE_CHARACTER +# define STATUS_UNMAPPABLE_CHARACTER ((NTSTATUS) 0xC0000162L) +#endif + +#ifndef STATUS_UNDEFINED_CHARACTER +# define STATUS_UNDEFINED_CHARACTER ((NTSTATUS) 0xC0000163L) +#endif + +#ifndef STATUS_FLOPPY_VOLUME +# define STATUS_FLOPPY_VOLUME ((NTSTATUS) 0xC0000164L) +#endif + +#ifndef STATUS_FLOPPY_ID_MARK_NOT_FOUND +# define STATUS_FLOPPY_ID_MARK_NOT_FOUND ((NTSTATUS) 0xC0000165L) +#endif + +#ifndef STATUS_FLOPPY_WRONG_CYLINDER +# define STATUS_FLOPPY_WRONG_CYLINDER ((NTSTATUS) 0xC0000166L) +#endif + +#ifndef STATUS_FLOPPY_UNKNOWN_ERROR +# define STATUS_FLOPPY_UNKNOWN_ERROR ((NTSTATUS) 0xC0000167L) +#endif + +#ifndef STATUS_FLOPPY_BAD_REGISTERS +# define STATUS_FLOPPY_BAD_REGISTERS ((NTSTATUS) 0xC0000168L) +#endif + +#ifndef STATUS_DISK_RECALIBRATE_FAILED +# define STATUS_DISK_RECALIBRATE_FAILED ((NTSTATUS) 0xC0000169L) +#endif + +#ifndef STATUS_DISK_OPERATION_FAILED +# define STATUS_DISK_OPERATION_FAILED ((NTSTATUS) 0xC000016AL) +#endif + +#ifndef STATUS_DISK_RESET_FAILED +# define STATUS_DISK_RESET_FAILED ((NTSTATUS) 0xC000016BL) +#endif + +#ifndef STATUS_SHARED_IRQ_BUSY +# define STATUS_SHARED_IRQ_BUSY ((NTSTATUS) 0xC000016CL) +#endif + +#ifndef STATUS_FT_ORPHANING +# define STATUS_FT_ORPHANING ((NTSTATUS) 0xC000016DL) +#endif + +#ifndef STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT +# define STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT ((NTSTATUS) 0xC000016EL) +#endif + +#ifndef STATUS_PARTITION_FAILURE +# define STATUS_PARTITION_FAILURE ((NTSTATUS) 0xC0000172L) +#endif + +#ifndef STATUS_INVALID_BLOCK_LENGTH +# define STATUS_INVALID_BLOCK_LENGTH ((NTSTATUS) 0xC0000173L) +#endif + +#ifndef STATUS_DEVICE_NOT_PARTITIONED +# define STATUS_DEVICE_NOT_PARTITIONED ((NTSTATUS) 0xC0000174L) +#endif + +#ifndef STATUS_UNABLE_TO_LOCK_MEDIA +# define STATUS_UNABLE_TO_LOCK_MEDIA ((NTSTATUS) 0xC0000175L) +#endif + +#ifndef STATUS_UNABLE_TO_UNLOAD_MEDIA +# define STATUS_UNABLE_TO_UNLOAD_MEDIA ((NTSTATUS) 0xC0000176L) +#endif + +#ifndef STATUS_EOM_OVERFLOW +# define STATUS_EOM_OVERFLOW ((NTSTATUS) 0xC0000177L) +#endif + +#ifndef STATUS_NO_MEDIA +# define STATUS_NO_MEDIA ((NTSTATUS) 0xC0000178L) +#endif + +#ifndef STATUS_NO_SUCH_MEMBER +# define STATUS_NO_SUCH_MEMBER ((NTSTATUS) 0xC000017AL) +#endif + +#ifndef STATUS_INVALID_MEMBER +# define STATUS_INVALID_MEMBER ((NTSTATUS) 0xC000017BL) +#endif + +#ifndef STATUS_KEY_DELETED +# define STATUS_KEY_DELETED ((NTSTATUS) 0xC000017CL) +#endif + +#ifndef STATUS_NO_LOG_SPACE +# define STATUS_NO_LOG_SPACE ((NTSTATUS) 0xC000017DL) +#endif + +#ifndef STATUS_TOO_MANY_SIDS +# define STATUS_TOO_MANY_SIDS ((NTSTATUS) 0xC000017EL) +#endif + +#ifndef STATUS_LM_CROSS_ENCRYPTION_REQUIRED +# define STATUS_LM_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000017FL) +#endif + +#ifndef STATUS_KEY_HAS_CHILDREN +# define STATUS_KEY_HAS_CHILDREN ((NTSTATUS) 0xC0000180L) +#endif + +#ifndef STATUS_CHILD_MUST_BE_VOLATILE +# define STATUS_CHILD_MUST_BE_VOLATILE ((NTSTATUS) 0xC0000181L) +#endif + +#ifndef STATUS_DEVICE_CONFIGURATION_ERROR +# define STATUS_DEVICE_CONFIGURATION_ERROR ((NTSTATUS) 0xC0000182L) +#endif + +#ifndef STATUS_DRIVER_INTERNAL_ERROR +# define STATUS_DRIVER_INTERNAL_ERROR ((NTSTATUS) 0xC0000183L) +#endif + +#ifndef STATUS_INVALID_DEVICE_STATE +# define STATUS_INVALID_DEVICE_STATE ((NTSTATUS) 0xC0000184L) +#endif + +#ifndef STATUS_IO_DEVICE_ERROR +# define STATUS_IO_DEVICE_ERROR ((NTSTATUS) 0xC0000185L) +#endif + +#ifndef STATUS_DEVICE_PROTOCOL_ERROR +# define STATUS_DEVICE_PROTOCOL_ERROR ((NTSTATUS) 0xC0000186L) +#endif + +#ifndef STATUS_BACKUP_CONTROLLER +# define STATUS_BACKUP_CONTROLLER ((NTSTATUS) 0xC0000187L) +#endif + +#ifndef STATUS_LOG_FILE_FULL +# define STATUS_LOG_FILE_FULL ((NTSTATUS) 0xC0000188L) +#endif + +#ifndef STATUS_TOO_LATE +# define STATUS_TOO_LATE ((NTSTATUS) 0xC0000189L) +#endif + +#ifndef STATUS_NO_TRUST_LSA_SECRET +# define STATUS_NO_TRUST_LSA_SECRET ((NTSTATUS) 0xC000018AL) +#endif + +#ifndef STATUS_NO_TRUST_SAM_ACCOUNT +# define STATUS_NO_TRUST_SAM_ACCOUNT ((NTSTATUS) 0xC000018BL) +#endif + +#ifndef STATUS_TRUSTED_DOMAIN_FAILURE +# define STATUS_TRUSTED_DOMAIN_FAILURE ((NTSTATUS) 0xC000018CL) +#endif + +#ifndef STATUS_TRUSTED_RELATIONSHIP_FAILURE +# define STATUS_TRUSTED_RELATIONSHIP_FAILURE ((NTSTATUS) 0xC000018DL) +#endif + +#ifndef STATUS_EVENTLOG_FILE_CORRUPT +# define STATUS_EVENTLOG_FILE_CORRUPT ((NTSTATUS) 0xC000018EL) +#endif + +#ifndef STATUS_EVENTLOG_CANT_START +# define STATUS_EVENTLOG_CANT_START ((NTSTATUS) 0xC000018FL) +#endif + +#ifndef STATUS_TRUST_FAILURE +# define STATUS_TRUST_FAILURE ((NTSTATUS) 0xC0000190L) +#endif + +#ifndef STATUS_MUTANT_LIMIT_EXCEEDED +# define STATUS_MUTANT_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000191L) +#endif + +#ifndef STATUS_NETLOGON_NOT_STARTED +# define STATUS_NETLOGON_NOT_STARTED ((NTSTATUS) 0xC0000192L) +#endif + +#ifndef STATUS_ACCOUNT_EXPIRED +# define STATUS_ACCOUNT_EXPIRED ((NTSTATUS) 0xC0000193L) +#endif + +#ifndef STATUS_POSSIBLE_DEADLOCK +# define STATUS_POSSIBLE_DEADLOCK ((NTSTATUS) 0xC0000194L) +#endif + +#ifndef STATUS_NETWORK_CREDENTIAL_CONFLICT +# define STATUS_NETWORK_CREDENTIAL_CONFLICT ((NTSTATUS) 0xC0000195L) +#endif + +#ifndef STATUS_REMOTE_SESSION_LIMIT +# define STATUS_REMOTE_SESSION_LIMIT ((NTSTATUS) 0xC0000196L) +#endif + +#ifndef STATUS_EVENTLOG_FILE_CHANGED +# define STATUS_EVENTLOG_FILE_CHANGED ((NTSTATUS) 0xC0000197L) +#endif + +#ifndef STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT +# define STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT ((NTSTATUS) 0xC0000198L) +#endif + +#ifndef STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT +# define STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT ((NTSTATUS) 0xC0000199L) +#endif + +#ifndef STATUS_NOLOGON_SERVER_TRUST_ACCOUNT +# define STATUS_NOLOGON_SERVER_TRUST_ACCOUNT ((NTSTATUS) 0xC000019AL) +#endif + +#ifndef STATUS_DOMAIN_TRUST_INCONSISTENT +# define STATUS_DOMAIN_TRUST_INCONSISTENT ((NTSTATUS) 0xC000019BL) +#endif + +#ifndef STATUS_FS_DRIVER_REQUIRED +# define STATUS_FS_DRIVER_REQUIRED ((NTSTATUS) 0xC000019CL) +#endif + +#ifndef STATUS_IMAGE_ALREADY_LOADED_AS_DLL +# define STATUS_IMAGE_ALREADY_LOADED_AS_DLL ((NTSTATUS) 0xC000019DL) +#endif + +#ifndef STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING +# define STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING ((NTSTATUS) 0xC000019EL) +#endif + +#ifndef STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME +# define STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME ((NTSTATUS) 0xC000019FL) +#endif + +#ifndef STATUS_SECURITY_STREAM_IS_INCONSISTENT +# define STATUS_SECURITY_STREAM_IS_INCONSISTENT ((NTSTATUS) 0xC00001A0L) +#endif + +#ifndef STATUS_INVALID_LOCK_RANGE +# define STATUS_INVALID_LOCK_RANGE ((NTSTATUS) 0xC00001A1L) +#endif + +#ifndef STATUS_INVALID_ACE_CONDITION +# define STATUS_INVALID_ACE_CONDITION ((NTSTATUS) 0xC00001A2L) +#endif + +#ifndef STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT +# define STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT ((NTSTATUS) 0xC00001A3L) +#endif + +#ifndef STATUS_NOTIFICATION_GUID_ALREADY_DEFINED +# define STATUS_NOTIFICATION_GUID_ALREADY_DEFINED ((NTSTATUS) 0xC00001A4L) +#endif + +#ifndef STATUS_NETWORK_OPEN_RESTRICTION +# define STATUS_NETWORK_OPEN_RESTRICTION ((NTSTATUS) 0xC0000201L) +#endif + +#ifndef STATUS_NO_USER_SESSION_KEY +# define STATUS_NO_USER_SESSION_KEY ((NTSTATUS) 0xC0000202L) +#endif + +#ifndef STATUS_USER_SESSION_DELETED +# define STATUS_USER_SESSION_DELETED ((NTSTATUS) 0xC0000203L) +#endif + +#ifndef STATUS_RESOURCE_LANG_NOT_FOUND +# define STATUS_RESOURCE_LANG_NOT_FOUND ((NTSTATUS) 0xC0000204L) +#endif + +#ifndef STATUS_INSUFF_SERVER_RESOURCES +# define STATUS_INSUFF_SERVER_RESOURCES ((NTSTATUS) 0xC0000205L) +#endif + +#ifndef STATUS_INVALID_BUFFER_SIZE +# define STATUS_INVALID_BUFFER_SIZE ((NTSTATUS) 0xC0000206L) +#endif + +#ifndef STATUS_INVALID_ADDRESS_COMPONENT +# define STATUS_INVALID_ADDRESS_COMPONENT ((NTSTATUS) 0xC0000207L) +#endif + +#ifndef STATUS_INVALID_ADDRESS_WILDCARD +# define STATUS_INVALID_ADDRESS_WILDCARD ((NTSTATUS) 0xC0000208L) +#endif + +#ifndef STATUS_TOO_MANY_ADDRESSES +# define STATUS_TOO_MANY_ADDRESSES ((NTSTATUS) 0xC0000209L) +#endif + +#ifndef STATUS_ADDRESS_ALREADY_EXISTS +# define STATUS_ADDRESS_ALREADY_EXISTS ((NTSTATUS) 0xC000020AL) +#endif + +#ifndef STATUS_ADDRESS_CLOSED +# define STATUS_ADDRESS_CLOSED ((NTSTATUS) 0xC000020BL) +#endif + +#ifndef STATUS_CONNECTION_DISCONNECTED +# define STATUS_CONNECTION_DISCONNECTED ((NTSTATUS) 0xC000020CL) +#endif + +#ifndef STATUS_CONNECTION_RESET +# define STATUS_CONNECTION_RESET ((NTSTATUS) 0xC000020DL) +#endif + +#ifndef STATUS_TOO_MANY_NODES +# define STATUS_TOO_MANY_NODES ((NTSTATUS) 0xC000020EL) +#endif + +#ifndef STATUS_TRANSACTION_ABORTED +# define STATUS_TRANSACTION_ABORTED ((NTSTATUS) 0xC000020FL) +#endif + +#ifndef STATUS_TRANSACTION_TIMED_OUT +# define STATUS_TRANSACTION_TIMED_OUT ((NTSTATUS) 0xC0000210L) +#endif + +#ifndef STATUS_TRANSACTION_NO_RELEASE +# define STATUS_TRANSACTION_NO_RELEASE ((NTSTATUS) 0xC0000211L) +#endif + +#ifndef STATUS_TRANSACTION_NO_MATCH +# define STATUS_TRANSACTION_NO_MATCH ((NTSTATUS) 0xC0000212L) +#endif + +#ifndef STATUS_TRANSACTION_RESPONDED +# define STATUS_TRANSACTION_RESPONDED ((NTSTATUS) 0xC0000213L) +#endif + +#ifndef STATUS_TRANSACTION_INVALID_ID +# define STATUS_TRANSACTION_INVALID_ID ((NTSTATUS) 0xC0000214L) +#endif + +#ifndef STATUS_TRANSACTION_INVALID_TYPE +# define STATUS_TRANSACTION_INVALID_TYPE ((NTSTATUS) 0xC0000215L) +#endif + +#ifndef STATUS_NOT_SERVER_SESSION +# define STATUS_NOT_SERVER_SESSION ((NTSTATUS) 0xC0000216L) +#endif + +#ifndef STATUS_NOT_CLIENT_SESSION +# define STATUS_NOT_CLIENT_SESSION ((NTSTATUS) 0xC0000217L) +#endif + +#ifndef STATUS_CANNOT_LOAD_REGISTRY_FILE +# define STATUS_CANNOT_LOAD_REGISTRY_FILE ((NTSTATUS) 0xC0000218L) +#endif + +#ifndef STATUS_DEBUG_ATTACH_FAILED +# define STATUS_DEBUG_ATTACH_FAILED ((NTSTATUS) 0xC0000219L) +#endif + +#ifndef STATUS_SYSTEM_PROCESS_TERMINATED +# define STATUS_SYSTEM_PROCESS_TERMINATED ((NTSTATUS) 0xC000021AL) +#endif + +#ifndef STATUS_DATA_NOT_ACCEPTED +# define STATUS_DATA_NOT_ACCEPTED ((NTSTATUS) 0xC000021BL) +#endif + +#ifndef STATUS_NO_BROWSER_SERVERS_FOUND +# define STATUS_NO_BROWSER_SERVERS_FOUND ((NTSTATUS) 0xC000021CL) +#endif + +#ifndef STATUS_VDM_HARD_ERROR +# define STATUS_VDM_HARD_ERROR ((NTSTATUS) 0xC000021DL) +#endif + +#ifndef STATUS_DRIVER_CANCEL_TIMEOUT +# define STATUS_DRIVER_CANCEL_TIMEOUT ((NTSTATUS) 0xC000021EL) +#endif + +#ifndef STATUS_REPLY_MESSAGE_MISMATCH +# define STATUS_REPLY_MESSAGE_MISMATCH ((NTSTATUS) 0xC000021FL) +#endif + +#ifndef STATUS_MAPPED_ALIGNMENT +# define STATUS_MAPPED_ALIGNMENT ((NTSTATUS) 0xC0000220L) +#endif + +#ifndef STATUS_IMAGE_CHECKSUM_MISMATCH +# define STATUS_IMAGE_CHECKSUM_MISMATCH ((NTSTATUS) 0xC0000221L) +#endif + +#ifndef STATUS_LOST_WRITEBEHIND_DATA +# define STATUS_LOST_WRITEBEHIND_DATA ((NTSTATUS) 0xC0000222L) +#endif + +#ifndef STATUS_CLIENT_SERVER_PARAMETERS_INVALID +# define STATUS_CLIENT_SERVER_PARAMETERS_INVALID ((NTSTATUS) 0xC0000223L) +#endif + +#ifndef STATUS_PASSWORD_MUST_CHANGE +# define STATUS_PASSWORD_MUST_CHANGE ((NTSTATUS) 0xC0000224L) +#endif + +#ifndef STATUS_NOT_FOUND +# define STATUS_NOT_FOUND ((NTSTATUS) 0xC0000225L) +#endif + +#ifndef STATUS_NOT_TINY_STREAM +# define STATUS_NOT_TINY_STREAM ((NTSTATUS) 0xC0000226L) +#endif + +#ifndef STATUS_RECOVERY_FAILURE +# define STATUS_RECOVERY_FAILURE ((NTSTATUS) 0xC0000227L) +#endif + +#ifndef STATUS_STACK_OVERFLOW_READ +# define STATUS_STACK_OVERFLOW_READ ((NTSTATUS) 0xC0000228L) +#endif + +#ifndef STATUS_FAIL_CHECK +# define STATUS_FAIL_CHECK ((NTSTATUS) 0xC0000229L) +#endif + +#ifndef STATUS_DUPLICATE_OBJECTID +# define STATUS_DUPLICATE_OBJECTID ((NTSTATUS) 0xC000022AL) +#endif + +#ifndef STATUS_OBJECTID_EXISTS +# define STATUS_OBJECTID_EXISTS ((NTSTATUS) 0xC000022BL) +#endif + +#ifndef STATUS_CONVERT_TO_LARGE +# define STATUS_CONVERT_TO_LARGE ((NTSTATUS) 0xC000022CL) +#endif + +#ifndef STATUS_RETRY +# define STATUS_RETRY ((NTSTATUS) 0xC000022DL) +#endif + +#ifndef STATUS_FOUND_OUT_OF_SCOPE +# define STATUS_FOUND_OUT_OF_SCOPE ((NTSTATUS) 0xC000022EL) +#endif + +#ifndef STATUS_ALLOCATE_BUCKET +# define STATUS_ALLOCATE_BUCKET ((NTSTATUS) 0xC000022FL) +#endif + +#ifndef STATUS_PROPSET_NOT_FOUND +# define STATUS_PROPSET_NOT_FOUND ((NTSTATUS) 0xC0000230L) +#endif + +#ifndef STATUS_MARSHALL_OVERFLOW +# define STATUS_MARSHALL_OVERFLOW ((NTSTATUS) 0xC0000231L) +#endif + +#ifndef STATUS_INVALID_VARIANT +# define STATUS_INVALID_VARIANT ((NTSTATUS) 0xC0000232L) +#endif + +#ifndef STATUS_DOMAIN_CONTROLLER_NOT_FOUND +# define STATUS_DOMAIN_CONTROLLER_NOT_FOUND ((NTSTATUS) 0xC0000233L) +#endif + +#ifndef STATUS_ACCOUNT_LOCKED_OUT +# define STATUS_ACCOUNT_LOCKED_OUT ((NTSTATUS) 0xC0000234L) +#endif + +#ifndef STATUS_HANDLE_NOT_CLOSABLE +# define STATUS_HANDLE_NOT_CLOSABLE ((NTSTATUS) 0xC0000235L) +#endif + +#ifndef STATUS_CONNECTION_REFUSED +# define STATUS_CONNECTION_REFUSED ((NTSTATUS) 0xC0000236L) +#endif + +#ifndef STATUS_GRACEFUL_DISCONNECT +# define STATUS_GRACEFUL_DISCONNECT ((NTSTATUS) 0xC0000237L) +#endif + +#ifndef STATUS_ADDRESS_ALREADY_ASSOCIATED +# define STATUS_ADDRESS_ALREADY_ASSOCIATED ((NTSTATUS) 0xC0000238L) +#endif + +#ifndef STATUS_ADDRESS_NOT_ASSOCIATED +# define STATUS_ADDRESS_NOT_ASSOCIATED ((NTSTATUS) 0xC0000239L) +#endif + +#ifndef STATUS_CONNECTION_INVALID +# define STATUS_CONNECTION_INVALID ((NTSTATUS) 0xC000023AL) +#endif + +#ifndef STATUS_CONNECTION_ACTIVE +# define STATUS_CONNECTION_ACTIVE ((NTSTATUS) 0xC000023BL) +#endif + +#ifndef STATUS_NETWORK_UNREACHABLE +# define STATUS_NETWORK_UNREACHABLE ((NTSTATUS) 0xC000023CL) +#endif + +#ifndef STATUS_HOST_UNREACHABLE +# define STATUS_HOST_UNREACHABLE ((NTSTATUS) 0xC000023DL) +#endif + +#ifndef STATUS_PROTOCOL_UNREACHABLE +# define STATUS_PROTOCOL_UNREACHABLE ((NTSTATUS) 0xC000023EL) +#endif + +#ifndef STATUS_PORT_UNREACHABLE +# define STATUS_PORT_UNREACHABLE ((NTSTATUS) 0xC000023FL) +#endif + +#ifndef STATUS_REQUEST_ABORTED +# define STATUS_REQUEST_ABORTED ((NTSTATUS) 0xC0000240L) +#endif + +#ifndef STATUS_CONNECTION_ABORTED +# define STATUS_CONNECTION_ABORTED ((NTSTATUS) 0xC0000241L) +#endif + +#ifndef STATUS_BAD_COMPRESSION_BUFFER +# define STATUS_BAD_COMPRESSION_BUFFER ((NTSTATUS) 0xC0000242L) +#endif + +#ifndef STATUS_USER_MAPPED_FILE +# define STATUS_USER_MAPPED_FILE ((NTSTATUS) 0xC0000243L) +#endif + +#ifndef STATUS_AUDIT_FAILED +# define STATUS_AUDIT_FAILED ((NTSTATUS) 0xC0000244L) +#endif + +#ifndef STATUS_TIMER_RESOLUTION_NOT_SET +# define STATUS_TIMER_RESOLUTION_NOT_SET ((NTSTATUS) 0xC0000245L) +#endif + +#ifndef STATUS_CONNECTION_COUNT_LIMIT +# define STATUS_CONNECTION_COUNT_LIMIT ((NTSTATUS) 0xC0000246L) +#endif + +#ifndef STATUS_LOGIN_TIME_RESTRICTION +# define STATUS_LOGIN_TIME_RESTRICTION ((NTSTATUS) 0xC0000247L) +#endif + +#ifndef STATUS_LOGIN_WKSTA_RESTRICTION +# define STATUS_LOGIN_WKSTA_RESTRICTION ((NTSTATUS) 0xC0000248L) +#endif + +#ifndef STATUS_IMAGE_MP_UP_MISMATCH +# define STATUS_IMAGE_MP_UP_MISMATCH ((NTSTATUS) 0xC0000249L) +#endif + +#ifndef STATUS_INSUFFICIENT_LOGON_INFO +# define STATUS_INSUFFICIENT_LOGON_INFO ((NTSTATUS) 0xC0000250L) +#endif + +#ifndef STATUS_BAD_DLL_ENTRYPOINT +# define STATUS_BAD_DLL_ENTRYPOINT ((NTSTATUS) 0xC0000251L) +#endif + +#ifndef STATUS_BAD_SERVICE_ENTRYPOINT +# define STATUS_BAD_SERVICE_ENTRYPOINT ((NTSTATUS) 0xC0000252L) +#endif + +#ifndef STATUS_LPC_REPLY_LOST +# define STATUS_LPC_REPLY_LOST ((NTSTATUS) 0xC0000253L) +#endif + +#ifndef STATUS_IP_ADDRESS_CONFLICT1 +# define STATUS_IP_ADDRESS_CONFLICT1 ((NTSTATUS) 0xC0000254L) +#endif + +#ifndef STATUS_IP_ADDRESS_CONFLICT2 +# define STATUS_IP_ADDRESS_CONFLICT2 ((NTSTATUS) 0xC0000255L) +#endif + +#ifndef STATUS_REGISTRY_QUOTA_LIMIT +# define STATUS_REGISTRY_QUOTA_LIMIT ((NTSTATUS) 0xC0000256L) +#endif + +#ifndef STATUS_PATH_NOT_COVERED +# define STATUS_PATH_NOT_COVERED ((NTSTATUS) 0xC0000257L) +#endif + +#ifndef STATUS_NO_CALLBACK_ACTIVE +# define STATUS_NO_CALLBACK_ACTIVE ((NTSTATUS) 0xC0000258L) +#endif + +#ifndef STATUS_LICENSE_QUOTA_EXCEEDED +# define STATUS_LICENSE_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000259L) +#endif + +#ifndef STATUS_PWD_TOO_SHORT +# define STATUS_PWD_TOO_SHORT ((NTSTATUS) 0xC000025AL) +#endif + +#ifndef STATUS_PWD_TOO_RECENT +# define STATUS_PWD_TOO_RECENT ((NTSTATUS) 0xC000025BL) +#endif + +#ifndef STATUS_PWD_HISTORY_CONFLICT +# define STATUS_PWD_HISTORY_CONFLICT ((NTSTATUS) 0xC000025CL) +#endif + +#ifndef STATUS_PLUGPLAY_NO_DEVICE +# define STATUS_PLUGPLAY_NO_DEVICE ((NTSTATUS) 0xC000025EL) +#endif + +#ifndef STATUS_UNSUPPORTED_COMPRESSION +# define STATUS_UNSUPPORTED_COMPRESSION ((NTSTATUS) 0xC000025FL) +#endif + +#ifndef STATUS_INVALID_HW_PROFILE +# define STATUS_INVALID_HW_PROFILE ((NTSTATUS) 0xC0000260L) +#endif + +#ifndef STATUS_INVALID_PLUGPLAY_DEVICE_PATH +# define STATUS_INVALID_PLUGPLAY_DEVICE_PATH ((NTSTATUS) 0xC0000261L) +#endif + +#ifndef STATUS_DRIVER_ORDINAL_NOT_FOUND +# define STATUS_DRIVER_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000262L) +#endif + +#ifndef STATUS_DRIVER_ENTRYPOINT_NOT_FOUND +# define STATUS_DRIVER_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000263L) +#endif + +#ifndef STATUS_RESOURCE_NOT_OWNED +# define STATUS_RESOURCE_NOT_OWNED ((NTSTATUS) 0xC0000264L) +#endif + +#ifndef STATUS_TOO_MANY_LINKS +# define STATUS_TOO_MANY_LINKS ((NTSTATUS) 0xC0000265L) +#endif + +#ifndef STATUS_QUOTA_LIST_INCONSISTENT +# define STATUS_QUOTA_LIST_INCONSISTENT ((NTSTATUS) 0xC0000266L) +#endif + +#ifndef STATUS_FILE_IS_OFFLINE +# define STATUS_FILE_IS_OFFLINE ((NTSTATUS) 0xC0000267L) +#endif + +#ifndef STATUS_EVALUATION_EXPIRATION +# define STATUS_EVALUATION_EXPIRATION ((NTSTATUS) 0xC0000268L) +#endif + +#ifndef STATUS_ILLEGAL_DLL_RELOCATION +# define STATUS_ILLEGAL_DLL_RELOCATION ((NTSTATUS) 0xC0000269L) +#endif + +#ifndef STATUS_LICENSE_VIOLATION +# define STATUS_LICENSE_VIOLATION ((NTSTATUS) 0xC000026AL) +#endif + +#ifndef STATUS_DLL_INIT_FAILED_LOGOFF +# define STATUS_DLL_INIT_FAILED_LOGOFF ((NTSTATUS) 0xC000026BL) +#endif + +#ifndef STATUS_DRIVER_UNABLE_TO_LOAD +# define STATUS_DRIVER_UNABLE_TO_LOAD ((NTSTATUS) 0xC000026CL) +#endif + +#ifndef STATUS_DFS_UNAVAILABLE +# define STATUS_DFS_UNAVAILABLE ((NTSTATUS) 0xC000026DL) +#endif + +#ifndef STATUS_VOLUME_DISMOUNTED +# define STATUS_VOLUME_DISMOUNTED ((NTSTATUS) 0xC000026EL) +#endif + +#ifndef STATUS_WX86_INTERNAL_ERROR +# define STATUS_WX86_INTERNAL_ERROR ((NTSTATUS) 0xC000026FL) +#endif + +#ifndef STATUS_WX86_FLOAT_STACK_CHECK +# define STATUS_WX86_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000270L) +#endif + +#ifndef STATUS_VALIDATE_CONTINUE +# define STATUS_VALIDATE_CONTINUE ((NTSTATUS) 0xC0000271L) +#endif + +#ifndef STATUS_NO_MATCH +# define STATUS_NO_MATCH ((NTSTATUS) 0xC0000272L) +#endif + +#ifndef STATUS_NO_MORE_MATCHES +# define STATUS_NO_MORE_MATCHES ((NTSTATUS) 0xC0000273L) +#endif + +#ifndef STATUS_NOT_A_REPARSE_POINT +# define STATUS_NOT_A_REPARSE_POINT ((NTSTATUS) 0xC0000275L) +#endif + +#ifndef STATUS_IO_REPARSE_TAG_INVALID +# define STATUS_IO_REPARSE_TAG_INVALID ((NTSTATUS) 0xC0000276L) +#endif + +#ifndef STATUS_IO_REPARSE_TAG_MISMATCH +# define STATUS_IO_REPARSE_TAG_MISMATCH ((NTSTATUS) 0xC0000277L) +#endif + +#ifndef STATUS_IO_REPARSE_DATA_INVALID +# define STATUS_IO_REPARSE_DATA_INVALID ((NTSTATUS) 0xC0000278L) +#endif + +#ifndef STATUS_IO_REPARSE_TAG_NOT_HANDLED +# define STATUS_IO_REPARSE_TAG_NOT_HANDLED ((NTSTATUS) 0xC0000279L) +#endif + +#ifndef STATUS_REPARSE_POINT_NOT_RESOLVED +# define STATUS_REPARSE_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000280L) +#endif + +#ifndef STATUS_DIRECTORY_IS_A_REPARSE_POINT +# define STATUS_DIRECTORY_IS_A_REPARSE_POINT ((NTSTATUS) 0xC0000281L) +#endif + +#ifndef STATUS_RANGE_LIST_CONFLICT +# define STATUS_RANGE_LIST_CONFLICT ((NTSTATUS) 0xC0000282L) +#endif + +#ifndef STATUS_SOURCE_ELEMENT_EMPTY +# define STATUS_SOURCE_ELEMENT_EMPTY ((NTSTATUS) 0xC0000283L) +#endif + +#ifndef STATUS_DESTINATION_ELEMENT_FULL +# define STATUS_DESTINATION_ELEMENT_FULL ((NTSTATUS) 0xC0000284L) +#endif + +#ifndef STATUS_ILLEGAL_ELEMENT_ADDRESS +# define STATUS_ILLEGAL_ELEMENT_ADDRESS ((NTSTATUS) 0xC0000285L) +#endif + +#ifndef STATUS_MAGAZINE_NOT_PRESENT +# define STATUS_MAGAZINE_NOT_PRESENT ((NTSTATUS) 0xC0000286L) +#endif + +#ifndef STATUS_REINITIALIZATION_NEEDED +# define STATUS_REINITIALIZATION_NEEDED ((NTSTATUS) 0xC0000287L) +#endif + +#ifndef STATUS_DEVICE_REQUIRES_CLEANING +# define STATUS_DEVICE_REQUIRES_CLEANING ((NTSTATUS) 0x80000288L) +#endif + +#ifndef STATUS_DEVICE_DOOR_OPEN +# define STATUS_DEVICE_DOOR_OPEN ((NTSTATUS) 0x80000289L) +#endif + +#ifndef STATUS_ENCRYPTION_FAILED +# define STATUS_ENCRYPTION_FAILED ((NTSTATUS) 0xC000028AL) +#endif + +#ifndef STATUS_DECRYPTION_FAILED +# define STATUS_DECRYPTION_FAILED ((NTSTATUS) 0xC000028BL) +#endif + +#ifndef STATUS_RANGE_NOT_FOUND +# define STATUS_RANGE_NOT_FOUND ((NTSTATUS) 0xC000028CL) +#endif + +#ifndef STATUS_NO_RECOVERY_POLICY +# define STATUS_NO_RECOVERY_POLICY ((NTSTATUS) 0xC000028DL) +#endif + +#ifndef STATUS_NO_EFS +# define STATUS_NO_EFS ((NTSTATUS) 0xC000028EL) +#endif + +#ifndef STATUS_WRONG_EFS +# define STATUS_WRONG_EFS ((NTSTATUS) 0xC000028FL) +#endif + +#ifndef STATUS_NO_USER_KEYS +# define STATUS_NO_USER_KEYS ((NTSTATUS) 0xC0000290L) +#endif + +#ifndef STATUS_FILE_NOT_ENCRYPTED +# define STATUS_FILE_NOT_ENCRYPTED ((NTSTATUS) 0xC0000291L) +#endif + +#ifndef STATUS_NOT_EXPORT_FORMAT +# define STATUS_NOT_EXPORT_FORMAT ((NTSTATUS) 0xC0000292L) +#endif + +#ifndef STATUS_FILE_ENCRYPTED +# define STATUS_FILE_ENCRYPTED ((NTSTATUS) 0xC0000293L) +#endif + +#ifndef STATUS_WAKE_SYSTEM +# define STATUS_WAKE_SYSTEM ((NTSTATUS) 0x40000294L) +#endif + +#ifndef STATUS_WMI_GUID_NOT_FOUND +# define STATUS_WMI_GUID_NOT_FOUND ((NTSTATUS) 0xC0000295L) +#endif + +#ifndef STATUS_WMI_INSTANCE_NOT_FOUND +# define STATUS_WMI_INSTANCE_NOT_FOUND ((NTSTATUS) 0xC0000296L) +#endif + +#ifndef STATUS_WMI_ITEMID_NOT_FOUND +# define STATUS_WMI_ITEMID_NOT_FOUND ((NTSTATUS) 0xC0000297L) +#endif + +#ifndef STATUS_WMI_TRY_AGAIN +# define STATUS_WMI_TRY_AGAIN ((NTSTATUS) 0xC0000298L) +#endif + +#ifndef STATUS_SHARED_POLICY +# define STATUS_SHARED_POLICY ((NTSTATUS) 0xC0000299L) +#endif + +#ifndef STATUS_POLICY_OBJECT_NOT_FOUND +# define STATUS_POLICY_OBJECT_NOT_FOUND ((NTSTATUS) 0xC000029AL) +#endif + +#ifndef STATUS_POLICY_ONLY_IN_DS +# define STATUS_POLICY_ONLY_IN_DS ((NTSTATUS) 0xC000029BL) +#endif + +#ifndef STATUS_VOLUME_NOT_UPGRADED +# define STATUS_VOLUME_NOT_UPGRADED ((NTSTATUS) 0xC000029CL) +#endif + +#ifndef STATUS_REMOTE_STORAGE_NOT_ACTIVE +# define STATUS_REMOTE_STORAGE_NOT_ACTIVE ((NTSTATUS) 0xC000029DL) +#endif + +#ifndef STATUS_REMOTE_STORAGE_MEDIA_ERROR +# define STATUS_REMOTE_STORAGE_MEDIA_ERROR ((NTSTATUS) 0xC000029EL) +#endif + +#ifndef STATUS_NO_TRACKING_SERVICE +# define STATUS_NO_TRACKING_SERVICE ((NTSTATUS) 0xC000029FL) +#endif + +#ifndef STATUS_SERVER_SID_MISMATCH +# define STATUS_SERVER_SID_MISMATCH ((NTSTATUS) 0xC00002A0L) +#endif + +#ifndef STATUS_DS_NO_ATTRIBUTE_OR_VALUE +# define STATUS_DS_NO_ATTRIBUTE_OR_VALUE ((NTSTATUS) 0xC00002A1L) +#endif + +#ifndef STATUS_DS_INVALID_ATTRIBUTE_SYNTAX +# define STATUS_DS_INVALID_ATTRIBUTE_SYNTAX ((NTSTATUS) 0xC00002A2L) +#endif + +#ifndef STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED +# define STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED ((NTSTATUS) 0xC00002A3L) +#endif + +#ifndef STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS +# define STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS ((NTSTATUS) 0xC00002A4L) +#endif + +#ifndef STATUS_DS_BUSY +# define STATUS_DS_BUSY ((NTSTATUS) 0xC00002A5L) +#endif + +#ifndef STATUS_DS_UNAVAILABLE +# define STATUS_DS_UNAVAILABLE ((NTSTATUS) 0xC00002A6L) +#endif + +#ifndef STATUS_DS_NO_RIDS_ALLOCATED +# define STATUS_DS_NO_RIDS_ALLOCATED ((NTSTATUS) 0xC00002A7L) +#endif + +#ifndef STATUS_DS_NO_MORE_RIDS +# define STATUS_DS_NO_MORE_RIDS ((NTSTATUS) 0xC00002A8L) +#endif + +#ifndef STATUS_DS_INCORRECT_ROLE_OWNER +# define STATUS_DS_INCORRECT_ROLE_OWNER ((NTSTATUS) 0xC00002A9L) +#endif + +#ifndef STATUS_DS_RIDMGR_INIT_ERROR +# define STATUS_DS_RIDMGR_INIT_ERROR ((NTSTATUS) 0xC00002AAL) +#endif + +#ifndef STATUS_DS_OBJ_CLASS_VIOLATION +# define STATUS_DS_OBJ_CLASS_VIOLATION ((NTSTATUS) 0xC00002ABL) +#endif + +#ifndef STATUS_DS_CANT_ON_NON_LEAF +# define STATUS_DS_CANT_ON_NON_LEAF ((NTSTATUS) 0xC00002ACL) +#endif + +#ifndef STATUS_DS_CANT_ON_RDN +# define STATUS_DS_CANT_ON_RDN ((NTSTATUS) 0xC00002ADL) +#endif + +#ifndef STATUS_DS_CANT_MOD_OBJ_CLASS +# define STATUS_DS_CANT_MOD_OBJ_CLASS ((NTSTATUS) 0xC00002AEL) +#endif + +#ifndef STATUS_DS_CROSS_DOM_MOVE_FAILED +# define STATUS_DS_CROSS_DOM_MOVE_FAILED ((NTSTATUS) 0xC00002AFL) +#endif + +#ifndef STATUS_DS_GC_NOT_AVAILABLE +# define STATUS_DS_GC_NOT_AVAILABLE ((NTSTATUS) 0xC00002B0L) +#endif + +#ifndef STATUS_DIRECTORY_SERVICE_REQUIRED +# define STATUS_DIRECTORY_SERVICE_REQUIRED ((NTSTATUS) 0xC00002B1L) +#endif + +#ifndef STATUS_REPARSE_ATTRIBUTE_CONFLICT +# define STATUS_REPARSE_ATTRIBUTE_CONFLICT ((NTSTATUS) 0xC00002B2L) +#endif + +#ifndef STATUS_CANT_ENABLE_DENY_ONLY +# define STATUS_CANT_ENABLE_DENY_ONLY ((NTSTATUS) 0xC00002B3L) +#endif + +#ifndef STATUS_FLOAT_MULTIPLE_FAULTS +# define STATUS_FLOAT_MULTIPLE_FAULTS ((NTSTATUS) 0xC00002B4L) +#endif + +#ifndef STATUS_FLOAT_MULTIPLE_TRAPS +# define STATUS_FLOAT_MULTIPLE_TRAPS ((NTSTATUS) 0xC00002B5L) +#endif + +#ifndef STATUS_DEVICE_REMOVED +# define STATUS_DEVICE_REMOVED ((NTSTATUS) 0xC00002B6L) +#endif + +#ifndef STATUS_JOURNAL_DELETE_IN_PROGRESS +# define STATUS_JOURNAL_DELETE_IN_PROGRESS ((NTSTATUS) 0xC00002B7L) +#endif + +#ifndef STATUS_JOURNAL_NOT_ACTIVE +# define STATUS_JOURNAL_NOT_ACTIVE ((NTSTATUS) 0xC00002B8L) +#endif + +#ifndef STATUS_NOINTERFACE +# define STATUS_NOINTERFACE ((NTSTATUS) 0xC00002B9L) +#endif + +#ifndef STATUS_DS_ADMIN_LIMIT_EXCEEDED +# define STATUS_DS_ADMIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00002C1L) +#endif + +#ifndef STATUS_DRIVER_FAILED_SLEEP +# define STATUS_DRIVER_FAILED_SLEEP ((NTSTATUS) 0xC00002C2L) +#endif + +#ifndef STATUS_MUTUAL_AUTHENTICATION_FAILED +# define STATUS_MUTUAL_AUTHENTICATION_FAILED ((NTSTATUS) 0xC00002C3L) +#endif + +#ifndef STATUS_CORRUPT_SYSTEM_FILE +# define STATUS_CORRUPT_SYSTEM_FILE ((NTSTATUS) 0xC00002C4L) +#endif + +#ifndef STATUS_DATATYPE_MISALIGNMENT_ERROR +# define STATUS_DATATYPE_MISALIGNMENT_ERROR ((NTSTATUS) 0xC00002C5L) +#endif + +#ifndef STATUS_WMI_READ_ONLY +# define STATUS_WMI_READ_ONLY ((NTSTATUS) 0xC00002C6L) +#endif + +#ifndef STATUS_WMI_SET_FAILURE +# define STATUS_WMI_SET_FAILURE ((NTSTATUS) 0xC00002C7L) +#endif + +#ifndef STATUS_COMMITMENT_MINIMUM +# define STATUS_COMMITMENT_MINIMUM ((NTSTATUS) 0xC00002C8L) +#endif + +#ifndef STATUS_REG_NAT_CONSUMPTION +# define STATUS_REG_NAT_CONSUMPTION ((NTSTATUS) 0xC00002C9L) +#endif + +#ifndef STATUS_TRANSPORT_FULL +# define STATUS_TRANSPORT_FULL ((NTSTATUS) 0xC00002CAL) +#endif + +#ifndef STATUS_DS_SAM_INIT_FAILURE +# define STATUS_DS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002CBL) +#endif + +#ifndef STATUS_ONLY_IF_CONNECTED +# define STATUS_ONLY_IF_CONNECTED ((NTSTATUS) 0xC00002CCL) +#endif + +#ifndef STATUS_DS_SENSITIVE_GROUP_VIOLATION +# define STATUS_DS_SENSITIVE_GROUP_VIOLATION ((NTSTATUS) 0xC00002CDL) +#endif + +#ifndef STATUS_PNP_RESTART_ENUMERATION +# define STATUS_PNP_RESTART_ENUMERATION ((NTSTATUS) 0xC00002CEL) +#endif + +#ifndef STATUS_JOURNAL_ENTRY_DELETED +# define STATUS_JOURNAL_ENTRY_DELETED ((NTSTATUS) 0xC00002CFL) +#endif + +#ifndef STATUS_DS_CANT_MOD_PRIMARYGROUPID +# define STATUS_DS_CANT_MOD_PRIMARYGROUPID ((NTSTATUS) 0xC00002D0L) +#endif + +#ifndef STATUS_SYSTEM_IMAGE_BAD_SIGNATURE +# define STATUS_SYSTEM_IMAGE_BAD_SIGNATURE ((NTSTATUS) 0xC00002D1L) +#endif + +#ifndef STATUS_PNP_REBOOT_REQUIRED +# define STATUS_PNP_REBOOT_REQUIRED ((NTSTATUS) 0xC00002D2L) +#endif + +#ifndef STATUS_POWER_STATE_INVALID +# define STATUS_POWER_STATE_INVALID ((NTSTATUS) 0xC00002D3L) +#endif + +#ifndef STATUS_DS_INVALID_GROUP_TYPE +# define STATUS_DS_INVALID_GROUP_TYPE ((NTSTATUS) 0xC00002D4L) +#endif + +#ifndef STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN +# define STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D5L) +#endif + +#ifndef STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN +# define STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D6L) +#endif + +#ifndef STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER +# define STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D7L) +#endif + +#ifndef STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER +# define STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC00002D8L) +#endif + +#ifndef STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER +# define STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D9L) +#endif + +#ifndef STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER +# define STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER ((NTSTATUS) 0xC00002DAL) +#endif + +#ifndef STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER +# define STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER ((NTSTATUS) 0xC00002DBL) +#endif + +#ifndef STATUS_DS_HAVE_PRIMARY_MEMBERS +# define STATUS_DS_HAVE_PRIMARY_MEMBERS ((NTSTATUS) 0xC00002DCL) +#endif + +#ifndef STATUS_WMI_NOT_SUPPORTED +# define STATUS_WMI_NOT_SUPPORTED ((NTSTATUS) 0xC00002DDL) +#endif + +#ifndef STATUS_INSUFFICIENT_POWER +# define STATUS_INSUFFICIENT_POWER ((NTSTATUS) 0xC00002DEL) +#endif + +#ifndef STATUS_SAM_NEED_BOOTKEY_PASSWORD +# define STATUS_SAM_NEED_BOOTKEY_PASSWORD ((NTSTATUS) 0xC00002DFL) +#endif + +#ifndef STATUS_SAM_NEED_BOOTKEY_FLOPPY +# define STATUS_SAM_NEED_BOOTKEY_FLOPPY ((NTSTATUS) 0xC00002E0L) +#endif + +#ifndef STATUS_DS_CANT_START +# define STATUS_DS_CANT_START ((NTSTATUS) 0xC00002E1L) +#endif + +#ifndef STATUS_DS_INIT_FAILURE +# define STATUS_DS_INIT_FAILURE ((NTSTATUS) 0xC00002E2L) +#endif + +#ifndef STATUS_SAM_INIT_FAILURE +# define STATUS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002E3L) +#endif + +#ifndef STATUS_DS_GC_REQUIRED +# define STATUS_DS_GC_REQUIRED ((NTSTATUS) 0xC00002E4L) +#endif + +#ifndef STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY +# define STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY ((NTSTATUS) 0xC00002E5L) +#endif + +#ifndef STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS +# define STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS ((NTSTATUS) 0xC00002E6L) +#endif + +#ifndef STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED +# define STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED ((NTSTATUS) 0xC00002E7L) +#endif + +#ifndef STATUS_MULTIPLE_FAULT_VIOLATION +# define STATUS_MULTIPLE_FAULT_VIOLATION ((NTSTATUS) 0xC00002E8L) +#endif + +#ifndef STATUS_CURRENT_DOMAIN_NOT_ALLOWED +# define STATUS_CURRENT_DOMAIN_NOT_ALLOWED ((NTSTATUS) 0xC00002E9L) +#endif + +#ifndef STATUS_CANNOT_MAKE +# define STATUS_CANNOT_MAKE ((NTSTATUS) 0xC00002EAL) +#endif + +#ifndef STATUS_SYSTEM_SHUTDOWN +# define STATUS_SYSTEM_SHUTDOWN ((NTSTATUS) 0xC00002EBL) +#endif + +#ifndef STATUS_DS_INIT_FAILURE_CONSOLE +# define STATUS_DS_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002ECL) +#endif + +#ifndef STATUS_DS_SAM_INIT_FAILURE_CONSOLE +# define STATUS_DS_SAM_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002EDL) +#endif + +#ifndef STATUS_UNFINISHED_CONTEXT_DELETED +# define STATUS_UNFINISHED_CONTEXT_DELETED ((NTSTATUS) 0xC00002EEL) +#endif + +#ifndef STATUS_NO_TGT_REPLY +# define STATUS_NO_TGT_REPLY ((NTSTATUS) 0xC00002EFL) +#endif + +#ifndef STATUS_OBJECTID_NOT_FOUND +# define STATUS_OBJECTID_NOT_FOUND ((NTSTATUS) 0xC00002F0L) +#endif + +#ifndef STATUS_NO_IP_ADDRESSES +# define STATUS_NO_IP_ADDRESSES ((NTSTATUS) 0xC00002F1L) +#endif + +#ifndef STATUS_WRONG_CREDENTIAL_HANDLE +# define STATUS_WRONG_CREDENTIAL_HANDLE ((NTSTATUS) 0xC00002F2L) +#endif + +#ifndef STATUS_CRYPTO_SYSTEM_INVALID +# define STATUS_CRYPTO_SYSTEM_INVALID ((NTSTATUS) 0xC00002F3L) +#endif + +#ifndef STATUS_MAX_REFERRALS_EXCEEDED +# define STATUS_MAX_REFERRALS_EXCEEDED ((NTSTATUS) 0xC00002F4L) +#endif + +#ifndef STATUS_MUST_BE_KDC +# define STATUS_MUST_BE_KDC ((NTSTATUS) 0xC00002F5L) +#endif + +#ifndef STATUS_STRONG_CRYPTO_NOT_SUPPORTED +# define STATUS_STRONG_CRYPTO_NOT_SUPPORTED ((NTSTATUS) 0xC00002F6L) +#endif + +#ifndef STATUS_TOO_MANY_PRINCIPALS +# define STATUS_TOO_MANY_PRINCIPALS ((NTSTATUS) 0xC00002F7L) +#endif + +#ifndef STATUS_NO_PA_DATA +# define STATUS_NO_PA_DATA ((NTSTATUS) 0xC00002F8L) +#endif + +#ifndef STATUS_PKINIT_NAME_MISMATCH +# define STATUS_PKINIT_NAME_MISMATCH ((NTSTATUS) 0xC00002F9L) +#endif + +#ifndef STATUS_SMARTCARD_LOGON_REQUIRED +# define STATUS_SMARTCARD_LOGON_REQUIRED ((NTSTATUS) 0xC00002FAL) +#endif + +#ifndef STATUS_KDC_INVALID_REQUEST +# define STATUS_KDC_INVALID_REQUEST ((NTSTATUS) 0xC00002FBL) +#endif + +#ifndef STATUS_KDC_UNABLE_TO_REFER +# define STATUS_KDC_UNABLE_TO_REFER ((NTSTATUS) 0xC00002FCL) +#endif + +#ifndef STATUS_KDC_UNKNOWN_ETYPE +# define STATUS_KDC_UNKNOWN_ETYPE ((NTSTATUS) 0xC00002FDL) +#endif + +#ifndef STATUS_SHUTDOWN_IN_PROGRESS +# define STATUS_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FEL) +#endif + +#ifndef STATUS_SERVER_SHUTDOWN_IN_PROGRESS +# define STATUS_SERVER_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FFL) +#endif + +#ifndef STATUS_NOT_SUPPORTED_ON_SBS +# define STATUS_NOT_SUPPORTED_ON_SBS ((NTSTATUS) 0xC0000300L) +#endif + +#ifndef STATUS_WMI_GUID_DISCONNECTED +# define STATUS_WMI_GUID_DISCONNECTED ((NTSTATUS) 0xC0000301L) +#endif + +#ifndef STATUS_WMI_ALREADY_DISABLED +# define STATUS_WMI_ALREADY_DISABLED ((NTSTATUS) 0xC0000302L) +#endif + +#ifndef STATUS_WMI_ALREADY_ENABLED +# define STATUS_WMI_ALREADY_ENABLED ((NTSTATUS) 0xC0000303L) +#endif + +#ifndef STATUS_MFT_TOO_FRAGMENTED +# define STATUS_MFT_TOO_FRAGMENTED ((NTSTATUS) 0xC0000304L) +#endif + +#ifndef STATUS_COPY_PROTECTION_FAILURE +# define STATUS_COPY_PROTECTION_FAILURE ((NTSTATUS) 0xC0000305L) +#endif + +#ifndef STATUS_CSS_AUTHENTICATION_FAILURE +# define STATUS_CSS_AUTHENTICATION_FAILURE ((NTSTATUS) 0xC0000306L) +#endif + +#ifndef STATUS_CSS_KEY_NOT_PRESENT +# define STATUS_CSS_KEY_NOT_PRESENT ((NTSTATUS) 0xC0000307L) +#endif + +#ifndef STATUS_CSS_KEY_NOT_ESTABLISHED +# define STATUS_CSS_KEY_NOT_ESTABLISHED ((NTSTATUS) 0xC0000308L) +#endif + +#ifndef STATUS_CSS_SCRAMBLED_SECTOR +# define STATUS_CSS_SCRAMBLED_SECTOR ((NTSTATUS) 0xC0000309L) +#endif + +#ifndef STATUS_CSS_REGION_MISMATCH +# define STATUS_CSS_REGION_MISMATCH ((NTSTATUS) 0xC000030AL) +#endif + +#ifndef STATUS_CSS_RESETS_EXHAUSTED +# define STATUS_CSS_RESETS_EXHAUSTED ((NTSTATUS) 0xC000030BL) +#endif + +#ifndef STATUS_PKINIT_FAILURE +# define STATUS_PKINIT_FAILURE ((NTSTATUS) 0xC0000320L) +#endif + +#ifndef STATUS_SMARTCARD_SUBSYSTEM_FAILURE +# define STATUS_SMARTCARD_SUBSYSTEM_FAILURE ((NTSTATUS) 0xC0000321L) +#endif + +#ifndef STATUS_NO_KERB_KEY +# define STATUS_NO_KERB_KEY ((NTSTATUS) 0xC0000322L) +#endif + +#ifndef STATUS_HOST_DOWN +# define STATUS_HOST_DOWN ((NTSTATUS) 0xC0000350L) +#endif + +#ifndef STATUS_UNSUPPORTED_PREAUTH +# define STATUS_UNSUPPORTED_PREAUTH ((NTSTATUS) 0xC0000351L) +#endif + +#ifndef STATUS_EFS_ALG_BLOB_TOO_BIG +# define STATUS_EFS_ALG_BLOB_TOO_BIG ((NTSTATUS) 0xC0000352L) +#endif + +#ifndef STATUS_PORT_NOT_SET +# define STATUS_PORT_NOT_SET ((NTSTATUS) 0xC0000353L) +#endif + +#ifndef STATUS_DEBUGGER_INACTIVE +# define STATUS_DEBUGGER_INACTIVE ((NTSTATUS) 0xC0000354L) +#endif + +#ifndef STATUS_DS_VERSION_CHECK_FAILURE +# define STATUS_DS_VERSION_CHECK_FAILURE ((NTSTATUS) 0xC0000355L) +#endif + +#ifndef STATUS_AUDITING_DISABLED +# define STATUS_AUDITING_DISABLED ((NTSTATUS) 0xC0000356L) +#endif + +#ifndef STATUS_PRENT4_MACHINE_ACCOUNT +# define STATUS_PRENT4_MACHINE_ACCOUNT ((NTSTATUS) 0xC0000357L) +#endif + +#ifndef STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER +# define STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC0000358L) +#endif + +#ifndef STATUS_INVALID_IMAGE_WIN_32 +# define STATUS_INVALID_IMAGE_WIN_32 ((NTSTATUS) 0xC0000359L) +#endif + +#ifndef STATUS_INVALID_IMAGE_WIN_64 +# define STATUS_INVALID_IMAGE_WIN_64 ((NTSTATUS) 0xC000035AL) +#endif + +#ifndef STATUS_BAD_BINDINGS +# define STATUS_BAD_BINDINGS ((NTSTATUS) 0xC000035BL) +#endif + +#ifndef STATUS_NETWORK_SESSION_EXPIRED +# define STATUS_NETWORK_SESSION_EXPIRED ((NTSTATUS) 0xC000035CL) +#endif + +#ifndef STATUS_APPHELP_BLOCK +# define STATUS_APPHELP_BLOCK ((NTSTATUS) 0xC000035DL) +#endif + +#ifndef STATUS_ALL_SIDS_FILTERED +# define STATUS_ALL_SIDS_FILTERED ((NTSTATUS) 0xC000035EL) +#endif + +#ifndef STATUS_NOT_SAFE_MODE_DRIVER +# define STATUS_NOT_SAFE_MODE_DRIVER ((NTSTATUS) 0xC000035FL) +#endif + +#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT +# define STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT ((NTSTATUS) 0xC0000361L) +#endif + +#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PATH +# define STATUS_ACCESS_DISABLED_BY_POLICY_PATH ((NTSTATUS) 0xC0000362L) +#endif + +#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER +# define STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER ((NTSTATUS) 0xC0000363L) +#endif + +#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_OTHER +# define STATUS_ACCESS_DISABLED_BY_POLICY_OTHER ((NTSTATUS) 0xC0000364L) +#endif + +#ifndef STATUS_FAILED_DRIVER_ENTRY +# define STATUS_FAILED_DRIVER_ENTRY ((NTSTATUS) 0xC0000365L) +#endif + +#ifndef STATUS_DEVICE_ENUMERATION_ERROR +# define STATUS_DEVICE_ENUMERATION_ERROR ((NTSTATUS) 0xC0000366L) +#endif + +#ifndef STATUS_MOUNT_POINT_NOT_RESOLVED +# define STATUS_MOUNT_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000368L) +#endif + +#ifndef STATUS_INVALID_DEVICE_OBJECT_PARAMETER +# define STATUS_INVALID_DEVICE_OBJECT_PARAMETER ((NTSTATUS) 0xC0000369L) +#endif + +#ifndef STATUS_MCA_OCCURED +# define STATUS_MCA_OCCURED ((NTSTATUS) 0xC000036AL) +#endif + +#ifndef STATUS_DRIVER_BLOCKED_CRITICAL +# define STATUS_DRIVER_BLOCKED_CRITICAL ((NTSTATUS) 0xC000036BL) +#endif + +#ifndef STATUS_DRIVER_BLOCKED +# define STATUS_DRIVER_BLOCKED ((NTSTATUS) 0xC000036CL) +#endif + +#ifndef STATUS_DRIVER_DATABASE_ERROR +# define STATUS_DRIVER_DATABASE_ERROR ((NTSTATUS) 0xC000036DL) +#endif + +#ifndef STATUS_SYSTEM_HIVE_TOO_LARGE +# define STATUS_SYSTEM_HIVE_TOO_LARGE ((NTSTATUS) 0xC000036EL) +#endif + +#ifndef STATUS_INVALID_IMPORT_OF_NON_DLL +# define STATUS_INVALID_IMPORT_OF_NON_DLL ((NTSTATUS) 0xC000036FL) +#endif + +#ifndef STATUS_DS_SHUTTING_DOWN +# define STATUS_DS_SHUTTING_DOWN ((NTSTATUS) 0x40000370L) +#endif + +#ifndef STATUS_NO_SECRETS +# define STATUS_NO_SECRETS ((NTSTATUS) 0xC0000371L) +#endif + +#ifndef STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY +# define STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY ((NTSTATUS) 0xC0000372L) +#endif + +#ifndef STATUS_FAILED_STACK_SWITCH +# define STATUS_FAILED_STACK_SWITCH ((NTSTATUS) 0xC0000373L) +#endif + +#ifndef STATUS_HEAP_CORRUPTION +# define STATUS_HEAP_CORRUPTION ((NTSTATUS) 0xC0000374L) +#endif + +#ifndef STATUS_SMARTCARD_WRONG_PIN +# define STATUS_SMARTCARD_WRONG_PIN ((NTSTATUS) 0xC0000380L) +#endif + +#ifndef STATUS_SMARTCARD_CARD_BLOCKED +# define STATUS_SMARTCARD_CARD_BLOCKED ((NTSTATUS) 0xC0000381L) +#endif + +#ifndef STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED +# define STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED ((NTSTATUS) 0xC0000382L) +#endif + +#ifndef STATUS_SMARTCARD_NO_CARD +# define STATUS_SMARTCARD_NO_CARD ((NTSTATUS) 0xC0000383L) +#endif + +#ifndef STATUS_SMARTCARD_NO_KEY_CONTAINER +# define STATUS_SMARTCARD_NO_KEY_CONTAINER ((NTSTATUS) 0xC0000384L) +#endif + +#ifndef STATUS_SMARTCARD_NO_CERTIFICATE +# define STATUS_SMARTCARD_NO_CERTIFICATE ((NTSTATUS) 0xC0000385L) +#endif + +#ifndef STATUS_SMARTCARD_NO_KEYSET +# define STATUS_SMARTCARD_NO_KEYSET ((NTSTATUS) 0xC0000386L) +#endif + +#ifndef STATUS_SMARTCARD_IO_ERROR +# define STATUS_SMARTCARD_IO_ERROR ((NTSTATUS) 0xC0000387L) +#endif + +#ifndef STATUS_DOWNGRADE_DETECTED +# define STATUS_DOWNGRADE_DETECTED ((NTSTATUS) 0xC0000388L) +#endif + +#ifndef STATUS_SMARTCARD_CERT_REVOKED +# define STATUS_SMARTCARD_CERT_REVOKED ((NTSTATUS) 0xC0000389L) +#endif + +#ifndef STATUS_ISSUING_CA_UNTRUSTED +# define STATUS_ISSUING_CA_UNTRUSTED ((NTSTATUS) 0xC000038AL) +#endif + +#ifndef STATUS_REVOCATION_OFFLINE_C +# define STATUS_REVOCATION_OFFLINE_C ((NTSTATUS) 0xC000038BL) +#endif + +#ifndef STATUS_PKINIT_CLIENT_FAILURE +# define STATUS_PKINIT_CLIENT_FAILURE ((NTSTATUS) 0xC000038CL) +#endif + +#ifndef STATUS_SMARTCARD_CERT_EXPIRED +# define STATUS_SMARTCARD_CERT_EXPIRED ((NTSTATUS) 0xC000038DL) +#endif + +#ifndef STATUS_DRIVER_FAILED_PRIOR_UNLOAD +# define STATUS_DRIVER_FAILED_PRIOR_UNLOAD ((NTSTATUS) 0xC000038EL) +#endif + +#ifndef STATUS_SMARTCARD_SILENT_CONTEXT +# define STATUS_SMARTCARD_SILENT_CONTEXT ((NTSTATUS) 0xC000038FL) +#endif + +#ifndef STATUS_PER_USER_TRUST_QUOTA_EXCEEDED +# define STATUS_PER_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000401L) +#endif + +#ifndef STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED +# define STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000402L) +#endif + +#ifndef STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED +# define STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000403L) +#endif + +#ifndef STATUS_DS_NAME_NOT_UNIQUE +# define STATUS_DS_NAME_NOT_UNIQUE ((NTSTATUS) 0xC0000404L) +#endif + +#ifndef STATUS_DS_DUPLICATE_ID_FOUND +# define STATUS_DS_DUPLICATE_ID_FOUND ((NTSTATUS) 0xC0000405L) +#endif + +#ifndef STATUS_DS_GROUP_CONVERSION_ERROR +# define STATUS_DS_GROUP_CONVERSION_ERROR ((NTSTATUS) 0xC0000406L) +#endif + +#ifndef STATUS_VOLSNAP_PREPARE_HIBERNATE +# define STATUS_VOLSNAP_PREPARE_HIBERNATE ((NTSTATUS) 0xC0000407L) +#endif + +#ifndef STATUS_USER2USER_REQUIRED +# define STATUS_USER2USER_REQUIRED ((NTSTATUS) 0xC0000408L) +#endif + +#ifndef STATUS_STACK_BUFFER_OVERRUN +# define STATUS_STACK_BUFFER_OVERRUN ((NTSTATUS) 0xC0000409L) +#endif + +#ifndef STATUS_NO_S4U_PROT_SUPPORT +# define STATUS_NO_S4U_PROT_SUPPORT ((NTSTATUS) 0xC000040AL) +#endif + +#ifndef STATUS_CROSSREALM_DELEGATION_FAILURE +# define STATUS_CROSSREALM_DELEGATION_FAILURE ((NTSTATUS) 0xC000040BL) +#endif + +#ifndef STATUS_REVOCATION_OFFLINE_KDC +# define STATUS_REVOCATION_OFFLINE_KDC ((NTSTATUS) 0xC000040CL) +#endif + +#ifndef STATUS_ISSUING_CA_UNTRUSTED_KDC +# define STATUS_ISSUING_CA_UNTRUSTED_KDC ((NTSTATUS) 0xC000040DL) +#endif + +#ifndef STATUS_KDC_CERT_EXPIRED +# define STATUS_KDC_CERT_EXPIRED ((NTSTATUS) 0xC000040EL) +#endif + +#ifndef STATUS_KDC_CERT_REVOKED +# define STATUS_KDC_CERT_REVOKED ((NTSTATUS) 0xC000040FL) +#endif + +#ifndef STATUS_PARAMETER_QUOTA_EXCEEDED +# define STATUS_PARAMETER_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000410L) +#endif + +#ifndef STATUS_HIBERNATION_FAILURE +# define STATUS_HIBERNATION_FAILURE ((NTSTATUS) 0xC0000411L) +#endif + +#ifndef STATUS_DELAY_LOAD_FAILED +# define STATUS_DELAY_LOAD_FAILED ((NTSTATUS) 0xC0000412L) +#endif + +#ifndef STATUS_AUTHENTICATION_FIREWALL_FAILED +# define STATUS_AUTHENTICATION_FIREWALL_FAILED ((NTSTATUS) 0xC0000413L) +#endif + +#ifndef STATUS_VDM_DISALLOWED +# define STATUS_VDM_DISALLOWED ((NTSTATUS) 0xC0000414L) +#endif + +#ifndef STATUS_HUNG_DISPLAY_DRIVER_THREAD +# define STATUS_HUNG_DISPLAY_DRIVER_THREAD ((NTSTATUS) 0xC0000415L) +#endif + +#ifndef STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE +# define STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE ((NTSTATUS) 0xC0000416L) +#endif + +#ifndef STATUS_INVALID_CRUNTIME_PARAMETER +# define STATUS_INVALID_CRUNTIME_PARAMETER ((NTSTATUS) 0xC0000417L) +#endif + +#ifndef STATUS_NTLM_BLOCKED +# define STATUS_NTLM_BLOCKED ((NTSTATUS) 0xC0000418L) +#endif + +#ifndef STATUS_DS_SRC_SID_EXISTS_IN_FOREST +# define STATUS_DS_SRC_SID_EXISTS_IN_FOREST ((NTSTATUS) 0xC0000419L) +#endif + +#ifndef STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST +# define STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041AL) +#endif + +#ifndef STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST +# define STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041BL) +#endif + +#ifndef STATUS_INVALID_USER_PRINCIPAL_NAME +# define STATUS_INVALID_USER_PRINCIPAL_NAME ((NTSTATUS) 0xC000041CL) +#endif + +#ifndef STATUS_FATAL_USER_CALLBACK_EXCEPTION +# define STATUS_FATAL_USER_CALLBACK_EXCEPTION ((NTSTATUS) 0xC000041DL) +#endif + +#ifndef STATUS_ASSERTION_FAILURE +# define STATUS_ASSERTION_FAILURE ((NTSTATUS) 0xC0000420L) +#endif + +#ifndef STATUS_VERIFIER_STOP +# define STATUS_VERIFIER_STOP ((NTSTATUS) 0xC0000421L) +#endif + +#ifndef STATUS_CALLBACK_POP_STACK +# define STATUS_CALLBACK_POP_STACK ((NTSTATUS) 0xC0000423L) +#endif + +#ifndef STATUS_INCOMPATIBLE_DRIVER_BLOCKED +# define STATUS_INCOMPATIBLE_DRIVER_BLOCKED ((NTSTATUS) 0xC0000424L) +#endif + +#ifndef STATUS_HIVE_UNLOADED +# define STATUS_HIVE_UNLOADED ((NTSTATUS) 0xC0000425L) +#endif + +#ifndef STATUS_COMPRESSION_DISABLED +# define STATUS_COMPRESSION_DISABLED ((NTSTATUS) 0xC0000426L) +#endif + +#ifndef STATUS_FILE_SYSTEM_LIMITATION +# define STATUS_FILE_SYSTEM_LIMITATION ((NTSTATUS) 0xC0000427L) +#endif + +#ifndef STATUS_INVALID_IMAGE_HASH +# define STATUS_INVALID_IMAGE_HASH ((NTSTATUS) 0xC0000428L) +#endif + +#ifndef STATUS_NOT_CAPABLE +# define STATUS_NOT_CAPABLE ((NTSTATUS) 0xC0000429L) +#endif + +#ifndef STATUS_REQUEST_OUT_OF_SEQUENCE +# define STATUS_REQUEST_OUT_OF_SEQUENCE ((NTSTATUS) 0xC000042AL) +#endif + +#ifndef STATUS_IMPLEMENTATION_LIMIT +# define STATUS_IMPLEMENTATION_LIMIT ((NTSTATUS) 0xC000042BL) +#endif + +#ifndef STATUS_ELEVATION_REQUIRED +# define STATUS_ELEVATION_REQUIRED ((NTSTATUS) 0xC000042CL) +#endif + +#ifndef STATUS_NO_SECURITY_CONTEXT +# define STATUS_NO_SECURITY_CONTEXT ((NTSTATUS) 0xC000042DL) +#endif + +#ifndef STATUS_PKU2U_CERT_FAILURE +# define STATUS_PKU2U_CERT_FAILURE ((NTSTATUS) 0xC000042FL) +#endif + +#ifndef STATUS_BEYOND_VDL +# define STATUS_BEYOND_VDL ((NTSTATUS) 0xC0000432L) +#endif + +#ifndef STATUS_ENCOUNTERED_WRITE_IN_PROGRESS +# define STATUS_ENCOUNTERED_WRITE_IN_PROGRESS ((NTSTATUS) 0xC0000433L) +#endif + +#ifndef STATUS_PTE_CHANGED +# define STATUS_PTE_CHANGED ((NTSTATUS) 0xC0000434L) +#endif + +#ifndef STATUS_PURGE_FAILED +# define STATUS_PURGE_FAILED ((NTSTATUS) 0xC0000435L) +#endif + +#ifndef STATUS_CRED_REQUIRES_CONFIRMATION +# define STATUS_CRED_REQUIRES_CONFIRMATION ((NTSTATUS) 0xC0000440L) +#endif + +#ifndef STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE +# define STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE ((NTSTATUS) 0xC0000441L) +#endif + +#ifndef STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER +# define STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER ((NTSTATUS) 0xC0000442L) +#endif + +#ifndef STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE +# define STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE ((NTSTATUS) 0xC0000443L) +#endif + +#ifndef STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE +# define STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE ((NTSTATUS) 0xC0000444L) +#endif + +#ifndef STATUS_CS_ENCRYPTION_FILE_NOT_CSE +# define STATUS_CS_ENCRYPTION_FILE_NOT_CSE ((NTSTATUS) 0xC0000445L) +#endif + +#ifndef STATUS_INVALID_LABEL +# define STATUS_INVALID_LABEL ((NTSTATUS) 0xC0000446L) +#endif + +#ifndef STATUS_DRIVER_PROCESS_TERMINATED +# define STATUS_DRIVER_PROCESS_TERMINATED ((NTSTATUS) 0xC0000450L) +#endif + +#ifndef STATUS_AMBIGUOUS_SYSTEM_DEVICE +# define STATUS_AMBIGUOUS_SYSTEM_DEVICE ((NTSTATUS) 0xC0000451L) +#endif + +#ifndef STATUS_SYSTEM_DEVICE_NOT_FOUND +# define STATUS_SYSTEM_DEVICE_NOT_FOUND ((NTSTATUS) 0xC0000452L) +#endif + +#ifndef STATUS_RESTART_BOOT_APPLICATION +# define STATUS_RESTART_BOOT_APPLICATION ((NTSTATUS) 0xC0000453L) +#endif + +#ifndef STATUS_INSUFFICIENT_NVRAM_RESOURCES +# define STATUS_INSUFFICIENT_NVRAM_RESOURCES ((NTSTATUS) 0xC0000454L) +#endif + +#ifndef STATUS_INVALID_TASK_NAME +# define STATUS_INVALID_TASK_NAME ((NTSTATUS) 0xC0000500L) +#endif + +#ifndef STATUS_INVALID_TASK_INDEX +# define STATUS_INVALID_TASK_INDEX ((NTSTATUS) 0xC0000501L) +#endif + +#ifndef STATUS_THREAD_ALREADY_IN_TASK +# define STATUS_THREAD_ALREADY_IN_TASK ((NTSTATUS) 0xC0000502L) +#endif + +#ifndef STATUS_CALLBACK_BYPASS +# define STATUS_CALLBACK_BYPASS ((NTSTATUS) 0xC0000503L) +#endif + +#ifndef STATUS_FAIL_FAST_EXCEPTION +# define STATUS_FAIL_FAST_EXCEPTION ((NTSTATUS) 0xC0000602L) +#endif + +#ifndef STATUS_IMAGE_CERT_REVOKED +# define STATUS_IMAGE_CERT_REVOKED ((NTSTATUS) 0xC0000603L) +#endif + +#ifndef STATUS_PORT_CLOSED +# define STATUS_PORT_CLOSED ((NTSTATUS) 0xC0000700L) +#endif + +#ifndef STATUS_MESSAGE_LOST +# define STATUS_MESSAGE_LOST ((NTSTATUS) 0xC0000701L) +#endif + +#ifndef STATUS_INVALID_MESSAGE +# define STATUS_INVALID_MESSAGE ((NTSTATUS) 0xC0000702L) +#endif + +#ifndef STATUS_REQUEST_CANCELED +# define STATUS_REQUEST_CANCELED ((NTSTATUS) 0xC0000703L) +#endif + +#ifndef STATUS_RECURSIVE_DISPATCH +# define STATUS_RECURSIVE_DISPATCH ((NTSTATUS) 0xC0000704L) +#endif + +#ifndef STATUS_LPC_RECEIVE_BUFFER_EXPECTED +# define STATUS_LPC_RECEIVE_BUFFER_EXPECTED ((NTSTATUS) 0xC0000705L) +#endif + +#ifndef STATUS_LPC_INVALID_CONNECTION_USAGE +# define STATUS_LPC_INVALID_CONNECTION_USAGE ((NTSTATUS) 0xC0000706L) +#endif + +#ifndef STATUS_LPC_REQUESTS_NOT_ALLOWED +# define STATUS_LPC_REQUESTS_NOT_ALLOWED ((NTSTATUS) 0xC0000707L) +#endif + +#ifndef STATUS_RESOURCE_IN_USE +# define STATUS_RESOURCE_IN_USE ((NTSTATUS) 0xC0000708L) +#endif + +#ifndef STATUS_HARDWARE_MEMORY_ERROR +# define STATUS_HARDWARE_MEMORY_ERROR ((NTSTATUS) 0xC0000709L) +#endif + +#ifndef STATUS_THREADPOOL_HANDLE_EXCEPTION +# define STATUS_THREADPOOL_HANDLE_EXCEPTION ((NTSTATUS) 0xC000070AL) +#endif + +#ifndef STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED +# define STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070BL) +#endif + +#ifndef STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED +# define STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070CL) +#endif + +#ifndef STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED +# define STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070DL) +#endif + +#ifndef STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED +# define STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070EL) +#endif + +#ifndef STATUS_THREADPOOL_RELEASED_DURING_OPERATION +# define STATUS_THREADPOOL_RELEASED_DURING_OPERATION ((NTSTATUS) 0xC000070FL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING +# define STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000710L) +#endif + +#ifndef STATUS_APC_RETURNED_WHILE_IMPERSONATING +# define STATUS_APC_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000711L) +#endif + +#ifndef STATUS_PROCESS_IS_PROTECTED +# define STATUS_PROCESS_IS_PROTECTED ((NTSTATUS) 0xC0000712L) +#endif + +#ifndef STATUS_MCA_EXCEPTION +# define STATUS_MCA_EXCEPTION ((NTSTATUS) 0xC0000713L) +#endif + +#ifndef STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE +# define STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE ((NTSTATUS) 0xC0000714L) +#endif + +#ifndef STATUS_SYMLINK_CLASS_DISABLED +# define STATUS_SYMLINK_CLASS_DISABLED ((NTSTATUS) 0xC0000715L) +#endif + +#ifndef STATUS_INVALID_IDN_NORMALIZATION +# define STATUS_INVALID_IDN_NORMALIZATION ((NTSTATUS) 0xC0000716L) +#endif + +#ifndef STATUS_NO_UNICODE_TRANSLATION +# define STATUS_NO_UNICODE_TRANSLATION ((NTSTATUS) 0xC0000717L) +#endif + +#ifndef STATUS_ALREADY_REGISTERED +# define STATUS_ALREADY_REGISTERED ((NTSTATUS) 0xC0000718L) +#endif + +#ifndef STATUS_CONTEXT_MISMATCH +# define STATUS_CONTEXT_MISMATCH ((NTSTATUS) 0xC0000719L) +#endif + +#ifndef STATUS_PORT_ALREADY_HAS_COMPLETION_LIST +# define STATUS_PORT_ALREADY_HAS_COMPLETION_LIST ((NTSTATUS) 0xC000071AL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_THREAD_PRIORITY +# define STATUS_CALLBACK_RETURNED_THREAD_PRIORITY ((NTSTATUS) 0xC000071BL) +#endif + +#ifndef STATUS_INVALID_THREAD +# define STATUS_INVALID_THREAD ((NTSTATUS) 0xC000071CL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_TRANSACTION +# define STATUS_CALLBACK_RETURNED_TRANSACTION ((NTSTATUS) 0xC000071DL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_LDR_LOCK +# define STATUS_CALLBACK_RETURNED_LDR_LOCK ((NTSTATUS) 0xC000071EL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_LANG +# define STATUS_CALLBACK_RETURNED_LANG ((NTSTATUS) 0xC000071FL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_PRI_BACK +# define STATUS_CALLBACK_RETURNED_PRI_BACK ((NTSTATUS) 0xC0000720L) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_THREAD_AFFINITY +# define STATUS_CALLBACK_RETURNED_THREAD_AFFINITY ((NTSTATUS) 0xC0000721L) +#endif + +#ifndef STATUS_DISK_REPAIR_DISABLED +# define STATUS_DISK_REPAIR_DISABLED ((NTSTATUS) 0xC0000800L) +#endif + +#ifndef STATUS_DS_DOMAIN_RENAME_IN_PROGRESS +# define STATUS_DS_DOMAIN_RENAME_IN_PROGRESS ((NTSTATUS) 0xC0000801L) +#endif + +#ifndef STATUS_DISK_QUOTA_EXCEEDED +# define STATUS_DISK_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000802L) +#endif + +#ifndef STATUS_DATA_LOST_REPAIR +# define STATUS_DATA_LOST_REPAIR ((NTSTATUS) 0x80000803L) +#endif + +#ifndef STATUS_CONTENT_BLOCKED +# define STATUS_CONTENT_BLOCKED ((NTSTATUS) 0xC0000804L) +#endif + +#ifndef STATUS_BAD_CLUSTERS +# define STATUS_BAD_CLUSTERS ((NTSTATUS) 0xC0000805L) +#endif + +#ifndef STATUS_VOLUME_DIRTY +# define STATUS_VOLUME_DIRTY ((NTSTATUS) 0xC0000806L) +#endif + +#ifndef STATUS_FILE_CHECKED_OUT +# define STATUS_FILE_CHECKED_OUT ((NTSTATUS) 0xC0000901L) +#endif + +#ifndef STATUS_CHECKOUT_REQUIRED +# define STATUS_CHECKOUT_REQUIRED ((NTSTATUS) 0xC0000902L) +#endif + +#ifndef STATUS_BAD_FILE_TYPE +# define STATUS_BAD_FILE_TYPE ((NTSTATUS) 0xC0000903L) +#endif + +#ifndef STATUS_FILE_TOO_LARGE +# define STATUS_FILE_TOO_LARGE ((NTSTATUS) 0xC0000904L) +#endif + +#ifndef STATUS_FORMS_AUTH_REQUIRED +# define STATUS_FORMS_AUTH_REQUIRED ((NTSTATUS) 0xC0000905L) +#endif + +#ifndef STATUS_VIRUS_INFECTED +# define STATUS_VIRUS_INFECTED ((NTSTATUS) 0xC0000906L) +#endif + +#ifndef STATUS_VIRUS_DELETED +# define STATUS_VIRUS_DELETED ((NTSTATUS) 0xC0000907L) +#endif + +#ifndef STATUS_BAD_MCFG_TABLE +# define STATUS_BAD_MCFG_TABLE ((NTSTATUS) 0xC0000908L) +#endif + +#ifndef STATUS_CANNOT_BREAK_OPLOCK +# define STATUS_CANNOT_BREAK_OPLOCK ((NTSTATUS) 0xC0000909L) +#endif + +#ifndef STATUS_WOW_ASSERTION +# define STATUS_WOW_ASSERTION ((NTSTATUS) 0xC0009898L) +#endif + +#ifndef STATUS_INVALID_SIGNATURE +# define STATUS_INVALID_SIGNATURE ((NTSTATUS) 0xC000A000L) +#endif + +#ifndef STATUS_HMAC_NOT_SUPPORTED +# define STATUS_HMAC_NOT_SUPPORTED ((NTSTATUS) 0xC000A001L) +#endif + +#ifndef STATUS_AUTH_TAG_MISMATCH +# define STATUS_AUTH_TAG_MISMATCH ((NTSTATUS) 0xC000A002L) +#endif + +#ifndef STATUS_IPSEC_QUEUE_OVERFLOW +# define STATUS_IPSEC_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A010L) +#endif + +#ifndef STATUS_ND_QUEUE_OVERFLOW +# define STATUS_ND_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A011L) +#endif + +#ifndef STATUS_HOPLIMIT_EXCEEDED +# define STATUS_HOPLIMIT_EXCEEDED ((NTSTATUS) 0xC000A012L) +#endif + +#ifndef STATUS_PROTOCOL_NOT_SUPPORTED +# define STATUS_PROTOCOL_NOT_SUPPORTED ((NTSTATUS) 0xC000A013L) +#endif + +#ifndef STATUS_FASTPATH_REJECTED +# define STATUS_FASTPATH_REJECTED ((NTSTATUS) 0xC000A014L) +#endif + +#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED +# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED ((NTSTATUS) 0xC000A080L) +#endif + +#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR +# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR ((NTSTATUS) 0xC000A081L) +#endif + +#ifndef STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR +# define STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR ((NTSTATUS) 0xC000A082L) +#endif + +#ifndef STATUS_XML_PARSE_ERROR +# define STATUS_XML_PARSE_ERROR ((NTSTATUS) 0xC000A083L) +#endif + +#ifndef STATUS_XMLDSIG_ERROR +# define STATUS_XMLDSIG_ERROR ((NTSTATUS) 0xC000A084L) +#endif + +#ifndef STATUS_WRONG_COMPARTMENT +# define STATUS_WRONG_COMPARTMENT ((NTSTATUS) 0xC000A085L) +#endif + +#ifndef STATUS_AUTHIP_FAILURE +# define STATUS_AUTHIP_FAILURE ((NTSTATUS) 0xC000A086L) +#endif + +#ifndef STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS +# define STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS ((NTSTATUS) 0xC000A087L) +#endif + +#ifndef STATUS_DS_OID_NOT_FOUND +# define STATUS_DS_OID_NOT_FOUND ((NTSTATUS) 0xC000A088L) +#endif + +#ifndef STATUS_HASH_NOT_SUPPORTED +# define STATUS_HASH_NOT_SUPPORTED ((NTSTATUS) 0xC000A100L) +#endif + +#ifndef STATUS_HASH_NOT_PRESENT +# define STATUS_HASH_NOT_PRESENT ((NTSTATUS) 0xC000A101L) +#endif + +/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the */ +/* DDK got it wrong! */ +#ifdef NTSTATUS_FROM_WIN32 +# undef NTSTATUS_FROM_WIN32 +#endif +#define NTSTATUS_FROM_WIN32(error) ((NTSTATUS) (error) <= 0 ? \ + ((NTSTATUS) (error)) : ((NTSTATUS) (((error) & 0x0000FFFF) | \ + (FACILITY_NTWIN32 << 16) | ERROR_SEVERITY_WARNING))) + +#ifndef JOB_OBJECT_LIMIT_PROCESS_MEMORY +# define JOB_OBJECT_LIMIT_PROCESS_MEMORY 0x00000100 +#endif +#ifndef JOB_OBJECT_LIMIT_JOB_MEMORY +# define JOB_OBJECT_LIMIT_JOB_MEMORY 0x00000200 +#endif +#ifndef JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION +# define JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x00000400 +#endif +#ifndef JOB_OBJECT_LIMIT_BREAKAWAY_OK +# define JOB_OBJECT_LIMIT_BREAKAWAY_OK 0x00000800 +#endif +#ifndef JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK +# define JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 0x00001000 +#endif +#ifndef JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE +# define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000 +#endif + +/* from winternl.h */ +typedef struct _UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING, *PUNICODE_STRING; + +typedef const UNICODE_STRING *PCUNICODE_STRING; + +/* from ntifs.h */ +#ifndef DEVICE_TYPE +# define DEVICE_TYPE DWORD +#endif + +/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does + * not. + */ +#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) + typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + } DUMMYUNIONNAME; + } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; +#endif + +typedef struct _IO_STATUS_BLOCK { + union { + NTSTATUS Status; + PVOID Pointer; + } DUMMYUNIONNAME; + ULONG_PTR Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + +typedef enum _FILE_INFORMATION_CLASS { + FileDirectoryInformation = 1, + FileFullDirectoryInformation, + FileBothDirectoryInformation, + FileBasicInformation, + FileStandardInformation, + FileInternalInformation, + FileEaInformation, + FileAccessInformation, + FileNameInformation, + FileRenameInformation, + FileLinkInformation, + FileNamesInformation, + FileDispositionInformation, + FilePositionInformation, + FileFullEaInformation, + FileModeInformation, + FileAlignmentInformation, + FileAllInformation, + FileAllocationInformation, + FileEndOfFileInformation, + FileAlternateNameInformation, + FileStreamInformation, + FilePipeInformation, + FilePipeLocalInformation, + FilePipeRemoteInformation, + FileMailslotQueryInformation, + FileMailslotSetInformation, + FileCompressionInformation, + FileObjectIdInformation, + FileCompletionInformation, + FileMoveClusterInformation, + FileQuotaInformation, + FileReparsePointInformation, + FileNetworkOpenInformation, + FileAttributeTagInformation, + FileTrackingInformation, + FileIdBothDirectoryInformation, + FileIdFullDirectoryInformation, + FileValidDataLengthInformation, + FileShortNameInformation, + FileIoCompletionNotificationInformation, + FileIoStatusBlockRangeInformation, + FileIoPriorityHintInformation, + FileSfioReserveInformation, + FileSfioVolumeInformation, + FileHardLinkInformation, + FileProcessIdsUsingFileInformation, + FileNormalizedNameInformation, + FileNetworkPhysicalNameInformation, + FileIdGlobalTxDirectoryInformation, + FileIsRemoteDeviceInformation, + FileAttributeCacheInformation, + FileNumaNodeInformation, + FileStandardLinkInformation, + FileRemoteProtocolInformation, + FileMaximumInformation +} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; + +typedef struct _FILE_DIRECTORY_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION; + +typedef struct _FILE_BOTH_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[1]; +} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; + +typedef struct _FILE_BASIC_INFORMATION { + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + DWORD FileAttributes; +} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; + +typedef struct _FILE_STANDARD_INFORMATION { + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; + +typedef struct _FILE_INTERNAL_INFORMATION { + LARGE_INTEGER IndexNumber; +} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION; + +typedef struct _FILE_EA_INFORMATION { + ULONG EaSize; +} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION; + +typedef struct _FILE_ACCESS_INFORMATION { + ACCESS_MASK AccessFlags; +} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION; + +typedef struct _FILE_POSITION_INFORMATION { + LARGE_INTEGER CurrentByteOffset; +} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; + +typedef struct _FILE_MODE_INFORMATION { + ULONG Mode; +} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION; + +typedef struct _FILE_ALIGNMENT_INFORMATION { + ULONG AlignmentRequirement; +} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION; + +typedef struct _FILE_NAME_INFORMATION { + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; + +typedef struct _FILE_END_OF_FILE_INFORMATION { + LARGE_INTEGER EndOfFile; +} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; + +typedef struct _FILE_ALL_INFORMATION { + FILE_BASIC_INFORMATION BasicInformation; + FILE_STANDARD_INFORMATION StandardInformation; + FILE_INTERNAL_INFORMATION InternalInformation; + FILE_EA_INFORMATION EaInformation; + FILE_ACCESS_INFORMATION AccessInformation; + FILE_POSITION_INFORMATION PositionInformation; + FILE_MODE_INFORMATION ModeInformation; + FILE_ALIGNMENT_INFORMATION AlignmentInformation; + FILE_NAME_INFORMATION NameInformation; +} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION; + +typedef struct _FILE_DISPOSITION_INFORMATION { + BOOLEAN DeleteFile; +} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION; + +typedef struct _FILE_PIPE_LOCAL_INFORMATION { + ULONG NamedPipeType; + ULONG NamedPipeConfiguration; + ULONG MaximumInstances; + ULONG CurrentInstances; + ULONG InboundQuota; + ULONG ReadDataAvailable; + ULONG OutboundQuota; + ULONG WriteQuotaAvailable; + ULONG NamedPipeState; + ULONG NamedPipeEnd; +} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION; + +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 + +typedef enum _FS_INFORMATION_CLASS { + FileFsVolumeInformation = 1, + FileFsLabelInformation = 2, + FileFsSizeInformation = 3, + FileFsDeviceInformation = 4, + FileFsAttributeInformation = 5, + FileFsControlInformation = 6, + FileFsFullSizeInformation = 7, + FileFsObjectIdInformation = 8, + FileFsDriverPathInformation = 9, + FileFsVolumeFlagsInformation = 10, + FileFsSectorSizeInformation = 11 +} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; + +typedef struct _FILE_FS_VOLUME_INFORMATION { + LARGE_INTEGER VolumeCreationTime; + ULONG VolumeSerialNumber; + ULONG VolumeLabelLength; + BOOLEAN SupportsObjects; + WCHAR VolumeLabel[1]; +} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION; + +typedef struct _FILE_FS_LABEL_INFORMATION { + ULONG VolumeLabelLength; + WCHAR VolumeLabel[1]; +} FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION; + +typedef struct _FILE_FS_SIZE_INFORMATION { + LARGE_INTEGER TotalAllocationUnits; + LARGE_INTEGER AvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION; + +typedef struct _FILE_FS_DEVICE_INFORMATION { + DEVICE_TYPE DeviceType; + ULONG Characteristics; +} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION; + +typedef struct _FILE_FS_ATTRIBUTE_INFORMATION { + ULONG FileSystemAttributes; + LONG MaximumComponentNameLength; + ULONG FileSystemNameLength; + WCHAR FileSystemName[1]; +} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION; + +typedef struct _FILE_FS_CONTROL_INFORMATION { + LARGE_INTEGER FreeSpaceStartFiltering; + LARGE_INTEGER FreeSpaceThreshold; + LARGE_INTEGER FreeSpaceStopFiltering; + LARGE_INTEGER DefaultQuotaThreshold; + LARGE_INTEGER DefaultQuotaLimit; + ULONG FileSystemControlFlags; +} FILE_FS_CONTROL_INFORMATION, *PFILE_FS_CONTROL_INFORMATION; + +typedef struct _FILE_FS_FULL_SIZE_INFORMATION { + LARGE_INTEGER TotalAllocationUnits; + LARGE_INTEGER CallerAvailableAllocationUnits; + LARGE_INTEGER ActualAvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION; + +typedef struct _FILE_FS_OBJECTID_INFORMATION { + UCHAR ObjectId[16]; + UCHAR ExtendedInfo[48]; +} FILE_FS_OBJECTID_INFORMATION, *PFILE_FS_OBJECTID_INFORMATION; + +typedef struct _FILE_FS_DRIVER_PATH_INFORMATION { + BOOLEAN DriverInPath; + ULONG DriverNameLength; + WCHAR DriverName[1]; +} FILE_FS_DRIVER_PATH_INFORMATION, *PFILE_FS_DRIVER_PATH_INFORMATION; + +typedef struct _FILE_FS_VOLUME_FLAGS_INFORMATION { + ULONG Flags; +} FILE_FS_VOLUME_FLAGS_INFORMATION, *PFILE_FS_VOLUME_FLAGS_INFORMATION; + +typedef struct _FILE_FS_SECTOR_SIZE_INFORMATION { + ULONG LogicalBytesPerSector; + ULONG PhysicalBytesPerSectorForAtomicity; + ULONG PhysicalBytesPerSectorForPerformance; + ULONG FileSystemEffectivePhysicalBytesPerSectorForAtomicity; + ULONG Flags; + ULONG ByteOffsetForSectorAlignment; + ULONG ByteOffsetForPartitionAlignment; +} FILE_FS_SECTOR_SIZE_INFORMATION, *PFILE_FS_SECTOR_SIZE_INFORMATION; + +typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; + LARGE_INTEGER InterruptTime; + ULONG InterruptCount; +} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; + +#ifndef SystemProcessorPerformanceInformation +# define SystemProcessorPerformanceInformation 8 +#endif + +#ifndef FILE_DEVICE_FILE_SYSTEM +# define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#endif + +#ifndef FILE_DEVICE_NETWORK +# define FILE_DEVICE_NETWORK 0x00000012 +#endif + +#ifndef METHOD_BUFFERED +# define METHOD_BUFFERED 0 +#endif + +#ifndef METHOD_IN_DIRECT +# define METHOD_IN_DIRECT 1 +#endif + +#ifndef METHOD_OUT_DIRECT +# define METHOD_OUT_DIRECT 2 +#endif + +#ifndef METHOD_NEITHER +#define METHOD_NEITHER 3 +#endif + +#ifndef METHOD_DIRECT_TO_HARDWARE +# define METHOD_DIRECT_TO_HARDWARE METHOD_IN_DIRECT +#endif + +#ifndef METHOD_DIRECT_FROM_HARDWARE +# define METHOD_DIRECT_FROM_HARDWARE METHOD_OUT_DIRECT +#endif + +#ifndef FILE_ANY_ACCESS +# define FILE_ANY_ACCESS 0 +#endif + +#ifndef FILE_SPECIAL_ACCESS +# define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) +#endif + +#ifndef FILE_READ_ACCESS +# define FILE_READ_ACCESS 0x0001 +#endif + +#ifndef FILE_WRITE_ACCESS +# define FILE_WRITE_ACCESS 0x0002 +#endif + +#ifndef CTL_CODE +# define CTL_CODE(device_type, function, method, access) \ + (((device_type) << 16) | ((access) << 14) | ((function) << 2) | (method)) +#endif + +#ifndef FSCTL_SET_REPARSE_POINT +# define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \ + 41, \ + METHOD_BUFFERED, \ + FILE_SPECIAL_ACCESS) +#endif + +#ifndef FSCTL_GET_REPARSE_POINT +# define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \ + 42, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) +#endif + +#ifndef FSCTL_DELETE_REPARSE_POINT +# define FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \ + 43, \ + METHOD_BUFFERED, \ + FILE_SPECIAL_ACCESS) +#endif + +#ifndef IO_REPARSE_TAG_SYMLINK +# define IO_REPARSE_TAG_SYMLINK (0xA000000CL) +#endif + +typedef VOID (NTAPI *PIO_APC_ROUTINE) + (PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG Reserved); + +typedef ULONG (NTAPI *sRtlNtStatusToDosError) + (NTSTATUS Status); + +typedef NTSTATUS (NTAPI *sNtDeviceIoControlFile) + (HANDLE FileHandle, + HANDLE Event, + PIO_APC_ROUTINE ApcRoutine, + PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG IoControlCode, + PVOID InputBuffer, + ULONG InputBufferLength, + PVOID OutputBuffer, + ULONG OutputBufferLength); + +typedef NTSTATUS (NTAPI *sNtQueryInformationFile) + (HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass); + +typedef NTSTATUS (NTAPI *sNtSetInformationFile) + (HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass); + +typedef NTSTATUS (NTAPI *sNtQueryVolumeInformationFile) + (HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FsInformation, + ULONG Length, + FS_INFORMATION_CLASS FsInformationClass); + +typedef NTSTATUS (NTAPI *sNtQuerySystemInformation) + (UINT SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength); + +typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile) + (HANDLE FileHandle, + HANDLE Event, + PIO_APC_ROUTINE ApcRoutine, + PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass, + BOOLEAN ReturnSingleEntry, + PUNICODE_STRING FileName, + BOOLEAN RestartScan + ); + +/* + * Kernel32 headers + */ +#ifndef FILE_SKIP_COMPLETION_PORT_ON_SUCCESS +# define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1 +#endif + +#ifndef FILE_SKIP_SET_EVENT_ON_HANDLE +# define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2 +#endif + +#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY +# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 +#endif + +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) + typedef struct _OVERLAPPED_ENTRY { + ULONG_PTR lpCompletionKey; + LPOVERLAPPED lpOverlapped; + ULONG_PTR Internal; + DWORD dwNumberOfBytesTransferred; + } OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY; +#endif + +/* from wincon.h */ +#ifndef ENABLE_INSERT_MODE +# define ENABLE_INSERT_MODE 0x20 +#endif + +#ifndef ENABLE_QUICK_EDIT_MODE +# define ENABLE_QUICK_EDIT_MODE 0x40 +#endif + +#ifndef ENABLE_EXTENDED_FLAGS +# define ENABLE_EXTENDED_FLAGS 0x80 +#endif + +/* from winerror.h */ +#ifndef ERROR_SYMLINK_NOT_SUPPORTED +# define ERROR_SYMLINK_NOT_SUPPORTED 1464 +#endif + +#ifndef ERROR_MUI_FILE_NOT_FOUND +# define ERROR_MUI_FILE_NOT_FOUND 15100 +#endif + +#ifndef ERROR_MUI_INVALID_FILE +# define ERROR_MUI_INVALID_FILE 15101 +#endif + +#ifndef ERROR_MUI_INVALID_RC_CONFIG +# define ERROR_MUI_INVALID_RC_CONFIG 15102 +#endif + +#ifndef ERROR_MUI_INVALID_LOCALE_NAME +# define ERROR_MUI_INVALID_LOCALE_NAME 15103 +#endif + +#ifndef ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME +# define ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME 15104 +#endif + +#ifndef ERROR_MUI_FILE_NOT_LOADED +# define ERROR_MUI_FILE_NOT_LOADED 15105 +#endif + +typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx) + (HANDLE CompletionPort, + LPOVERLAPPED_ENTRY lpCompletionPortEntries, + ULONG ulCount, + PULONG ulNumEntriesRemoved, + DWORD dwMilliseconds, + BOOL fAlertable); + +typedef BOOL (WINAPI* sSetFileCompletionNotificationModes) + (HANDLE FileHandle, + UCHAR Flags); + +typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW) + (LPCWSTR lpSymlinkFileName, + LPCWSTR lpTargetFileName, + DWORD dwFlags); + +typedef BOOL (WINAPI* sCancelIoEx) + (HANDLE hFile, + LPOVERLAPPED lpOverlapped); + +typedef VOID (WINAPI* sInitializeConditionVariable) + (PCONDITION_VARIABLE ConditionVariable); + +typedef BOOL (WINAPI* sSleepConditionVariableCS) + (PCONDITION_VARIABLE ConditionVariable, + PCRITICAL_SECTION CriticalSection, + DWORD dwMilliseconds); + +typedef BOOL (WINAPI* sSleepConditionVariableSRW) + (PCONDITION_VARIABLE ConditionVariable, + PSRWLOCK SRWLock, + DWORD dwMilliseconds, + ULONG Flags); + +typedef VOID (WINAPI* sWakeAllConditionVariable) + (PCONDITION_VARIABLE ConditionVariable); + +typedef VOID (WINAPI* sWakeConditionVariable) + (PCONDITION_VARIABLE ConditionVariable); + +typedef BOOL (WINAPI* sCancelSynchronousIo) + (HANDLE hThread); + +typedef DWORD (WINAPI* sGetFinalPathNameByHandleW) + (HANDLE hFile, + LPWSTR lpszFilePath, + DWORD cchFilePath, + DWORD dwFlags); + +/* from powerbase.h */ +#ifndef DEVICE_NOTIFY_CALLBACK +# define DEVICE_NOTIFY_CALLBACK 2 +#endif + +#ifndef PBT_APMRESUMEAUTOMATIC +# define PBT_APMRESUMEAUTOMATIC 18 +#endif + +#ifndef PBT_APMRESUMESUSPEND +# define PBT_APMRESUMESUSPEND 7 +#endif + +typedef ULONG CALLBACK _DEVICE_NOTIFY_CALLBACK_ROUTINE( + PVOID Context, + ULONG Type, + PVOID Setting +); +typedef _DEVICE_NOTIFY_CALLBACK_ROUTINE* _PDEVICE_NOTIFY_CALLBACK_ROUTINE; + +typedef struct _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS { + _PDEVICE_NOTIFY_CALLBACK_ROUTINE Callback; + PVOID Context; +} _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, *_PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS; + +typedef PVOID _HPOWERNOTIFY; +typedef _HPOWERNOTIFY *_PHPOWERNOTIFY; + +typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification) + (DWORD Flags, + HANDLE Recipient, + _PHPOWERNOTIFY RegistrationHandle); + + +/* Ntdll function pointers */ +extern sRtlNtStatusToDosError pRtlNtStatusToDosError; +extern sNtDeviceIoControlFile pNtDeviceIoControlFile; +extern sNtQueryInformationFile pNtQueryInformationFile; +extern sNtSetInformationFile pNtSetInformationFile; +extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile; +extern sNtQueryDirectoryFile pNtQueryDirectoryFile; +extern sNtQuerySystemInformation pNtQuerySystemInformation; + + +/* Kernel32 function pointers */ +extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; +extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; +extern sCreateSymbolicLinkW pCreateSymbolicLinkW; +extern sCancelIoEx pCancelIoEx; +extern sInitializeConditionVariable pInitializeConditionVariable; +extern sSleepConditionVariableCS pSleepConditionVariableCS; +extern sSleepConditionVariableSRW pSleepConditionVariableSRW; +extern sWakeAllConditionVariable pWakeAllConditionVariable; +extern sWakeConditionVariable pWakeConditionVariable; +extern sCancelSynchronousIo pCancelSynchronousIo; +extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; + + +/* Powrprof.dll function pointer */ +extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; + +#endif /* UV_WIN_WINAPI_H_ */ diff --git a/src/win/winsock.c b/src/win/winsock.c new file mode 100644 index 0000000..d2e667e --- /dev/null +++ b/src/win/winsock.c @@ -0,0 +1,561 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" + + +/* Whether there are any non-IFS LSPs stacked on TCP */ +int uv_tcp_non_ifs_lsp_ipv4; +int uv_tcp_non_ifs_lsp_ipv6; + +/* Ip address used to bind to any port at any interface */ +struct sockaddr_in uv_addr_ip4_any_; +struct sockaddr_in6 uv_addr_ip6_any_; + + +/* + * Retrieves the pointer to a winsock extension function. + */ +static BOOL uv_get_extension_function(SOCKET socket, GUID guid, + void **target) { + int result; + DWORD bytes; + + result = WSAIoctl(socket, + SIO_GET_EXTENSION_FUNCTION_POINTER, + &guid, + sizeof(guid), + (void*)target, + sizeof(*target), + &bytes, + NULL, + NULL); + + if (result == SOCKET_ERROR) { + *target = NULL; + return FALSE; + } else { + return TRUE; + } +} + + +BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) { + const GUID wsaid_acceptex = WSAID_ACCEPTEX; + return uv_get_extension_function(socket, wsaid_acceptex, (void**)target); +} + + +BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) { + const GUID wsaid_connectex = WSAID_CONNECTEX; + return uv_get_extension_function(socket, wsaid_connectex, (void**)target); +} + + +static int error_means_no_support(DWORD error) { + return error == WSAEPROTONOSUPPORT || error == WSAESOCKTNOSUPPORT || + error == WSAEPFNOSUPPORT || error == WSAEAFNOSUPPORT; +} + + +void uv_winsock_init() { + WSADATA wsa_data; + int errorno; + SOCKET dummy; + WSAPROTOCOL_INFOW protocol_info; + int opt_len; + + /* Initialize winsock */ + errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data); + if (errorno != 0) { + uv_fatal_error(errorno, "WSAStartup"); + } + + /* Set implicit binding address used by connectEx */ + if (uv_ip4_addr("0.0.0.0", 0, &uv_addr_ip4_any_)) { + abort(); + } + + if (uv_ip6_addr("::", 0, &uv_addr_ip6_any_)) { + abort(); + } + + /* Detect non-IFS LSPs */ + dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + + if (dummy != INVALID_SOCKET) { + opt_len = (int) sizeof protocol_info; + if (getsockopt(dummy, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &opt_len) == SOCKET_ERROR) + uv_fatal_error(WSAGetLastError(), "getsockopt"); + + if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)) + uv_tcp_non_ifs_lsp_ipv4 = 1; + + if (closesocket(dummy) == SOCKET_ERROR) + uv_fatal_error(WSAGetLastError(), "closesocket"); + + } else if (!error_means_no_support(WSAGetLastError())) { + /* Any error other than "socket type not supported" is fatal. */ + uv_fatal_error(WSAGetLastError(), "socket"); + } + + /* Detect IPV6 support and non-IFS LSPs */ + dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP); + + if (dummy != INVALID_SOCKET) { + opt_len = (int) sizeof protocol_info; + if (getsockopt(dummy, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &opt_len) == SOCKET_ERROR) + uv_fatal_error(WSAGetLastError(), "getsockopt"); + + if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)) + uv_tcp_non_ifs_lsp_ipv6 = 1; + + if (closesocket(dummy) == SOCKET_ERROR) + uv_fatal_error(WSAGetLastError(), "closesocket"); + + } else if (!error_means_no_support(WSAGetLastError())) { + /* Any error other than "socket type not supported" is fatal. */ + uv_fatal_error(WSAGetLastError(), "socket"); + } +} + + +int uv_ntstatus_to_winsock_error(NTSTATUS status) { + switch (status) { + case STATUS_SUCCESS: + return ERROR_SUCCESS; + + case STATUS_PENDING: + return ERROR_IO_PENDING; + + case STATUS_INVALID_HANDLE: + case STATUS_OBJECT_TYPE_MISMATCH: + return WSAENOTSOCK; + + case STATUS_INSUFFICIENT_RESOURCES: + case STATUS_PAGEFILE_QUOTA: + case STATUS_COMMITMENT_LIMIT: + case STATUS_WORKING_SET_QUOTA: + case STATUS_NO_MEMORY: + case STATUS_QUOTA_EXCEEDED: + case STATUS_TOO_MANY_PAGING_FILES: + case STATUS_REMOTE_RESOURCES: + return WSAENOBUFS; + + case STATUS_TOO_MANY_ADDRESSES: + case STATUS_SHARING_VIOLATION: + case STATUS_ADDRESS_ALREADY_EXISTS: + return WSAEADDRINUSE; + + case STATUS_LINK_TIMEOUT: + case STATUS_IO_TIMEOUT: + case STATUS_TIMEOUT: + return WSAETIMEDOUT; + + case STATUS_GRACEFUL_DISCONNECT: + return WSAEDISCON; + + case STATUS_REMOTE_DISCONNECT: + case STATUS_CONNECTION_RESET: + case STATUS_LINK_FAILED: + case STATUS_CONNECTION_DISCONNECTED: + case STATUS_PORT_UNREACHABLE: + case STATUS_HOPLIMIT_EXCEEDED: + return WSAECONNRESET; + + case STATUS_LOCAL_DISCONNECT: + case STATUS_TRANSACTION_ABORTED: + case STATUS_CONNECTION_ABORTED: + return WSAECONNABORTED; + + case STATUS_BAD_NETWORK_PATH: + case STATUS_NETWORK_UNREACHABLE: + case STATUS_PROTOCOL_UNREACHABLE: + return WSAENETUNREACH; + + case STATUS_HOST_UNREACHABLE: + return WSAEHOSTUNREACH; + + case STATUS_CANCELLED: + case STATUS_REQUEST_ABORTED: + return WSAEINTR; + + case STATUS_BUFFER_OVERFLOW: + case STATUS_INVALID_BUFFER_SIZE: + return WSAEMSGSIZE; + + case STATUS_BUFFER_TOO_SMALL: + case STATUS_ACCESS_VIOLATION: + return WSAEFAULT; + + case STATUS_DEVICE_NOT_READY: + case STATUS_REQUEST_NOT_ACCEPTED: + return WSAEWOULDBLOCK; + + case STATUS_INVALID_NETWORK_RESPONSE: + case STATUS_NETWORK_BUSY: + case STATUS_NO_SUCH_DEVICE: + case STATUS_NO_SUCH_FILE: + case STATUS_OBJECT_PATH_NOT_FOUND: + case STATUS_OBJECT_NAME_NOT_FOUND: + case STATUS_UNEXPECTED_NETWORK_ERROR: + return WSAENETDOWN; + + case STATUS_INVALID_CONNECTION: + return WSAENOTCONN; + + case STATUS_REMOTE_NOT_LISTENING: + case STATUS_CONNECTION_REFUSED: + return WSAECONNREFUSED; + + case STATUS_PIPE_DISCONNECTED: + return WSAESHUTDOWN; + + case STATUS_CONFLICTING_ADDRESSES: + case STATUS_INVALID_ADDRESS: + case STATUS_INVALID_ADDRESS_COMPONENT: + return WSAEADDRNOTAVAIL; + + case STATUS_NOT_SUPPORTED: + case STATUS_NOT_IMPLEMENTED: + return WSAEOPNOTSUPP; + + case STATUS_ACCESS_DENIED: + return WSAEACCES; + + default: + if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) && + (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) { + /* It's a windows error that has been previously mapped to an */ + /* ntstatus code. */ + return (DWORD) (status & 0xffff); + } else { + /* The default fallback for unmappable ntstatus codes. */ + return WSAEINVAL; + } + } +} + + +/* + * This function provides a workaround for a bug in the winsock implementation + * of WSARecv. The problem is that when SetFileCompletionNotificationModes is + * used to avoid IOCP notifications of completed reads, WSARecv does not + * reliably indicate whether we can expect a completion package to be posted + * when the receive buffer is smaller than the received datagram. + * + * However it is desirable to use SetFileCompletionNotificationModes because + * it yields a massive performance increase. + * + * This function provides a workaround for that bug, but it only works for the + * specific case that we need it for. E.g. it assumes that the "avoid iocp" + * bit has been set, and supports only overlapped operation. It also requires + * the user to use the default msafd driver, doesn't work when other LSPs are + * stacked on top of it. + */ +int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers, + DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) { + NTSTATUS status; + void* apc_context; + IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal; + AFD_RECV_INFO info; + DWORD error; + + if (overlapped == NULL || completion_routine != NULL) { + WSASetLastError(WSAEINVAL); + return SOCKET_ERROR; + } + + info.BufferArray = buffers; + info.BufferCount = buffer_count; + info.AfdFlags = AFD_OVERLAPPED; + info.TdiFlags = TDI_RECEIVE_NORMAL; + + if (*flags & MSG_PEEK) { + info.TdiFlags |= TDI_RECEIVE_PEEK; + } + + if (*flags & MSG_PARTIAL) { + info.TdiFlags |= TDI_RECEIVE_PARTIAL; + } + + if (!((intptr_t) overlapped->hEvent & 1)) { + apc_context = (void*) overlapped; + } else { + apc_context = NULL; + } + + iosb->Status = STATUS_PENDING; + iosb->Pointer = 0; + + status = pNtDeviceIoControlFile((HANDLE) socket, + overlapped->hEvent, + NULL, + apc_context, + iosb, + IOCTL_AFD_RECEIVE, + &info, + sizeof(info), + NULL, + 0); + + *flags = 0; + *bytes = (DWORD) iosb->Information; + + switch (status) { + case STATUS_SUCCESS: + error = ERROR_SUCCESS; + break; + + case STATUS_PENDING: + error = WSA_IO_PENDING; + break; + + case STATUS_BUFFER_OVERFLOW: + error = WSAEMSGSIZE; + break; + + case STATUS_RECEIVE_EXPEDITED: + error = ERROR_SUCCESS; + *flags = MSG_OOB; + break; + + case STATUS_RECEIVE_PARTIAL_EXPEDITED: + error = ERROR_SUCCESS; + *flags = MSG_PARTIAL | MSG_OOB; + break; + + case STATUS_RECEIVE_PARTIAL: + error = ERROR_SUCCESS; + *flags = MSG_PARTIAL; + break; + + default: + error = uv_ntstatus_to_winsock_error(status); + break; + } + + WSASetLastError(error); + + if (error == ERROR_SUCCESS) { + return 0; + } else { + return SOCKET_ERROR; + } +} + + +/* See description of uv_wsarecv_workaround. */ +int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, + DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr, + int* addr_len, WSAOVERLAPPED *overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) { + NTSTATUS status; + void* apc_context; + IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal; + AFD_RECV_DATAGRAM_INFO info; + DWORD error; + + if (overlapped == NULL || addr == NULL || addr_len == NULL || + completion_routine != NULL) { + WSASetLastError(WSAEINVAL); + return SOCKET_ERROR; + } + + info.BufferArray = buffers; + info.BufferCount = buffer_count; + info.AfdFlags = AFD_OVERLAPPED; + info.TdiFlags = TDI_RECEIVE_NORMAL; + info.Address = addr; + info.AddressLength = addr_len; + + if (*flags & MSG_PEEK) { + info.TdiFlags |= TDI_RECEIVE_PEEK; + } + + if (*flags & MSG_PARTIAL) { + info.TdiFlags |= TDI_RECEIVE_PARTIAL; + } + + if (!((intptr_t) overlapped->hEvent & 1)) { + apc_context = (void*) overlapped; + } else { + apc_context = NULL; + } + + iosb->Status = STATUS_PENDING; + iosb->Pointer = 0; + + status = pNtDeviceIoControlFile((HANDLE) socket, + overlapped->hEvent, + NULL, + apc_context, + iosb, + IOCTL_AFD_RECEIVE_DATAGRAM, + &info, + sizeof(info), + NULL, + 0); + + *flags = 0; + *bytes = (DWORD) iosb->Information; + + switch (status) { + case STATUS_SUCCESS: + error = ERROR_SUCCESS; + break; + + case STATUS_PENDING: + error = WSA_IO_PENDING; + break; + + case STATUS_BUFFER_OVERFLOW: + error = WSAEMSGSIZE; + break; + + case STATUS_RECEIVE_EXPEDITED: + error = ERROR_SUCCESS; + *flags = MSG_OOB; + break; + + case STATUS_RECEIVE_PARTIAL_EXPEDITED: + error = ERROR_SUCCESS; + *flags = MSG_PARTIAL | MSG_OOB; + break; + + case STATUS_RECEIVE_PARTIAL: + error = ERROR_SUCCESS; + *flags = MSG_PARTIAL; + break; + + default: + error = uv_ntstatus_to_winsock_error(status); + break; + } + + WSASetLastError(error); + + if (error == ERROR_SUCCESS) { + return 0; + } else { + return SOCKET_ERROR; + } +} + + +int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, + AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) { + IO_STATUS_BLOCK iosb; + IO_STATUS_BLOCK* iosb_ptr; + HANDLE event = NULL; + void* apc_context; + NTSTATUS status; + DWORD error; + + if (overlapped != NULL) { + /* Overlapped operation. */ + iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal; + event = overlapped->hEvent; + + /* Do not report iocp completion if hEvent is tagged. */ + if ((uintptr_t) event & 1) { + event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1); + apc_context = NULL; + } else { + apc_context = overlapped; + } + + } else { + /* Blocking operation. */ + iosb_ptr = &iosb; + event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (event == NULL) { + return SOCKET_ERROR; + } + apc_context = NULL; + } + + iosb_ptr->Status = STATUS_PENDING; + status = pNtDeviceIoControlFile((HANDLE) socket, + event, + NULL, + apc_context, + iosb_ptr, + IOCTL_AFD_POLL, + info_in, + sizeof *info_in, + info_out, + sizeof *info_out); + + if (overlapped == NULL) { + /* If this is a blocking operation, wait for the event to become */ + /* signaled, and then grab the real status from the io status block. */ + if (status == STATUS_PENDING) { + DWORD r = WaitForSingleObject(event, INFINITE); + + if (r == WAIT_FAILED) { + DWORD saved_error = GetLastError(); + CloseHandle(event); + WSASetLastError(saved_error); + return SOCKET_ERROR; + } + + status = iosb.Status; + } + + CloseHandle(event); + } + + switch (status) { + case STATUS_SUCCESS: + error = ERROR_SUCCESS; + break; + + case STATUS_PENDING: + error = WSA_IO_PENDING; + break; + + default: + error = uv_ntstatus_to_winsock_error(status); + break; + } + + WSASetLastError(error); + + if (error == ERROR_SUCCESS) { + return 0; + } else { + return SOCKET_ERROR; + } +} diff --git a/src/win/winsock.h b/src/win/winsock.h new file mode 100644 index 0000000..7c007ab --- /dev/null +++ b/src/win/winsock.h @@ -0,0 +1,190 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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 UV_WIN_WINSOCK_H_ +#define UV_WIN_WINSOCK_H_ + +#include +#include +#include +#include +#include + +#include "winapi.h" + + +/* + * MinGW is missing these too + */ +#ifndef SO_UPDATE_CONNECT_CONTEXT +# define SO_UPDATE_CONNECT_CONTEXT 0x7010 +#endif + +#ifndef TCP_KEEPALIVE +# define TCP_KEEPALIVE 3 +#endif + +#ifndef IPV6_V6ONLY +# define IPV6_V6ONLY 27 +#endif + +#ifndef IPV6_HOPLIMIT +# define IPV6_HOPLIMIT 21 +#endif + +#ifndef SIO_BASE_HANDLE +# define SIO_BASE_HANDLE 0x48000022 +#endif + +/* + * TDI defines that are only in the DDK. + * We only need receive flags so far. + */ +#ifndef TDI_RECEIVE_NORMAL + #define TDI_RECEIVE_BROADCAST 0x00000004 + #define TDI_RECEIVE_MULTICAST 0x00000008 + #define TDI_RECEIVE_PARTIAL 0x00000010 + #define TDI_RECEIVE_NORMAL 0x00000020 + #define TDI_RECEIVE_EXPEDITED 0x00000040 + #define TDI_RECEIVE_PEEK 0x00000080 + #define TDI_RECEIVE_NO_RESPONSE_EXP 0x00000100 + #define TDI_RECEIVE_COPY_LOOKAHEAD 0x00000200 + #define TDI_RECEIVE_ENTIRE_MESSAGE 0x00000400 + #define TDI_RECEIVE_AT_DISPATCH_LEVEL 0x00000800 + #define TDI_RECEIVE_CONTROL_INFO 0x00001000 + #define TDI_RECEIVE_FORCE_INDICATION 0x00002000 + #define TDI_RECEIVE_NO_PUSH 0x00004000 +#endif + +/* + * The "Auxiliary Function Driver" is the windows kernel-mode driver that does + * TCP, UDP etc. Winsock is just a layer that dispatches requests to it. + * Having these definitions allows us to bypass winsock and make an AFD kernel + * call directly, avoiding a bug in winsock's recvfrom implementation. + */ + +#define AFD_NO_FAST_IO 0x00000001 +#define AFD_OVERLAPPED 0x00000002 +#define AFD_IMMEDIATE 0x00000004 + +#define AFD_POLL_RECEIVE_BIT 0 +#define AFD_POLL_RECEIVE (1 << AFD_POLL_RECEIVE_BIT) +#define AFD_POLL_RECEIVE_EXPEDITED_BIT 1 +#define AFD_POLL_RECEIVE_EXPEDITED (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT) +#define AFD_POLL_SEND_BIT 2 +#define AFD_POLL_SEND (1 << AFD_POLL_SEND_BIT) +#define AFD_POLL_DISCONNECT_BIT 3 +#define AFD_POLL_DISCONNECT (1 << AFD_POLL_DISCONNECT_BIT) +#define AFD_POLL_ABORT_BIT 4 +#define AFD_POLL_ABORT (1 << AFD_POLL_ABORT_BIT) +#define AFD_POLL_LOCAL_CLOSE_BIT 5 +#define AFD_POLL_LOCAL_CLOSE (1 << AFD_POLL_LOCAL_CLOSE_BIT) +#define AFD_POLL_CONNECT_BIT 6 +#define AFD_POLL_CONNECT (1 << AFD_POLL_CONNECT_BIT) +#define AFD_POLL_ACCEPT_BIT 7 +#define AFD_POLL_ACCEPT (1 << AFD_POLL_ACCEPT_BIT) +#define AFD_POLL_CONNECT_FAIL_BIT 8 +#define AFD_POLL_CONNECT_FAIL (1 << AFD_POLL_CONNECT_FAIL_BIT) +#define AFD_POLL_QOS_BIT 9 +#define AFD_POLL_QOS (1 << AFD_POLL_QOS_BIT) +#define AFD_POLL_GROUP_QOS_BIT 10 +#define AFD_POLL_GROUP_QOS (1 << AFD_POLL_GROUP_QOS_BIT) + +#define AFD_NUM_POLL_EVENTS 11 +#define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1) + +typedef struct _AFD_RECV_DATAGRAM_INFO { + LPWSABUF BufferArray; + ULONG BufferCount; + ULONG AfdFlags; + ULONG TdiFlags; + struct sockaddr* Address; + int* AddressLength; +} AFD_RECV_DATAGRAM_INFO, *PAFD_RECV_DATAGRAM_INFO; + +typedef struct _AFD_RECV_INFO { + LPWSABUF BufferArray; + ULONG BufferCount; + ULONG AfdFlags; + ULONG TdiFlags; +} AFD_RECV_INFO, *PAFD_RECV_INFO; + + +#define _AFD_CONTROL_CODE(operation, method) \ + ((FSCTL_AFD_BASE) << 12 | (operation << 2) | method) + +#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK + +#define AFD_RECEIVE 5 +#define AFD_RECEIVE_DATAGRAM 6 +#define AFD_POLL 9 + +#define IOCTL_AFD_RECEIVE \ + _AFD_CONTROL_CODE(AFD_RECEIVE, METHOD_NEITHER) + +#define IOCTL_AFD_RECEIVE_DATAGRAM \ + _AFD_CONTROL_CODE(AFD_RECEIVE_DATAGRAM, METHOD_NEITHER) + +#define IOCTL_AFD_POLL \ + _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED) + +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP { + /* FIXME: __C89_NAMELESS was removed */ + /* __C89_NAMELESS */ union { + ULONGLONG Alignment; + /* __C89_NAMELESS */ struct { + ULONG Length; + DWORD Flags; + }; + }; + struct _IP_ADAPTER_UNICAST_ADDRESS_XP *Next; + SOCKET_ADDRESS Address; + IP_PREFIX_ORIGIN PrefixOrigin; + IP_SUFFIX_ORIGIN SuffixOrigin; + IP_DAD_STATE DadState; + ULONG ValidLifetime; + ULONG PreferredLifetime; + ULONG LeaseLifetime; +} IP_ADAPTER_UNICAST_ADDRESS_XP,*PIP_ADAPTER_UNICAST_ADDRESS_XP; + +typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH { + union { + ULONGLONG Alignment; + struct { + ULONG Length; + DWORD Flags; + }; + }; + struct _IP_ADAPTER_UNICAST_ADDRESS_LH *Next; + SOCKET_ADDRESS Address; + IP_PREFIX_ORIGIN PrefixOrigin; + IP_SUFFIX_ORIGIN SuffixOrigin; + IP_DAD_STATE DadState; + ULONG ValidLifetime; + ULONG PreferredLifetime; + ULONG LeaseLifetime; + UINT8 OnLinkPrefixLength; +} IP_ADAPTER_UNICAST_ADDRESS_LH,*PIP_ADAPTER_UNICAST_ADDRESS_LH; + +#endif + +#endif /* UV_WIN_WINSOCK_H_ */ https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3800fc299fe7703c4a3976f9ba9028e1ebeb3d3e commit 3800fc299fe7703c4a3976f9ba9028e1ebeb3d3e Author: Brad King AuthorDate: Tue Aug 16 16:19:43 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 08:53:38 2016 -0400 Add script to update libuv from upstream diff --git a/Utilities/Scripts/update-libuv.bash b/Utilities/Scripts/update-libuv.bash new file mode 100755 index 0000000..d7a7d1f --- /dev/null +++ b/Utilities/Scripts/update-libuv.bash @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -e +set -x +shopt -s dotglob + +readonly name="libuv" +readonly ownership="libuv upstream " +readonly subtree="Utilities/cmlibuv" +readonly repo="https://github.com/libuv/libuv.git" +readonly tag="v1.x" +readonly shortlog=false +readonly paths=" + LICENSE + include + src +" + +extract_source () { + git_archive + pushd "${extractdir}/${name}-reduced" + echo "* -whitespace" > .gitattributes + popd +} + +. "${BASH_SOURCE%/*}/update-third-party.bash" ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 09:17:41 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 09:17:41 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1647-g698e662 Message-ID: <20160831131741.616B4F56F9@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 698e66225604dfd7b2419d2459bddcbc08c609b9 (commit) via df32e564aed43470e304cf21d8c9ac1d5a01d055 (commit) from da28ae1b3d79b91d94fa39aa7228b0717374f972 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=698e66225604dfd7b2419d2459bddcbc08c609b9 commit 698e66225604dfd7b2419d2459bddcbc08c609b9 Merge: da28ae1 df32e56 Author: Brad King AuthorDate: Wed Aug 31 09:17:40 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 09:17:40 2016 -0400 Merge topic '16101-xcode-fix-directory-exclude-from-all' into next df32e564 Xcode: Add targets marked as EXCLUDE_FROM_ALL to project (#16101) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=df32e564aed43470e304cf21d8c9ac1d5a01d055 commit df32e564aed43470e304cf21d8c9ac1d5a01d055 Author: Gregor Jasny AuthorDate: Fri Aug 19 21:50:48 2016 +0200 Commit: Brad King CommitDate: Wed Aug 31 09:16:44 2016 -0400 Xcode: Add targets marked as EXCLUDE_FROM_ALL to project (#16101) diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 780ca90..b4bc084 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -2635,13 +2635,10 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) } bool cmGlobalXCodeGenerator::CreateGroups( - cmLocalGenerator* root, std::vector& generators) + std::vector& generators) { for (std::vector::iterator i = generators.begin(); i != generators.end(); ++i) { - if (this->IsExcluded(root, *i)) { - continue; - } cmMakefile* mf = (*i)->GetMakefile(); std::vector sourceGroups = mf->GetSourceGroups(); std::vector tgts = (*i)->GetGeneratorTargets(); @@ -2873,7 +2870,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( this->MainGroupChildren->AddObject(resourcesGroup); // now create the cmake groups - if (!this->CreateGroups(root, generators)) { + if (!this->CreateGroups(generators)) { return false; } @@ -3041,10 +3038,8 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( std::vector targets; for (std::vector::iterator i = generators.begin(); i != generators.end(); ++i) { - if (!this->IsExcluded(root, *i)) { - if (!this->CreateXCodeTargets(*i, targets)) { - return false; - } + if (!this->CreateXCodeTargets(*i, targets)) { + return false; } } // loop over all targets and add link and depend info diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 0485d4f..303dfa0 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -92,8 +92,7 @@ private: cmXCodeObject* CreateOrGetPBXGroup(cmGeneratorTarget* gtgt, cmSourceGroup* sg); cmXCodeObject* CreatePBXGroup(cmXCodeObject* parent, std::string name); - bool CreateGroups(cmLocalGenerator* root, - std::vector& generators); + bool CreateGroups(std::vector& generators); std::string XCodeEscapePath(const std::string& p); std::string RelativeToSource(const char* p); std::string RelativeToBinary(const char* p); diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake b/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake new file mode 100644 index 0000000..f686005 --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake @@ -0,0 +1,6 @@ +enable_language(CXX) + +add_subdirectory(ExcludeFromAll EXCLUDE_FROM_ALL) + +add_executable(main main.cpp) +target_link_libraries(main PRIVATE foo) diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt new file mode 100644 index 0000000..b1df6b0 --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(bar STATIC bar.cpp) + +add_library(foo STATIC foo.cpp) +target_include_directories(foo PUBLIC .) diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp new file mode 100644 index 0000000..7a828bd --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp @@ -0,0 +1 @@ +#error This should be excluded from all target diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp new file mode 100644 index 0000000..c9ad322 --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp @@ -0,0 +1,6 @@ +#include "foo.h" + +int foo() +{ + return 42; +} diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.h b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.h new file mode 100644 index 0000000..5d5f8f0 --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.h @@ -0,0 +1 @@ +int foo(); diff --git a/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake index 9d514e1..88b9283 100644 --- a/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake +++ b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake @@ -3,3 +3,15 @@ include(RunCMake) run_cmake(DoesNotExist) run_cmake(Missing) run_cmake(Function) + +set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ExcludeFromAll-build) +set(RunCMake_TEST_NO_CLEAN 1) + +file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") +file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + +run_cmake(ExcludeFromAll) +run_cmake_command(ExcludeFromAll-build ${CMAKE_COMMAND} --build .) + +unset(RunCMake_TEST_BINARY_DIR) +unset(RunCMake_TEST_NO_CLEAN) diff --git a/Tests/RunCMake/add_subdirectory/main.cpp b/Tests/RunCMake/add_subdirectory/main.cpp new file mode 100644 index 0000000..1dc3906 --- /dev/null +++ b/Tests/RunCMake/add_subdirectory/main.cpp @@ -0,0 +1,6 @@ +#include "foo.h" + +int main(int, char**) +{ + return foo(); +} ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 09:19:30 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 09:19:30 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-790-g59d559a Message-ID: <20160831131930.AEC99F585E@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 59d559af2e35d3521c7cffc4a0c7c33ffaf2c744 (commit) via b82d027b457db00b1a48ca225444d9c977cfc6f9 (commit) from 9bbf1dc06ebb891498747768736442b22058c49e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=59d559af2e35d3521c7cffc4a0c7c33ffaf2c744 commit 59d559af2e35d3521c7cffc4a0c7c33ffaf2c744 Merge: 9bbf1dc b82d027 Author: Brad King AuthorDate: Wed Aug 31 09:19:28 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 09:19:28 2016 -0400 Merge topic 'drop-linux-i386-binary' b82d027b Utilities/Release: Drop Linux 32-bit binary ----------------------------------------------------------------------- Summary of changes: Help/release/dev/drop-linux-i386-binary.rst | 5 +++++ Tests/CMakeLists.txt | 2 -- Utilities/Release/create-cmake-release.cmake | 1 - Utilities/Release/linux32_release.cmake | 25 ------------------------- 4 files changed, 5 insertions(+), 28 deletions(-) create mode 100644 Help/release/dev/drop-linux-i386-binary.rst delete mode 100644 Utilities/Release/linux32_release.cmake hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 09:19:33 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 09:19:33 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-810-g6f8b939 Message-ID: <20160831131933.CD106F585E@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 6f8b93983a3bfb4a9262cae8e9b989edb61e8a4b (commit) via 39ac889d636ee8ce083e00ab2c8351c6148150ef (commit) via 7cf369fe276e011d4c9322153ae7c77d5124ca7e (commit) via 075cae5147bdca011841a9ebaf166636ab3e410f (commit) via 9a53af4068fd7f7627f8af193f551c1f2b5d4ac4 (commit) via 219f741128bfe1f34a97d71fa3bcdf8588d3d890 (commit) via 8a5beef32e007e69a8b348afa8ed2bddd760199a (commit) via e56aa462976f80762712519a4cf653b8c45bf3db (commit) via 551d5aedbffc0020793c2b6b374f1fa2be3e91d8 (commit) via f4f8074bec408ba0cab0f08ce1c48ad312fc0b24 (commit) via a63aaaed051a51592f9ddc738febd58a4d99928a (commit) via 9130b53a5e949da07e10414e13b79d7abad2b4fa (commit) via b52afa4655737f442af6017bab8d44158bdd466d (commit) via 05dbc204cdb4c7d81f40f2e2174c51df7e3294b9 (commit) via 75139374f07cff43eeab6b4302d560a077440d76 (commit) via 95dcc4e474b8ad10fea47c68df88678a6ae10fac (commit) via 13b7e7587d50a52bb422852eb4d71a93eb8f18a6 (commit) via d96416fe482e17bc9f5a741d71d4a51a9b44f65e (commit) via 3a713eaaf7d289b130acf0007b197553a6528112 (commit) via 3800fc299fe7703c4a3976f9ba9028e1ebeb3d3e (commit) from 59d559af2e35d3521c7cffc4a0c7c33ffaf2c744 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6f8b93983a3bfb4a9262cae8e9b989edb61e8a4b commit 6f8b93983a3bfb4a9262cae8e9b989edb61e8a4b Merge: 59d559a 39ac889 Author: Brad King AuthorDate: Wed Aug 31 09:19:31 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 09:19:31 2016 -0400 Merge topic 'import-libuv' 39ac889d cmake: Add trivial usage of libuv 7cf369fe Do not build libuv on HP-UX 075cae51 Do not build libuv on SPARC 9a53af40 Do not build libuv on Cygwin 219f7411 Do not build libuv on Mac OS X 10.4 and lower 8a5beef3 Add option to build CMake against a system libuv e56aa462 FindLibUV: Add module to find libuv package 551d5aed libuv: Fix unused variable warning in uv_loop_close f4f8074b libuv: Avoid including macOS CoreServices header globally a63aaaed libuv: Always include our own header first 9130b53a libuv: Conditionally declare Windows APIs for VS 2008 and below b52afa46 libuv: Fix anonymous union syntax 05dbc204 libuv: Fix Windows API function typedef syntax 75139374 libuv: Install LICENSE file with CMake documentation 95dcc4e4 libuv: Disable warnings to avoid changing 3rd party code 13b7e758 libuv: Build the library within CMake ... ----------------------------------------------------------------------- Summary of changes: CMakeLists.txt | 52 +- Source/CMakeLists.txt | 1 + Source/Modules/FindLibUV.cmake | 131 + Source/cmConfigure.cmake.h.in | 1 + Source/cmakemain.cxx | 7 + Tests/CMakeLists.txt | 4 + Tests/FindLibUV/CMakeLists.txt | 10 + Tests/FindLibUV/Test/CMakeLists.txt | 17 + Tests/FindLibUV/Test/main.c | 7 + Utilities/Scripts/update-libuv.bash | 26 + Utilities/cmThirdParty.h.in | 1 + Utilities/cm_uv.h | 23 + Utilities/{cmcurl => cmlibuv}/.gitattributes | 0 Utilities/cmlibuv/CMakeLists.txt | 227 ++ Utilities/cmlibuv/LICENSE | 70 + Utilities/cmlibuv/include/android-ifaddrs.h | 54 + Utilities/cmlibuv/include/pthread-barrier.h | 66 + Utilities/cmlibuv/include/stdint-msvc2008.h | 247 ++ Utilities/cmlibuv/include/tree.h | 768 ++++ Utilities/cmlibuv/include/uv-aix.h | 32 + Utilities/cmlibuv/include/uv-bsd.h | 34 + Utilities/cmlibuv/include/uv-darwin.h | 61 + Utilities/cmlibuv/include/uv-errno.h | 419 +++ Utilities/cmlibuv/include/uv-linux.h | 34 + Utilities/cmlibuv/include/uv-os390.h | 27 + Utilities/cmlibuv/include/uv-sunos.h | 44 + Utilities/cmlibuv/include/uv-threadpool.h | 37 + Utilities/cmlibuv/include/uv-unix.h | 371 ++ Utilities/cmlibuv/include/uv-version.h | 43 + Utilities/cmlibuv/include/uv-win.h | 660 ++++ Utilities/cmlibuv/include/uv.h | 1499 ++++++++ Utilities/cmlibuv/src/fs-poll.c | 256 ++ Utilities/cmlibuv/src/heap-inl.h | 245 ++ Utilities/cmlibuv/src/inet.c | 309 ++ Utilities/cmlibuv/src/queue.h | 108 + Utilities/cmlibuv/src/threadpool.c | 303 ++ Utilities/cmlibuv/src/unix/aix.c | 1154 ++++++ Utilities/cmlibuv/src/unix/android-ifaddrs.c | 703 ++++ Utilities/cmlibuv/src/unix/async.c | 290 ++ Utilities/cmlibuv/src/unix/atomic-ops.h | 88 + Utilities/cmlibuv/src/unix/core.c | 1238 +++++++ Utilities/cmlibuv/src/unix/darwin-proctitle.c | 206 ++ Utilities/cmlibuv/src/unix/darwin.c | 335 ++ Utilities/cmlibuv/src/unix/dl.c | 80 + Utilities/cmlibuv/src/unix/freebsd.c | 460 +++ Utilities/cmlibuv/src/unix/fs.c | 1355 +++++++ Utilities/cmlibuv/src/unix/fsevents.c | 904 +++++ Utilities/cmlibuv/src/unix/getaddrinfo.c | 202 ++ Utilities/cmlibuv/src/unix/getnameinfo.c | 120 + Utilities/cmlibuv/src/unix/internal.h | 322 ++ Utilities/cmlibuv/src/unix/kqueue.c | 463 +++ Utilities/cmlibuv/src/unix/linux-core.c | 985 +++++ Utilities/cmlibuv/src/unix/linux-inotify.c | 285 ++ Utilities/cmlibuv/src/unix/linux-syscalls.c | 471 +++ Utilities/cmlibuv/src/unix/linux-syscalls.h | 151 + Utilities/cmlibuv/src/unix/loop-watcher.c | 68 + Utilities/cmlibuv/src/unix/loop.c | 159 + Utilities/cmlibuv/src/unix/netbsd.c | 380 ++ Utilities/cmlibuv/src/unix/openbsd.c | 396 ++ Utilities/cmlibuv/src/unix/os390.c | 42 + Utilities/cmlibuv/src/unix/pipe.c | 298 ++ Utilities/cmlibuv/src/unix/poll.c | 130 + Utilities/cmlibuv/src/unix/process.c | 563 +++ Utilities/cmlibuv/src/unix/proctitle.c | 105 + Utilities/cmlibuv/src/unix/pthread-barrier.c | 120 + Utilities/cmlibuv/src/unix/pthread-fixes.c | 56 + Utilities/cmlibuv/src/unix/signal.c | 467 +++ Utilities/cmlibuv/src/unix/spinlock.h | 53 + Utilities/cmlibuv/src/unix/stream.c | 1638 +++++++++ Utilities/cmlibuv/src/unix/sunos.c | 821 +++++ Utilities/cmlibuv/src/unix/tcp.c | 395 ++ Utilities/cmlibuv/src/unix/thread.c | 605 ++++ Utilities/cmlibuv/src/unix/timer.c | 172 + Utilities/cmlibuv/src/unix/tty.c | 336 ++ Utilities/cmlibuv/src/unix/udp.c | 895 +++++ Utilities/cmlibuv/src/uv-common.c | 654 ++++ Utilities/cmlibuv/src/uv-common.h | 227 ++ Utilities/cmlibuv/src/version.c | 45 + Utilities/cmlibuv/src/win/async.c | 99 + Utilities/cmlibuv/src/win/atomicops-inl.h | 56 + Utilities/cmlibuv/src/win/core.c | 602 ++++ Utilities/cmlibuv/src/win/detect-wakeup.c | 35 + Utilities/cmlibuv/src/win/dl.c | 118 + Utilities/cmlibuv/src/win/error.c | 170 + Utilities/cmlibuv/src/win/fs-event.c | 545 +++ Utilities/cmlibuv/src/win/fs.c | 2491 +++++++++++++ Utilities/cmlibuv/src/win/getaddrinfo.c | 385 ++ Utilities/cmlibuv/src/win/getnameinfo.c | 150 + Utilities/cmlibuv/src/win/handle-inl.h | 179 + Utilities/cmlibuv/src/win/handle.c | 154 + Utilities/cmlibuv/src/win/internal.h | 398 +++ Utilities/cmlibuv/src/win/loop-watcher.c | 122 + Utilities/cmlibuv/src/win/pipe.c | 2130 +++++++++++ Utilities/cmlibuv/src/win/poll.c | 646 ++++ Utilities/cmlibuv/src/win/process-stdio.c | 510 +++ Utilities/cmlibuv/src/win/process.c | 1247 +++++++ Utilities/cmlibuv/src/win/req-inl.h | 224 ++ Utilities/cmlibuv/src/win/req.c | 25 + Utilities/cmlibuv/src/win/signal.c | 356 ++ Utilities/cmlibuv/src/win/snprintf.c | 42 + Utilities/cmlibuv/src/win/stream-inl.h | 56 + Utilities/cmlibuv/src/win/stream.c | 249 ++ Utilities/cmlibuv/src/win/tcp.c | 1510 ++++++++ Utilities/cmlibuv/src/win/thread.c | 697 ++++ Utilities/cmlibuv/src/win/timer.c | 195 + Utilities/cmlibuv/src/win/tty.c | 2237 ++++++++++++ Utilities/cmlibuv/src/win/udp.c | 928 +++++ Utilities/cmlibuv/src/win/util.c | 1380 +++++++ Utilities/cmlibuv/src/win/winapi.c | 159 + Utilities/cmlibuv/src/win/winapi.h | 4757 +++++++++++++++++++++++++ Utilities/cmlibuv/src/win/winsock.c | 561 +++ Utilities/cmlibuv/src/win/winsock.h | 191 + 112 files changed, 48234 insertions(+), 1 deletion(-) create mode 100644 Source/Modules/FindLibUV.cmake create mode 100644 Tests/FindLibUV/CMakeLists.txt create mode 100644 Tests/FindLibUV/Test/CMakeLists.txt create mode 100644 Tests/FindLibUV/Test/main.c create mode 100755 Utilities/Scripts/update-libuv.bash create mode 100644 Utilities/cm_uv.h copy Utilities/{cmcurl => cmlibuv}/.gitattributes (100%) create mode 100644 Utilities/cmlibuv/CMakeLists.txt create mode 100644 Utilities/cmlibuv/LICENSE create mode 100644 Utilities/cmlibuv/include/android-ifaddrs.h create mode 100644 Utilities/cmlibuv/include/pthread-barrier.h create mode 100644 Utilities/cmlibuv/include/stdint-msvc2008.h create mode 100644 Utilities/cmlibuv/include/tree.h create mode 100644 Utilities/cmlibuv/include/uv-aix.h create mode 100644 Utilities/cmlibuv/include/uv-bsd.h create mode 100644 Utilities/cmlibuv/include/uv-darwin.h create mode 100644 Utilities/cmlibuv/include/uv-errno.h create mode 100644 Utilities/cmlibuv/include/uv-linux.h create mode 100644 Utilities/cmlibuv/include/uv-os390.h create mode 100644 Utilities/cmlibuv/include/uv-sunos.h create mode 100644 Utilities/cmlibuv/include/uv-threadpool.h create mode 100644 Utilities/cmlibuv/include/uv-unix.h create mode 100644 Utilities/cmlibuv/include/uv-version.h create mode 100644 Utilities/cmlibuv/include/uv-win.h create mode 100644 Utilities/cmlibuv/include/uv.h create mode 100644 Utilities/cmlibuv/src/fs-poll.c create mode 100644 Utilities/cmlibuv/src/heap-inl.h create mode 100644 Utilities/cmlibuv/src/inet.c create mode 100644 Utilities/cmlibuv/src/queue.h create mode 100644 Utilities/cmlibuv/src/threadpool.c create mode 100644 Utilities/cmlibuv/src/unix/aix.c create mode 100644 Utilities/cmlibuv/src/unix/android-ifaddrs.c create mode 100644 Utilities/cmlibuv/src/unix/async.c create mode 100644 Utilities/cmlibuv/src/unix/atomic-ops.h create mode 100644 Utilities/cmlibuv/src/unix/core.c create mode 100644 Utilities/cmlibuv/src/unix/darwin-proctitle.c create mode 100644 Utilities/cmlibuv/src/unix/darwin.c create mode 100644 Utilities/cmlibuv/src/unix/dl.c create mode 100644 Utilities/cmlibuv/src/unix/freebsd.c create mode 100644 Utilities/cmlibuv/src/unix/fs.c create mode 100644 Utilities/cmlibuv/src/unix/fsevents.c create mode 100644 Utilities/cmlibuv/src/unix/getaddrinfo.c create mode 100644 Utilities/cmlibuv/src/unix/getnameinfo.c create mode 100644 Utilities/cmlibuv/src/unix/internal.h create mode 100644 Utilities/cmlibuv/src/unix/kqueue.c create mode 100644 Utilities/cmlibuv/src/unix/linux-core.c create mode 100644 Utilities/cmlibuv/src/unix/linux-inotify.c create mode 100644 Utilities/cmlibuv/src/unix/linux-syscalls.c create mode 100644 Utilities/cmlibuv/src/unix/linux-syscalls.h create mode 100644 Utilities/cmlibuv/src/unix/loop-watcher.c create mode 100644 Utilities/cmlibuv/src/unix/loop.c create mode 100644 Utilities/cmlibuv/src/unix/netbsd.c create mode 100644 Utilities/cmlibuv/src/unix/openbsd.c create mode 100644 Utilities/cmlibuv/src/unix/os390.c create mode 100644 Utilities/cmlibuv/src/unix/pipe.c create mode 100644 Utilities/cmlibuv/src/unix/poll.c create mode 100644 Utilities/cmlibuv/src/unix/process.c create mode 100644 Utilities/cmlibuv/src/unix/proctitle.c create mode 100644 Utilities/cmlibuv/src/unix/pthread-barrier.c create mode 100644 Utilities/cmlibuv/src/unix/pthread-fixes.c create mode 100644 Utilities/cmlibuv/src/unix/signal.c create mode 100644 Utilities/cmlibuv/src/unix/spinlock.h create mode 100644 Utilities/cmlibuv/src/unix/stream.c create mode 100644 Utilities/cmlibuv/src/unix/sunos.c create mode 100644 Utilities/cmlibuv/src/unix/tcp.c create mode 100644 Utilities/cmlibuv/src/unix/thread.c create mode 100644 Utilities/cmlibuv/src/unix/timer.c create mode 100644 Utilities/cmlibuv/src/unix/tty.c create mode 100644 Utilities/cmlibuv/src/unix/udp.c create mode 100644 Utilities/cmlibuv/src/uv-common.c create mode 100644 Utilities/cmlibuv/src/uv-common.h create mode 100644 Utilities/cmlibuv/src/version.c create mode 100644 Utilities/cmlibuv/src/win/async.c create mode 100644 Utilities/cmlibuv/src/win/atomicops-inl.h create mode 100644 Utilities/cmlibuv/src/win/core.c create mode 100644 Utilities/cmlibuv/src/win/detect-wakeup.c create mode 100644 Utilities/cmlibuv/src/win/dl.c create mode 100644 Utilities/cmlibuv/src/win/error.c create mode 100644 Utilities/cmlibuv/src/win/fs-event.c create mode 100644 Utilities/cmlibuv/src/win/fs.c create mode 100644 Utilities/cmlibuv/src/win/getaddrinfo.c create mode 100644 Utilities/cmlibuv/src/win/getnameinfo.c create mode 100644 Utilities/cmlibuv/src/win/handle-inl.h create mode 100644 Utilities/cmlibuv/src/win/handle.c create mode 100644 Utilities/cmlibuv/src/win/internal.h create mode 100644 Utilities/cmlibuv/src/win/loop-watcher.c create mode 100644 Utilities/cmlibuv/src/win/pipe.c create mode 100644 Utilities/cmlibuv/src/win/poll.c create mode 100644 Utilities/cmlibuv/src/win/process-stdio.c create mode 100644 Utilities/cmlibuv/src/win/process.c create mode 100644 Utilities/cmlibuv/src/win/req-inl.h create mode 100644 Utilities/cmlibuv/src/win/req.c create mode 100644 Utilities/cmlibuv/src/win/signal.c create mode 100644 Utilities/cmlibuv/src/win/snprintf.c create mode 100644 Utilities/cmlibuv/src/win/stream-inl.h create mode 100644 Utilities/cmlibuv/src/win/stream.c create mode 100644 Utilities/cmlibuv/src/win/tcp.c create mode 100644 Utilities/cmlibuv/src/win/thread.c create mode 100644 Utilities/cmlibuv/src/win/timer.c create mode 100644 Utilities/cmlibuv/src/win/tty.c create mode 100644 Utilities/cmlibuv/src/win/udp.c create mode 100644 Utilities/cmlibuv/src/win/util.c create mode 100644 Utilities/cmlibuv/src/win/winapi.c create mode 100644 Utilities/cmlibuv/src/win/winapi.h create mode 100644 Utilities/cmlibuv/src/win/winsock.c create mode 100644 Utilities/cmlibuv/src/win/winsock.h hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 09:19:36 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 09:19:36 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-812-g5b1f9cd Message-ID: <20160831131936.F06B2F5862@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 5b1f9cd12703eca0505ee0b6d9d2a0e53ed86f67 (commit) via 1dda2ec55a07f2a51d09f7b1604707e690e884b5 (commit) from 6f8b93983a3bfb4a9262cae8e9b989edb61e8a4b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5b1f9cd12703eca0505ee0b6d9d2a0e53ed86f67 commit 5b1f9cd12703eca0505ee0b6d9d2a0e53ed86f67 Merge: 6f8b939 1dda2ec Author: Brad King AuthorDate: Wed Aug 31 09:19:34 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 09:19:34 2016 -0400 Merge topic 'syntax-unexpected-eof' 1dda2ec5 Improve error message on unexpected end of file ----------------------------------------------------------------------- Summary of changes: Source/cmListFileCache.cxx | 3 +-- .../BadSYSROOT-result.txt => Syntax/CommandEOF-result.txt} | 0 Tests/RunCMake/Syntax/CommandEOF-stderr.txt | 6 ++++++ Tests/RunCMake/Syntax/CommandEOF.cmake | 1 + Tests/RunCMake/Syntax/RunCMakeTest.cmake | 1 + 5 files changed, 9 insertions(+), 2 deletions(-) copy Tests/RunCMake/{Android/BadSYSROOT-result.txt => Syntax/CommandEOF-result.txt} (100%) create mode 100644 Tests/RunCMake/Syntax/CommandEOF-stderr.txt create mode 100644 Tests/RunCMake/Syntax/CommandEOF.cmake hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 09:19:40 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 09:19:40 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-814-g0820c78 Message-ID: <20160831131940.11525F5873@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 0820c7850805e7c41fd54292fa4ebd13b28b51fa (commit) via bf09271b656bb8110c40cd2d456acfaa3b4e4741 (commit) from 5b1f9cd12703eca0505ee0b6d9d2a0e53ed86f67 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0820c7850805e7c41fd54292fa4ebd13b28b51fa commit 0820c7850805e7c41fd54292fa4ebd13b28b51fa Merge: 5b1f9cd bf09271 Author: Brad King AuthorDate: Wed Aug 31 09:19:37 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 09:19:37 2016 -0400 Merge topic 'FindMatlab-additional-components' bf09271b FindMatlab: adding handling of component "MAT" ----------------------------------------------------------------------- Summary of changes: Modules/FindMatlab.cmake | 43 +++++++++++---------- Tests/CMakeLists.txt | 1 + Tests/FindMatlab/components_checks/CMakeLists.txt | 23 +++++++++++ 3 files changed, 47 insertions(+), 20 deletions(-) create mode 100644 Tests/FindMatlab/components_checks/CMakeLists.txt hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 09:19:43 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 09:19:43 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-816-g7a25220 Message-ID: <20160831131943.5092BF5860@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 7a25220776202998904d979ebf64c008fc4c4d24 (commit) via d6f96207c377e0492929592f9408a2fb3cafab93 (commit) from 0820c7850805e7c41fd54292fa4ebd13b28b51fa (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7a25220776202998904d979ebf64c008fc4c4d24 commit 7a25220776202998904d979ebf64c008fc4c4d24 Merge: 0820c78 d6f9620 Author: Brad King AuthorDate: Wed Aug 31 09:19:40 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 09:19:40 2016 -0400 Merge topic 'fortran-macOS-sysroot' d6f96207 Fortran: Use -isysroot and -mmacosx-version-min= on macOS if available ----------------------------------------------------------------------- Summary of changes: Modules/CMakeFortranCompiler.cmake.in | 2 ++ 1 file changed, 2 insertions(+) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 09:19:46 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 09:19:46 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-818-ga9affa0 Message-ID: <20160831131946.1392AF5862@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via a9affa07cdeea6b66c920e4826abfe59854f7ffa (commit) via ed1758f8eb58a4e52acf0f3885f82403814f5ffd (commit) from 7a25220776202998904d979ebf64c008fc4c4d24 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a9affa07cdeea6b66c920e4826abfe59854f7ffa commit a9affa07cdeea6b66c920e4826abfe59854f7ffa Merge: 7a25220 ed1758f Author: Brad King AuthorDate: Wed Aug 31 09:19:44 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 09:19:44 2016 -0400 Merge topic 'FindOpenSSL-new-windows-names' ed1758f8 FindOpenSSL: Fix detection of OpenSSL 1.1 Win32/64 ----------------------------------------------------------------------- Summary of changes: Modules/FindOpenSSL.cmake | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 09:19:49 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 09:19:49 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-820-g0a2d0b1 Message-ID: <20160831131949.10731F5873@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 0a2d0b126ca01a7d989a887c71693989e9d15224 (commit) via df32e564aed43470e304cf21d8c9ac1d5a01d055 (commit) from a9affa07cdeea6b66c920e4826abfe59854f7ffa (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0a2d0b126ca01a7d989a887c71693989e9d15224 commit 0a2d0b126ca01a7d989a887c71693989e9d15224 Merge: a9affa0 df32e56 Author: Brad King AuthorDate: Wed Aug 31 09:19:46 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 09:19:46 2016 -0400 Merge topic '16101-xcode-fix-directory-exclude-from-all' df32e564 Xcode: Add targets marked as EXCLUDE_FROM_ALL to project (#16101) ----------------------------------------------------------------------- Summary of changes: Source/cmGlobalXCodeGenerator.cxx | 13 ++++--------- Source/cmGlobalXCodeGenerator.h | 3 +-- Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake | 6 ++++++ .../add_subdirectory/ExcludeFromAll/CMakeLists.txt | 4 ++++ Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp | 1 + .../foo.c => add_subdirectory/ExcludeFromAll/foo.cpp} | 2 ++ .../{Framework => add_subdirectory/ExcludeFromAll}/foo.h | 0 Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake | 12 ++++++++++++ Tests/RunCMake/add_subdirectory/main.cpp | 6 ++++++ 9 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake create mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt create mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp copy Tests/RunCMake/{Framework/foo.c => add_subdirectory/ExcludeFromAll/foo.cpp} (60%) copy Tests/RunCMake/{Framework => add_subdirectory/ExcludeFromAll}/foo.h (100%) create mode 100644 Tests/RunCMake/add_subdirectory/main.cpp hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 09:37:23 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 09:37:23 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1657-g7cb415e Message-ID: <20160831133723.0A112F5B10@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 7cb415ef8b47a1f0ac6a40c2e7e2a6885a30c78d (commit) via 3bd55dba7c889776bd094c6c29045c567b9000e2 (commit) via 0a2d0b126ca01a7d989a887c71693989e9d15224 (commit) via a9affa07cdeea6b66c920e4826abfe59854f7ffa (commit) via 7a25220776202998904d979ebf64c008fc4c4d24 (commit) via 0820c7850805e7c41fd54292fa4ebd13b28b51fa (commit) via 5b1f9cd12703eca0505ee0b6d9d2a0e53ed86f67 (commit) via 6f8b93983a3bfb4a9262cae8e9b989edb61e8a4b (commit) via 59d559af2e35d3521c7cffc4a0c7c33ffaf2c744 (commit) via 9bbf1dc06ebb891498747768736442b22058c49e (commit) from 698e66225604dfd7b2419d2459bddcbc08c609b9 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7cb415ef8b47a1f0ac6a40c2e7e2a6885a30c78d commit 7cb415ef8b47a1f0ac6a40c2e7e2a6885a30c78d Merge: 698e662 3bd55db Author: Brad King AuthorDate: Wed Aug 31 09:37:22 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 09:37:22 2016 -0400 Merge topic 'install-directory-genex-fix' into next 3bd55dba install: Fix evaluation of leading generator expressions in DIRECTORY 0a2d0b12 Merge topic '16101-xcode-fix-directory-exclude-from-all' a9affa07 Merge topic 'FindOpenSSL-new-windows-names' 7a252207 Merge topic 'fortran-macOS-sysroot' 0820c785 Merge topic 'FindMatlab-additional-components' 5b1f9cd1 Merge topic 'syntax-unexpected-eof' 6f8b9398 Merge topic 'import-libuv' 59d559af Merge topic 'drop-linux-i386-binary' 9bbf1dc0 CMake Nightly Date Stamp https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3bd55dba7c889776bd094c6c29045c567b9000e2 commit 3bd55dba7c889776bd094c6c29045c567b9000e2 Author: Yves Frederix AuthorDate: Mon Aug 29 22:24:55 2016 +0200 Commit: Brad King CommitDate: Wed Aug 31 09:33:39 2016 -0400 install: Fix evaluation of leading generator expressions in DIRECTORY Since commit v3.5.0-rc1~58^2 (install: Allow generator expressions in DIRECTORY, 2016-01-12) we accidentally treat leading generator expressions as relative paths even though they may evaluate to absolute paths. Defer the conversion to an absolute path until after evaluation. diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 86ab85a..4912eac 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -976,7 +976,8 @@ bool cmInstallCommand::HandleDirectoryMode( } else if (doing == DoingDirs) { // Convert this directory to a full path. std::string dir = args[i]; - if (!cmSystemTools::FileIsFullPath(dir.c_str())) { + std::string::size_type gpos = cmGeneratorExpression::Find(dir); + if (gpos != 0 && !cmSystemTools::FileIsFullPath(dir.c_str())) { dir = this->Makefile->GetCurrentSourceDirectory(); dir += "/"; dir += args[i]; diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx index 3928231..469b119 100644 --- a/Source/cmInstallDirectoryGenerator.cxx +++ b/Source/cmInstallDirectoryGenerator.cxx @@ -13,6 +13,7 @@ #include "cmGeneratorExpression.h" #include "cmLocalGenerator.h" +#include "cmMakefile.h" cmInstallDirectoryGenerator::cmInstallDirectoryGenerator( std::vector const& dirs, const char* dest, @@ -73,6 +74,16 @@ void cmInstallDirectoryGenerator::GenerateScriptForConfig( cmSystemTools::ExpandListArgument( cge->Evaluate(this->LocalGenerator, config), dirs); } + + // Make sure all dirs have absolute paths. + cmMakefile const& mf = *this->LocalGenerator->GetMakefile(); + for (std::vector::iterator i = dirs.begin(); i != dirs.end(); + ++i) { + if (!cmSystemTools::FileIsFullPath(i->c_str())) { + *i = std::string(mf.GetCurrentSourceDirectory()) + "/" + *i; + } + } + this->AddDirectoryInstallRule(os, config, indent, dirs); } ----------------------------------------------------------------------- Summary of changes: Source/CMakeVersion.cmake | 2 +- Source/cmInstallCommand.cxx | 3 ++- Source/cmInstallDirectoryGenerator.cxx | 11 +++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 09:50:35 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 09:50:35 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1659-g50ecee5 Message-ID: <20160831135035.1D69AF4E26@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 50ecee5c02947588ad55575ec41d033e318087ba (commit) via 3e8615ef9c6097c1b0249ff3b8e3dd2609c7af96 (commit) from 7cb415ef8b47a1f0ac6a40c2e7e2a6885a30c78d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=50ecee5c02947588ad55575ec41d033e318087ba commit 50ecee5c02947588ad55575ec41d033e318087ba Merge: 7cb415e 3e8615e Author: Brad King AuthorDate: Wed Aug 31 09:50:34 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 09:50:34 2016 -0400 Merge topic 'doc-XCODE-variable' into next 3e8615ef Document XCODE variable https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3e8615ef9c6097c1b0249ff3b8e3dd2609c7af96 commit 3e8615ef9c6097c1b0249ff3b8e3dd2609c7af96 Author: Ruslan Baratov AuthorDate: Wed Aug 31 14:17:51 2016 +0300 Commit: Ruslan Baratov CommitDate: Wed Aug 31 14:17:51 2016 +0300 Document XCODE variable diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 275b66c..b14f667 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -214,6 +214,7 @@ Variables that Describe the System /variable/WINCE /variable/WINDOWS_PHONE /variable/WINDOWS_STORE + /variable/XCODE /variable/XCODE_VERSION Variables that Control the Build diff --git a/Help/variable/XCODE.rst b/Help/variable/XCODE.rst new file mode 100644 index 0000000..99f20fb --- /dev/null +++ b/Help/variable/XCODE.rst @@ -0,0 +1,4 @@ +XCODE +----- + +``True`` when using :generator:`Xcode` generator. ----------------------------------------------------------------------- Summary of changes: Help/manual/cmake-variables.7.rst | 1 + Help/variable/XCODE.rst | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 Help/variable/XCODE.rst hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 10:43:38 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 10:43:38 -0400 (EDT) Subject: [Cmake-commits] CMake branch, master, updated. v3.6.1-822-g901a060 Message-ID: <20160831144338.7C5E2F3BCE@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, master has been updated via 901a06021e169bdfa19633370192870385868a7d (commit) via 3e8615ef9c6097c1b0249ff3b8e3dd2609c7af96 (commit) from 0a2d0b126ca01a7d989a887c71693989e9d15224 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=901a06021e169bdfa19633370192870385868a7d commit 901a06021e169bdfa19633370192870385868a7d Merge: 0a2d0b1 3e8615e Author: Brad King AuthorDate: Wed Aug 31 10:43:35 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 10:43:35 2016 -0400 Merge topic 'doc-XCODE-variable' 3e8615ef Document XCODE variable ----------------------------------------------------------------------- Summary of changes: Help/manual/cmake-variables.7.rst | 1 + Help/variable/XCODE.rst | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 Help/variable/XCODE.rst hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 10:44:26 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 10:44:26 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1661-gc01d364 Message-ID: <20160831144426.F1E2FF3CFC@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via c01d364e2bd3ce04cc251e44aa21022204d69176 (commit) via 901a06021e169bdfa19633370192870385868a7d (commit) from 50ecee5c02947588ad55575ec41d033e318087ba (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c01d364e2bd3ce04cc251e44aa21022204d69176 commit c01d364e2bd3ce04cc251e44aa21022204d69176 Merge: 50ecee5 901a060 Author: Brad King AuthorDate: Wed Aug 31 10:44:19 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 10:44:19 2016 -0400 Merge branch 'master' into next ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake From bill.hoffman at kitware.com Wed Aug 31 11:24:16 2016 From: bill.hoffman at kitware.com (Bill Hoffman) Date: Wed, 31 Aug 2016 11:24:16 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1663-g908cfab Message-ID: <20160831152416.E6E00F58C3@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via 908cfab96a7cb0edbde586e6b31d28f36623577f (commit) via ca0497c945460a10d2bb273be1f39e35c9c88742 (commit) from c01d364e2bd3ce04cc251e44aa21022204d69176 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=908cfab96a7cb0edbde586e6b31d28f36623577f commit 908cfab96a7cb0edbde586e6b31d28f36623577f Merge: c01d364 ca0497c Author: Bill Hoffman AuthorDate: Wed Aug 31 11:24:16 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 11:24:16 2016 -0400 Merge topic 'extend_matlab_unit_test' into next ca0497c9 Extend matlab_add_unit_test to run arbitrary code for the test. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ca0497c945460a10d2bb273be1f39e35c9c88742 commit ca0497c945460a10d2bb273be1f39e35c9c88742 Author: Bill Hoffman AuthorDate: Tue Aug 30 15:02:35 2016 -0400 Commit: Bill Hoffman CommitDate: Wed Aug 31 10:42:13 2016 -0400 Extend matlab_add_unit_test to run arbitrary code for the test. This commit allows a custom matlab set of commands to be run as the test instead of runtests('matlab_file_name'). It also escapes strings for matlab commands to allow for complicated matlab commands to be passed into the tests. diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake index 9f96fe6..aaca953 100644 --- a/Modules/FindMatlab.cmake +++ b/Modules/FindMatlab.cmake @@ -635,7 +635,7 @@ function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_ve set(devnull INPUT_FILE NUL) endif() - # timeout set to 30 seconds, in case it does not start + # timeout set to 120 seconds, in case it does not start # note as said before OUTPUT_VARIABLE cannot be used in a platform # independent manner however, not setting it would flush the output of Matlab # in the current console (unix variant) @@ -644,12 +644,17 @@ function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_ve OUTPUT_VARIABLE _matlab_version_from_cmd_dummy RESULT_VARIABLE _matlab_result_version_call ERROR_VARIABLE _matlab_result_version_call_error - TIMEOUT 30 + TIMEOUT 120 WORKING_DIRECTORY "${_matlab_temporary_folder}" ${devnull} ) - - + if("${_matlab_result_version_call}" MATCHES "timeout") + if(MATLAB_FIND_DEBUG) + message(WARNING "[MATLAB] Unable to determine the version of Matlab." + " Matlab call timed out after 120 seconds.") + endif() + return() + endif() if(${_matlab_result_version_call}) if(MATLAB_FIND_DEBUG) message(WARNING "[MATLAB] Unable to determine the version of Matlab. Matlab call returned with error ${_matlab_result_version_call}.") @@ -698,7 +703,6 @@ function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_ve endfunction() - #.rst: # .. command:: matlab_add_unit_test # @@ -720,6 +724,7 @@ endfunction() # matlab_add_unit_test( # NAME # UNITTEST_FILE matlab_file_containing_unittest.m +# [CUSTOM_MATLAB_COMMAND matlab_command_to_run_as_test] # [UNITTEST_PRECOMMAND matlab_command_to_run] # [TIMEOUT timeout] # [ADDITIONAL_PATH path1 [path2 ...]] @@ -735,6 +740,11 @@ endfunction() # ``UNITTEST_FILE`` # the matlab unittest file. Its path will be automatically # added to the Matlab path. +# ``CUSTOM_MATLAB_COMMAND`` +# Matlab script command to run as the test. +# IIf this is not set, then the following is run: +# "runtests('matlab_file_name'), exit(max([ans(1,:).Failed])) +# matlab_file_name comes from UNITTEST_FILE without the .m. # ``UNITTEST_PRECOMMAND`` # Matlab script command to be ran before the file # containing the test (eg. GPU device initialisation based on CMake @@ -748,6 +758,7 @@ endfunction() # ``MATLAB_ADDITIONAL_STARTUP_OPTIONS`` # a list of additional option in order # to run Matlab from the command line. +# -nosplash -nodesktop -nodisplay are always added. # ``TEST_ARGS`` # Additional options provided to the add_test command. These # options are added to the default options (eg. "CONFIGURATIONS Release") @@ -762,8 +773,9 @@ function(matlab_add_unit_test) endif() set(options NO_UNITTEST_FRAMEWORK) - set(oneValueArgs NAME UNITTEST_PRECOMMAND UNITTEST_FILE TIMEOUT) - set(multiValueArgs ADDITIONAL_PATH MATLAB_ADDITIONAL_STARTUP_OPTIONS TEST_ARGS) + set(oneValueArgs NAME UNITTEST_FILE TIMEOUT WORKING_DIRECTORY) + set(multiValueArgs UNITTEST_PRECOMMAND ADDITIONAL_PATH + MATLAB_ADDITIONAL_STARTUP_OPTIONS TEST_ARGS CUSTOM_TEST_COMMAND) set(prefix _matlab_unittest_prefix) cmake_parse_arguments(${prefix} "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) @@ -772,17 +784,29 @@ function(matlab_add_unit_test) message(FATAL_ERROR "[MATLAB] The Matlab test name cannot be empty") endif() + # escape matlab commands so they can be passed to add_test + # and to cmake -P script. + + string(REPLACE "\"" "" custom_test_cmd_clean "${${prefix}_CUSTOM_TEST_COMMAND}") + string(REPLACE ";" "\\;" custom_test_cmd_clean "${custom_test_cmd_clean}") + string(REPLACE "\"" "" unittest_precmd_clean "${${prefix}_UNITTEST_PRECOMMAND}") + string(REPLACE ";" "\\;" unittest_precmd_clean "${unittest_precmd_clean}") + string(REPLACE " " "\ " unittest_precmd_clean "${unittest_precmd_clean}") + string(REPLACE ";" "\\;" additional_path_clean "${${prefix}_ADDITIONAL_PATH}") + add_test(NAME ${${prefix}_NAME} COMMAND ${CMAKE_COMMAND} -Dtest_name=${${prefix}_NAME} - -Dadditional_paths=${${prefix}_ADDITIONAL_PATH} + -Dadditional_paths=${additional_path_clean} -Dtest_timeout=${${prefix}_TIMEOUT} -Doutput_directory=${_matlab_temporary_folder} + -Dworking_directory=${${prefix}_WORKING_DIRECTORY} -DMatlab_PROGRAM=${Matlab_MAIN_PROGRAM} -Dno_unittest_framework=${${prefix}_NO_UNITTEST_FRAMEWORK} -DMatlab_ADDITIONNAL_STARTUP_OPTIONS=${${prefix}_MATLAB_ADDITIONAL_STARTUP_OPTIONS} -Dunittest_file_to_run=${${prefix}_UNITTEST_FILE} - -Dcmd_to_run_before_test=${${prefix}_UNITTEST_PRECOMMAND} + -Dcustom_Matlab_test_command=${custom_test_cmd_clean} + -Dcmd_to_run_before_test=${unittest_precmd_clean} -P ${_FindMatlab_SELF_DIR}/MatlabTestsRedirect.cmake ${${prefix}_TEST_ARGS} ${${prefix}_UNPARSED_ARGUMENTS} @@ -1029,9 +1053,11 @@ function(_Matlab_get_version_from_root matlab_root matlab_known_version matlab_f set(matlab_list_of_all_versions) matlab_get_version_from_matlab_run("${Matlab_PROG_VERSION_STRING_AUTO_DETECT}" matlab_list_of_all_versions) - - list(GET matlab_list_of_all_versions 0 _matlab_version_tmp) - + if(matlab_list_of_all_versions) + list(GET matlab_list_of_all_versions 0 _matlab_version_tmp) + else() + set(_matlab_version_tmp "unknown") + endif() # set the version into the cache set(Matlab_VERSION_STRING_INTERNAL ${_matlab_version_tmp} CACHE INTERNAL "Matlab version (automatically determined)" FORCE) diff --git a/Modules/MatlabTestsRedirect.cmake b/Modules/MatlabTestsRedirect.cmake index 0ef4c3e..5677ef6 100644 --- a/Modules/MatlabTestsRedirect.cmake +++ b/Modules/MatlabTestsRedirect.cmake @@ -23,11 +23,12 @@ # -DMatlab_PROGRAM=matlab_exe_location # -DMatlab_ADDITIONNAL_STARTUP_OPTIONS="" # -Dtest_name=name_of_the_test +# -Dcustom_Matlab_test_command="" # -Dcmd_to_run_before_test="" # -Dunittest_file_to_run # -P FindMatlab_TestsRedirect.cmake -set(Matlab_UNIT_TESTS_CMD -nosplash -nojvm -nodesktop -nodisplay ${Matlab_ADDITIONNAL_STARTUP_OPTIONS}) +set(Matlab_UNIT_TESTS_CMD -nosplash -nodesktop -nodisplay ${Matlab_ADDITIONNAL_STARTUP_OPTIONS}) if(WIN32) set(Matlab_UNIT_TESTS_CMD ${Matlab_UNIT_TESTS_CMD} -wait) endif() @@ -36,6 +37,13 @@ if(NOT test_timeout) set(test_timeout 180) endif() +# If timeout is -1, then do not put a timeout on the execute_process +if(test_timeout EQUAL -1) + set(test_timeout "") +else() + set(test_timeout TIMEOUT ${test_timeout}) +endif() + if(NOT cmd_to_run_before_test) set(cmd_to_run_before_test) endif() @@ -50,16 +58,26 @@ foreach(s IN LISTS additional_paths) endif() endforeach() -set(unittest_to_run "runtests('${unittest_file_to_run_name}'), exit(max([ans(1,:).Failed]))") +if(custom_Matlab_test_command) + set(unittest_to_run ${custom_Matlab_test_command}) +else() + set(unittest_to_run "runtests('${unittest_file_to_run_name}'), exit(max([ans(1,:).Failed]))") +endif() + + if(no_unittest_framework) set(unittest_to_run "try, ${unittest_file_to_run_name}, catch err, disp('An exception has been thrown during the execution'), disp(err), disp(err.stack), exit(1), end, exit(0)") endif() set(Matlab_SCRIPT_TO_RUN - "addpath(${concat_string}), path, ${cmd_to_run_before_test}, ${unittest_to_run}" - ) + "addpath(${concat_string}); ${cmd_to_run_before_test}; ${unittest_to_run}") + +if(NOT working_directory) + set(working_directory "${output_directory}") +endif() -set(Matlab_LOG_FILE "${output_directory}/${test_name}.log") +string(REPLACE "/" "_" clean_test_name "${test_name}") +set(Matlab_LOG_FILE "${output_directory}/${clean_test_name}.log") set(devnull) if(UNIX) @@ -69,11 +87,11 @@ elseif(WIN32) endif() execute_process( - COMMAND "${Matlab_PROGRAM}" ${Matlab_UNIT_TESTS_CMD} -logfile "${test_name}.log" -r "${Matlab_SCRIPT_TO_RUN}" + COMMAND "${Matlab_PROGRAM}" ${Matlab_UNIT_TESTS_CMD} -logfile "${Matlab_LOG_FILE}" -r "${Matlab_SCRIPT_TO_RUN}" RESULT_VARIABLE res - TIMEOUT ${test_timeout} + ${test_timeout} OUTPUT_QUIET # we do not want the output twice - WORKING_DIRECTORY "${output_directory}" + WORKING_DIRECTORY ${working_directory} ${devnull} ) @@ -87,5 +105,5 @@ message("Matlab test ${name_of_the_test} output:\n${matlab_log_content}") # if w if(NOT (res EQUAL 0)) - message( FATAL_ERROR "[MATLAB] TEST FAILED" ) + message( FATAL_ERROR "[MATLAB] TEST FAILED Matlab returned ${res}" ) endif() ----------------------------------------------------------------------- Summary of changes: Modules/FindMatlab.cmake | 50 ++++++++++++++++++++++++++++--------- Modules/MatlabTestsRedirect.cmake | 36 +++++++++++++++++++------- 2 files changed, 65 insertions(+), 21 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 11:53:20 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 11:53:20 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1666-gc2addd1 Message-ID: <20160831155320.7EE12F4F46@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via c2addd198fc7d6b417fa25e28d2d1f127e1e3288 (commit) via 900ee0b80077b38b81e5da47cd79c38f044c3a03 (commit) via 6442709bae306903084e0bd710b4cea41d0b2500 (commit) from 908cfab96a7cb0edbde586e6b31d28f36623577f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c2addd198fc7d6b417fa25e28d2d1f127e1e3288 commit c2addd198fc7d6b417fa25e28d2d1f127e1e3288 Merge: 908cfab 900ee0b Author: Brad King AuthorDate: Wed Aug 31 11:53:19 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 11:53:19 2016 -0400 Merge topic 'FindCUDA-fixes' into next 900ee0b8 FindCUDA: Allow cuda_compile* macros to be called more than once per directory 6442709b FindCUDA: Fix for broken cuda_compile* commands. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=900ee0b80077b38b81e5da47cd79c38f044c3a03 commit 900ee0b80077b38b81e5da47cd79c38f044c3a03 Author: Stephen Sorley AuthorDate: Wed Aug 31 10:11:41 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 11:53:01 2016 -0400 FindCUDA: Allow cuda_compile* macros to be called more than once per directory Added a counter as a directory property that gets incremented every time one of the cuda_compile* macros is called. The value of this counter is then added to the phony target name passed to CUDA_WRAP_SRCS. This ensures that every call to one of these macros has its own unique intermediate output directory. diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake index 9545564..aaa1536 100644 --- a/Modules/FindCUDA.cmake +++ b/Modules/FindCUDA.cmake @@ -1797,12 +1797,23 @@ endmacro() ############################################################################### ############################################################################### macro(cuda_compile_base cuda_target format generated_files) + # Update a counter in this directory, to keep phony target names unique. + set(_cuda_target "${cuda_target}") + get_property(_counter DIRECTORY PROPERTY _cuda_internal_phony_counter) + if(_counter) + math(EXPR _counter "${_counter} + 1") + else() + set(_counter 1) + endif() + set(_cuda_target "${_cuda_target}_${_counter}") + set_property(DIRECTORY PROPERTY _cuda_internal_phony_counter ${_counter}) # Separate the sources from the options CUDA_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN}) + # Create custom commands and targets for each file. - CUDA_WRAP_SRCS( ${cuda_target} ${format} _generated_files ${_sources} ${_cmake_options} - OPTIONS ${_options} PHONY) + CUDA_WRAP_SRCS( ${_cuda_target} ${format} _generated_files ${_sources} + ${_cmake_options} OPTIONS ${_options} PHONY) set( ${generated_files} ${_generated_files}) https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6442709bae306903084e0bd710b4cea41d0b2500 commit 6442709bae306903084e0bd710b4cea41d0b2500 Author: Stephen Sorley AuthorDate: Wed Aug 31 09:56:36 2016 -0400 Commit: Brad King CommitDate: Wed Aug 31 11:52:43 2016 -0400 FindCUDA: Fix for broken cuda_compile* commands. The macros CUDA_COMPILE, CUDA_COMPILE_PTX, CUDA_COMPILE_FATBIN, and CUDA_COMPILE_CUBIN were broken by commit 7ded655 (FindCUDA: Take NVCC include directories from target properties, 2016-08-16). This bug is due to the fact that all of these macros call CUDA_WRAP_SRCS with a target name that's not an actual target, causing the new generator expressions to fail. Fix the bug by changing these macros to pass "PHONY" to CUDA_WRAP_SRCS. Now, when CUDA_WRAP_SRCS sees "PHONY", it falls back to the old behavior of populating the include directories and compile definitions from directory properties, instead of using target generator expressions. diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake index 317a9cd..9545564 100644 --- a/Modules/FindCUDA.cmake +++ b/Modules/FindCUDA.cmake @@ -1188,6 +1188,18 @@ endfunction() macro(CUDA_WRAP_SRCS cuda_target format generated_files) + # Put optional arguments in list. + set(_argn_list "${ARGN}") + # If one of the given optional arguments is "PHONY", make a note of it, then + # remove it from the list. + list(FIND _argn_list "PHONY" _phony_idx) + if("${_phony_idx}" GREATER "-1") + set(_target_is_phony true) + list(REMOVE_AT _argn_list ${_phony_idx}) + else() + set(_target_is_phony false) + endif() + # If CMake doesn't support separable compilation, complain if(CUDA_SEPARABLE_COMPILATION AND CMAKE_VERSION VERSION_LESS "2.8.10.1") message(SEND_ERROR "CUDA_SEPARABLE_COMPILATION isn't supported for CMake versions less than 2.8.10.1") @@ -1250,13 +1262,24 @@ macro(CUDA_WRAP_SRCS cuda_target format generated_files) # Initialize our list of includes with the user ones followed by the CUDA system ones. set(CUDA_NVCC_INCLUDE_DIRS ${CUDA_NVCC_INCLUDE_DIRS_USER} "${CUDA_INCLUDE_DIRS}") - # Append the include directories for this target via generator expression, which is - # expanded by the FILE(GENERATE) call below. This generator expression captures all - # include dirs set by the user, whether via directory properties or target properties - list(APPEND CUDA_NVCC_INCLUDE_DIRS "$") + if(_target_is_phony) + # If the passed in target name isn't a real target (i.e., this is from a call to one of the + # cuda_compile_* functions), need to query directory properties to get include directories + # and compile definitions. + get_directory_property(_dir_include_dirs INCLUDE_DIRECTORIES) + get_directory_property(_dir_compile_defs COMPILE_DEFINITIONS) + + list(APPEND CUDA_NVCC_INCLUDE_DIRS "${_dir_include_dirs}") + set(CUDA_NVCC_COMPILE_DEFINITIONS "${_dir_compile_defs}") + else() + # Append the include directories for this target via generator expression, which is + # expanded by the FILE(GENERATE) call below. This generator expression captures all + # include dirs set by the user, whether via directory properties or target properties + list(APPEND CUDA_NVCC_INCLUDE_DIRS "$") - # Do the same thing with compile definitions - set(CUDA_NVCC_COMPILE_DEFINITIONS "$") + # Do the same thing with compile definitions + set(CUDA_NVCC_COMPILE_DEFINITIONS "$") + endif() # Reset these variables @@ -1266,7 +1289,7 @@ macro(CUDA_WRAP_SRCS cuda_target format generated_files) set(CUDA_WRAP_OPTION_NVCC_FLAGS_${config_upper}) endforeach() - CUDA_GET_SOURCES_AND_OPTIONS(_cuda_wrap_sources _cuda_wrap_cmake_options _cuda_wrap_options ${ARGN}) + CUDA_GET_SOURCES_AND_OPTIONS(_cuda_wrap_sources _cuda_wrap_cmake_options _cuda_wrap_options ${_argn_list}) CUDA_PARSE_NVCC_OPTIONS(CUDA_WRAP_OPTION_NVCC_FLAGS ${_cuda_wrap_options}) # Figure out if we are building a shared library. BUILD_SHARED_LIBS is @@ -1356,7 +1379,7 @@ macro(CUDA_WRAP_SRCS cuda_target format generated_files) # Iterate over the macro arguments and create custom # commands for all the .cu files. - foreach(file ${ARGN}) + foreach(file ${_argn_list}) # Ignore any file marked as a HEADER_FILE_ONLY get_source_file_property(_is_header ${file} HEADER_FILE_ONLY) # Allow per source file overrides of the format. Also allows compiling non-.cu files. @@ -1779,7 +1802,7 @@ macro(cuda_compile_base cuda_target format generated_files) CUDA_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN}) # Create custom commands and targets for each file. CUDA_WRAP_SRCS( ${cuda_target} ${format} _generated_files ${_sources} ${_cmake_options} - OPTIONS ${_options} ) + OPTIONS ${_options} PHONY) set( ${generated_files} ${_generated_files}) ----------------------------------------------------------------------- Summary of changes: Modules/FindCUDA.cmake | 54 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 10 deletions(-) hooks/post-receive -- CMake From brad.king at kitware.com Wed Aug 31 14:21:10 2016 From: brad.king at kitware.com (Brad King) Date: Wed, 31 Aug 2016 14:21:10 -0400 (EDT) Subject: [Cmake-commits] CMake branch, next, updated. v3.6.1-1668-gd9fa27a Message-ID: <20160831182110.B99B9F58AE@public.kitware.com> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake". The branch, next has been updated via d9fa27a6b1a4088095d8f20da8ca0542a857e989 (commit) via fc695a776b5a4d61c3bfd3253ff9d40c3f30f6b9 (commit) from c2addd198fc7d6b417fa25e28d2d1f127e1e3288 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d9fa27a6b1a4088095d8f20da8ca0542a857e989 commit d9fa27a6b1a4088095d8f20da8ca0542a857e989 Merge: c2addd1 fc695a7 Author: Brad King AuthorDate: Wed Aug 31 14:21:09 2016 -0400 Commit: CMake Topic Stage CommitDate: Wed Aug 31 14:21:09 2016 -0400 Merge topic 'FindEXPAT-use-PkgConfig' into next fc695a77 FindEXPAT: use hints from PkgConfig https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=fc695a776b5a4d61c3bfd3253ff9d40c3f30f6b9 commit fc695a776b5a4d61c3bfd3253ff9d40c3f30f6b9 Author: Christoph Junghans AuthorDate: Tue Aug 30 15:37:10 2016 -0600 Commit: Christoph Junghans CommitDate: Wed Aug 31 11:52:11 2016 -0600 FindEXPAT: use hints from PkgConfig diff --git a/Modules/FindEXPAT.cmake b/Modules/FindEXPAT.cmake index 70fc35b..ea55a73 100644 --- a/Modules/FindEXPAT.cmake +++ b/Modules/FindEXPAT.cmake @@ -25,11 +25,15 @@ # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) +find_package(PkgConfig QUIET) + +pkg_check_modules(PC_EXPAT QUIET expat) + # Look for the header file. -find_path(EXPAT_INCLUDE_DIR NAMES expat.h) +find_path(EXPAT_INCLUDE_DIR NAMES expat.h HINTS ${PC_EXPAT_INCLUDE_DIRS}) # Look for the library. -find_library(EXPAT_LIBRARY NAMES expat libexpat) +find_library(EXPAT_LIBRARY NAMES expat libexpat HINTS ${PC_EXPAT_LIBRARY_DIRS}) if (EXPAT_INCLUDE_DIR AND EXISTS "${EXPAT_INCLUDE_DIR}/expat.h") file(STRINGS "${EXPAT_INCLUDE_DIR}/expat.h" expat_version_str ----------------------------------------------------------------------- Summary of changes: Modules/FindEXPAT.cmake | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) hooks/post-receive -- CMake